diff options
Diffstat (limited to 'contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote')
22 files changed, 16615 insertions, 17951 deletions
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp new file mode 100644 index 0000000..1e20a09 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp @@ -0,0 +1,376 @@ +//===-- GDBRemoteClientBase.cpp ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "GDBRemoteClientBase.h" + +#include "llvm/ADT/StringExtras.h" + +#include "lldb/Target/Process.h" +#include "lldb/Target/UnixSignals.h" +#include "lldb/Utility/LLDBAssert.h" + +#include "ProcessGDBRemoteLog.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_gdb_remote; +using namespace std::chrono; + +static const seconds kInterruptTimeout(5); + +///////////////////////// +// GDBRemoteClientBase // +///////////////////////// + +GDBRemoteClientBase::ContinueDelegate::~ContinueDelegate() = default; + +GDBRemoteClientBase::GDBRemoteClientBase(const char *comm_name, + const char *listener_name) + : GDBRemoteCommunication(comm_name, listener_name), m_async_count(0), + m_is_running(false), m_should_stop(false) {} + +StateType GDBRemoteClientBase::SendContinuePacketAndWaitForResponse( + ContinueDelegate &delegate, const UnixSignals &signals, + llvm::StringRef payload, StringExtractorGDBRemote &response) { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + response.Clear(); + + { + std::lock_guard<std::mutex> lock(m_mutex); + m_continue_packet = payload; + m_should_stop = false; + } + ContinueLock cont_lock(*this); + if (!cont_lock) + return eStateInvalid; + OnRunPacketSent(true); + + for (;;) { + PacketResult read_result = ReadPacket(response, kInterruptTimeout, false); + switch (read_result) { + case PacketResult::ErrorReplyTimeout: { + std::lock_guard<std::mutex> lock(m_mutex); + if (m_async_count == 0) + continue; + if (steady_clock::now() >= m_interrupt_time + kInterruptTimeout) + return eStateInvalid; + } + case PacketResult::Success: + break; + default: + if (log) + log->Printf("GDBRemoteClientBase::%s () ReadPacket(...) => false", + __FUNCTION__); + return eStateInvalid; + } + if (response.Empty()) + return eStateInvalid; + + const char stop_type = response.GetChar(); + if (log) + log->Printf("GDBRemoteClientBase::%s () got packet: %s", __FUNCTION__, + response.GetStringRef().c_str()); + + switch (stop_type) { + case 'W': + case 'X': + return eStateExited; + case 'E': + // ERROR + return eStateInvalid; + default: + if (log) + log->Printf("GDBRemoteClientBase::%s () unrecognized async packet", + __FUNCTION__); + return eStateInvalid; + case 'O': { + std::string inferior_stdout; + response.GetHexByteString(inferior_stdout); + delegate.HandleAsyncStdout(inferior_stdout); + break; + } + case 'A': + delegate.HandleAsyncMisc( + llvm::StringRef(response.GetStringRef()).substr(1)); + break; + case 'J': + delegate.HandleAsyncStructuredDataPacket(response.GetStringRef()); + break; + case 'T': + case 'S': + // Do this with the continue lock held. + const bool should_stop = ShouldStop(signals, response); + response.SetFilePos(0); + + // The packet we should resume with. In the future + // we should check our thread list and "do the right thing" + // for new threads that show up while we stop and run async + // packets. Setting the packet to 'c' to continue all threads + // is the right thing to do 99.99% of the time because if a + // thread was single stepping, and we sent an interrupt, we + // will notice above that we didn't stop due to an interrupt + // but stopped due to stepping and we would _not_ continue. + // This packet may get modified by the async actions (e.g. to send a + // signal). + m_continue_packet = 'c'; + cont_lock.unlock(); + + delegate.HandleStopReply(); + if (should_stop) + return eStateStopped; + + switch (cont_lock.lock()) { + case ContinueLock::LockResult::Success: + break; + case ContinueLock::LockResult::Failed: + return eStateInvalid; + case ContinueLock::LockResult::Cancelled: + return eStateStopped; + } + OnRunPacketSent(false); + break; + } + } +} + +bool GDBRemoteClientBase::SendAsyncSignal(int signo) { + Lock lock(*this, true); + if (!lock || !lock.DidInterrupt()) + return false; + + m_continue_packet = 'C'; + m_continue_packet += llvm::hexdigit((signo / 16) % 16); + m_continue_packet += llvm::hexdigit(signo % 16); + return true; +} + +bool GDBRemoteClientBase::Interrupt() { + Lock lock(*this, true); + if (!lock.DidInterrupt()) + return false; + m_should_stop = true; + return true; +} +GDBRemoteCommunication::PacketResult +GDBRemoteClientBase::SendPacketAndWaitForResponse( + llvm::StringRef payload, StringExtractorGDBRemote &response, + bool send_async) { + Lock lock(*this, send_async); + if (!lock) { + if (Log *log = + ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)) + log->Printf("GDBRemoteClientBase::%s failed to get mutex, not sending " + "packet '%.*s' (send_async=%d)", + __FUNCTION__, int(payload.size()), payload.data(), + send_async); + return PacketResult::ErrorSendFailed; + } + + return SendPacketAndWaitForResponseNoLock(payload, response); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteClientBase::SendPacketAndWaitForResponseNoLock( + llvm::StringRef payload, StringExtractorGDBRemote &response) { + PacketResult packet_result = SendPacketNoLock(payload); + if (packet_result != PacketResult::Success) + return packet_result; + + const size_t max_response_retries = 3; + for (size_t i = 0; i < max_response_retries; ++i) { + packet_result = ReadPacket(response, GetPacketTimeout(), true); + // Make sure we received a response + if (packet_result != PacketResult::Success) + return packet_result; + // Make sure our response is valid for the payload that was sent + if (response.ValidateResponse()) + return packet_result; + // Response says it wasn't valid + Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS); + if (log) + log->Printf( + "error: packet with payload \"%.*s\" got invalid response \"%s\": %s", + int(payload.size()), payload.data(), response.GetStringRef().c_str(), + (i == (max_response_retries - 1)) + ? "using invalid response and giving up" + : "ignoring response and waiting for another"); + } + return packet_result; +} + +bool GDBRemoteClientBase::SendvContPacket(llvm::StringRef payload, + StringExtractorGDBRemote &response) { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + if (log) + log->Printf("GDBRemoteCommunicationClient::%s ()", __FUNCTION__); + + // we want to lock down packet sending while we continue + Lock lock(*this, true); + + if (log) + log->Printf( + "GDBRemoteCommunicationClient::%s () sending vCont packet: %.*s", + __FUNCTION__, int(payload.size()), payload.data()); + + if (SendPacketNoLock(payload) != PacketResult::Success) + return false; + + OnRunPacketSent(true); + + // wait for the response to the vCont + if (ReadPacket(response, llvm::None, false) == PacketResult::Success) { + if (response.IsOKResponse()) + return true; + } + + return false; +} +bool GDBRemoteClientBase::ShouldStop(const UnixSignals &signals, + StringExtractorGDBRemote &response) { + std::lock_guard<std::mutex> lock(m_mutex); + + if (m_async_count == 0) + return true; // We were not interrupted. The process stopped on its own. + + // Older debugserver stubs (before April 2016) can return two + // stop-reply packets in response to a ^C packet. + // Additionally, all debugservers still return two stop replies if + // the inferior stops due to some other reason before the remote + // stub manages to interrupt it. We need to wait for this + // additional packet to make sure the packet sequence does not get + // skewed. + StringExtractorGDBRemote extra_stop_reply_packet; + ReadPacket(extra_stop_reply_packet, milliseconds(100), false); + + // Interrupting is typically done using SIGSTOP or SIGINT, so if + // the process stops with some other signal, we definitely want to + // stop. + const uint8_t signo = response.GetHexU8(UINT8_MAX); + if (signo != signals.GetSignalNumberFromName("SIGSTOP") && + signo != signals.GetSignalNumberFromName("SIGINT")) + return true; + + // We probably only stopped to perform some async processing, so continue + // after that is done. + // TODO: This is not 100% correct, as the process may have been stopped with + // SIGINT or SIGSTOP that was not caused by us (e.g. raise(SIGINT)). This will + // normally cause a stop, but if it's done concurrently with a async + // interrupt, that stop will get eaten (llvm.org/pr20231). + return false; +} + +void GDBRemoteClientBase::OnRunPacketSent(bool first) { + if (first) + BroadcastEvent(eBroadcastBitRunPacketSent, NULL); +} + +/////////////////////////////////////// +// GDBRemoteClientBase::ContinueLock // +/////////////////////////////////////// + +GDBRemoteClientBase::ContinueLock::ContinueLock(GDBRemoteClientBase &comm) + : m_comm(comm), m_acquired(false) { + lock(); +} + +GDBRemoteClientBase::ContinueLock::~ContinueLock() { + if (m_acquired) + unlock(); +} + +void GDBRemoteClientBase::ContinueLock::unlock() { + lldbassert(m_acquired); + { + std::unique_lock<std::mutex> lock(m_comm.m_mutex); + m_comm.m_is_running = false; + } + m_comm.m_cv.notify_all(); + m_acquired = false; +} + +GDBRemoteClientBase::ContinueLock::LockResult +GDBRemoteClientBase::ContinueLock::lock() { + Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS); + if (log) + log->Printf("GDBRemoteClientBase::ContinueLock::%s() resuming with %s", + __FUNCTION__, m_comm.m_continue_packet.c_str()); + + lldbassert(!m_acquired); + std::unique_lock<std::mutex> lock(m_comm.m_mutex); + m_comm.m_cv.wait(lock, [this] { return m_comm.m_async_count == 0; }); + if (m_comm.m_should_stop) { + m_comm.m_should_stop = false; + if (log) + log->Printf("GDBRemoteClientBase::ContinueLock::%s() cancelled", + __FUNCTION__); + return LockResult::Cancelled; + } + if (m_comm.SendPacketNoLock(m_comm.m_continue_packet) != + PacketResult::Success) + return LockResult::Failed; + + lldbassert(!m_comm.m_is_running); + m_comm.m_is_running = true; + m_acquired = true; + return LockResult::Success; +} + +/////////////////////////////// +// GDBRemoteClientBase::Lock // +/////////////////////////////// + +GDBRemoteClientBase::Lock::Lock(GDBRemoteClientBase &comm, bool interrupt) + : m_async_lock(comm.m_async_mutex, std::defer_lock), m_comm(comm), + m_acquired(false), m_did_interrupt(false) { + SyncWithContinueThread(interrupt); + if (m_acquired) + m_async_lock.lock(); +} + +void GDBRemoteClientBase::Lock::SyncWithContinueThread(bool interrupt) { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + std::unique_lock<std::mutex> lock(m_comm.m_mutex); + if (m_comm.m_is_running && !interrupt) + return; // We were asked to avoid interrupting the sender. Lock is not + // acquired. + + ++m_comm.m_async_count; + if (m_comm.m_is_running) { + if (m_comm.m_async_count == 1) { + // The sender has sent the continue packet and we are the first async + // packet. Let's interrupt it. + const char ctrl_c = '\x03'; + ConnectionStatus status = eConnectionStatusSuccess; + size_t bytes_written = m_comm.Write(&ctrl_c, 1, status, NULL); + if (bytes_written == 0) { + --m_comm.m_async_count; + if (log) + log->Printf("GDBRemoteClientBase::Lock::Lock failed to send " + "interrupt packet"); + return; + } + if (log) + 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_did_interrupt = true; + } + m_acquired = true; +} + +GDBRemoteClientBase::Lock::~Lock() { + if (!m_acquired) + return; + { + std::unique_lock<std::mutex> lock(m_comm.m_mutex); + --m_comm.m_async_count; + } + m_comm.m_cv.notify_one(); +} diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h new file mode 100644 index 0000000..2646405 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h @@ -0,0 +1,144 @@ +//===-- GDBRemoteClientBase.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_GDBRemoteClientBase_h_ +#define liblldb_GDBRemoteClientBase_h_ + +#include "GDBRemoteCommunication.h" + +#include <condition_variable> + +namespace lldb_private { +namespace process_gdb_remote { + +class GDBRemoteClientBase : public GDBRemoteCommunication { +public: + struct ContinueDelegate { + virtual ~ContinueDelegate(); + virtual void HandleAsyncStdout(llvm::StringRef out) = 0; + virtual void HandleAsyncMisc(llvm::StringRef data) = 0; + virtual void HandleStopReply() = 0; + + // ========================================================================= + /// Process asynchronously-received structured data. + /// + /// @param[in] data + /// The complete data packet, expected to start with JSON-async. + // ========================================================================= + virtual void HandleAsyncStructuredDataPacket(llvm::StringRef data) = 0; + }; + + GDBRemoteClientBase(const char *comm_name, const char *listener_name); + + bool SendAsyncSignal(int signo); + + bool Interrupt(); + + lldb::StateType SendContinuePacketAndWaitForResponse( + ContinueDelegate &delegate, const UnixSignals &signals, + llvm::StringRef payload, StringExtractorGDBRemote &response); + + PacketResult SendPacketAndWaitForResponse(llvm::StringRef payload, + StringExtractorGDBRemote &response, + bool send_async); + + bool SendvContPacket(llvm::StringRef payload, + StringExtractorGDBRemote &response); + + class Lock { + public: + Lock(GDBRemoteClientBase &comm, bool interrupt); + ~Lock(); + + explicit operator bool() { return m_acquired; } + + // Whether we had to interrupt the continue thread to acquire the + // connection. + bool DidInterrupt() const { return m_did_interrupt; } + + private: + std::unique_lock<std::recursive_mutex> m_async_lock; + GDBRemoteClientBase &m_comm; + bool m_acquired; + bool m_did_interrupt; + + void SyncWithContinueThread(bool interrupt); + }; + +protected: + PacketResult + SendPacketAndWaitForResponseNoLock(llvm::StringRef payload, + StringExtractorGDBRemote &response); + + virtual void OnRunPacketSent(bool first); + +private: + // Variables handling synchronization between the Continue thread and any + // other threads + // wishing to send packets over the connection. Either the continue thread has + // control over + // the connection (m_is_running == true) or the connection is free for an + // arbitrary number of + // other senders to take which indicate their interest by incrementing + // m_async_count. + // Semantics of individual states: + // - m_continue_packet == false, m_async_count == 0: connection is free + // - m_continue_packet == true, m_async_count == 0: only continue thread is + // present + // - m_continue_packet == true, m_async_count > 0: continue thread has + // control, async threads + // should interrupt it and wait for it to set m_continue_packet to false + // - m_continue_packet == false, m_async_count > 0: async threads have + // control, continue + // thread needs to wait for them to finish (m_async_count goes down to 0). + std::mutex m_mutex; + std::condition_variable m_cv; + // Packet with which to resume after an async interrupt. Can be changed by an + // async thread + // e.g. to inject a signal. + std::string m_continue_packet; + // When was the interrupt packet sent. Used to make sure we time out if the + // stub does not + // respond to interrupt requests. + std::chrono::time_point<std::chrono::steady_clock> m_interrupt_time; + uint32_t m_async_count; + bool m_is_running; + bool m_should_stop; // Whether we should resume after a stop. + // end of continue thread synchronization block + + // This handles the synchronization between individual async threads. For now + // they just use a + // simple mutex. + std::recursive_mutex m_async_mutex; + + bool ShouldStop(const UnixSignals &signals, + StringExtractorGDBRemote &response); + + class ContinueLock { + public: + enum class LockResult { Success, Cancelled, Failed }; + + explicit ContinueLock(GDBRemoteClientBase &comm); + ~ContinueLock(); + explicit operator bool() { return m_acquired; } + + LockResult lock(); + + void unlock(); + + private: + GDBRemoteClientBase &m_comm; + bool m_acquired; + }; +}; + +} // namespace process_gdb_remote +} // namespace lldb_private + +#endif // liblldb_GDBRemoteCommunicationClient_h_ diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index f164b14..bd87521 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -7,7 +7,6 @@ // //===----------------------------------------------------------------------===// - #include "GDBRemoteCommunication.h" // C Includes @@ -29,25 +28,25 @@ #include "lldb/Host/Socket.h" #include "lldb/Host/StringConvert.h" #include "lldb/Host/ThreadLauncher.h" -#include "lldb/Host/TimeValue.h" #include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" #include "llvm/ADT/SmallString.h" +#include "llvm/Support/ScopedPrinter.h" // Project includes #include "ProcessGDBRemoteLog.h" #if defined(__APPLE__) -# define DEBUGSERVER_BASENAME "debugserver" +#define DEBUGSERVER_BASENAME "debugserver" #else -# define DEBUGSERVER_BASENAME "lldb-server" +#define DEBUGSERVER_BASENAME "lldb-server" #endif -#if defined (HAVE_LIBCOMPRESSION) +#if defined(HAVE_LIBCOMPRESSION) #include <compression.h> #endif -#if defined (HAVE_LIBZ) +#if defined(HAVE_LIBZ) #include <zlib.h> #endif @@ -55,1449 +54,1309 @@ 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(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 () -{ +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 = Host::GetCurrentThreadID(); + } } -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 = Host::GetCurrentThreadID(); - } +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 = Host::GetCurrentThreadID(); + } } -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 = Host::GetCurrentThreadID(); - } +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 (Stream &strm) const -{ - const uint32_t size = GetNumPacketsInHistory (); - const uint32_t first_idx = GetFirstSavedPacketIndex (); +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; - 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()); - } + 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 //---------------------------------------------------------------------- -GDBRemoteCommunication::GDBRemoteCommunication(const char *comm_name, - const char *listener_name) : - Communication(comm_name), +GDBRemoteCommunication::GDBRemoteCommunication(const char *comm_name, + const char *listener_name) + : Communication(comm_name), #ifdef LLDB_CONFIGURATION_DEBUG - m_packet_timeout (1000), + m_packet_timeout(1000), #else - m_packet_timeout (1), + m_packet_timeout(1), #endif - m_echo_number(0), - m_supports_qEcho (eLazyBoolCalculate), - m_sequence_mutex (Mutex::eMutexTypeRecursive), - m_public_is_running (false), - m_private_is_running (false), - m_history (512), - m_send_acks (true), - m_compression_type (CompressionType::None), - m_listen_url () -{ + m_echo_number(0), m_supports_qEcho(eLazyBoolCalculate), m_history(512), + m_send_acks(true), m_compression_type(CompressionType::None), + m_listen_url() { } //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- -GDBRemoteCommunication::~GDBRemoteCommunication() -{ - if (IsConnected()) - { - Disconnect(); - } - - // 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) - StopReadThread(); +GDBRemoteCommunication::~GDBRemoteCommunication() { + if (IsConnected()) { + Disconnect(); + } + + // 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) + StopReadThread(); } -char -GDBRemoteCommunication::CalculcateChecksum (const char *payload, size_t payload_length) -{ - int checksum = 0; +char GDBRemoteCommunication::CalculcateChecksum(llvm::StringRef payload) { + int checksum = 0; - for (size_t i = 0; i < payload_length; ++i) - checksum += payload[i]; + for (char c : payload) + checksum += c; - return checksum & 255; + return checksum & 255; } -size_t -GDBRemoteCommunication::SendAck () -{ - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS)); - ConnectionStatus status = eConnectionStatusSuccess; - char ch = '+'; - 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); - return bytes_written; +size_t GDBRemoteCommunication::SendAck() { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS)); + ConnectionStatus status = eConnectionStatusSuccess; + char ch = '+'; + 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); + return bytes_written; } -size_t -GDBRemoteCommunication::SendNack () -{ - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS)); - ConnectionStatus status = eConnectionStatusSuccess; - char ch = '-'; - 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); - return bytes_written; +size_t GDBRemoteCommunication::SendNack() { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS)); + ConnectionStatus status = eConnectionStatusSuccess; + char ch = '-'; + 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); + return bytes_written; } GDBRemoteCommunication::PacketResult -GDBRemoteCommunication::SendPacket (const char *payload, size_t payload_length) -{ - Mutex::Locker locker(m_sequence_mutex); - return SendPacketNoLock (payload, payload_length); -} +GDBRemoteCommunication::SendPacketNoLock(llvm::StringRef payload) { + if (IsConnected()) { + StreamString packet(0, 4, eByteOrderBig); -GDBRemoteCommunication::PacketResult -GDBRemoteCommunication::SendPacketNoLock (const char *payload, size_t payload_length) -{ - if (IsConnected()) - { - StreamString packet(0, 4, eByteOrderBig); - - packet.PutChar('$'); - packet.Write (payload, payload_length); - packet.PutChar('#'); - packet.PutHex8(CalculcateChecksum (payload, payload_length)); - - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS)); - ConnectionStatus status = eConnectionStatusSuccess; - const char *packet_data = packet.GetData(); - const size_t packet_length = packet.GetSize(); - size_t bytes_written = Write (packet_data, packet_length, status, NULL); - if (log) - { - size_t binary_start_offset = 0; - if (strncmp(packet_data, "$vFile:pwrite:", strlen("$vFile:pwrite:")) == 0) - { - const char *first_comma = strchr(packet_data, ','); - if (first_comma) - { - const char *second_comma = strchr(first_comma + 1, ','); - if (second_comma) - binary_start_offset = second_comma - packet_data + 1; - } - } - - // 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); - - if (binary_start_offset) - { - StreamString strm; - // Print non binary data header - strm.Printf("<%4" PRIu64 "> send packet: %.*s", (uint64_t)bytes_written, (int)binary_start_offset, packet_data); - const uint8_t *p; - // Print binary data exactly as sent - for (p = (const uint8_t*)packet_data + binary_start_offset; *p != '#'; ++p) - strm.Printf("\\x%2.2x", *p); - // Print the checksum - strm.Printf("%*s", (int)3, p); - log->PutCString(strm.GetString().c_str()); - } - else - log->Printf("<%4" PRIu64 "> send packet: %.*s", (uint64_t)bytes_written, (int)packet_length, packet_data); - } + packet.PutChar('$'); + packet.Write(payload.data(), payload.size()); + packet.PutChar('#'); + packet.PutHex8(CalculcateChecksum(payload)); - m_history.AddPacket (packet.GetString(), packet_length, History::ePacketTypeSend, bytes_written); - - - if (bytes_written == packet_length) - { - if (GetSendAcks ()) - return GetAck (); - else - return PacketResult::Success; - } - else - { - if (log) - log->Printf ("error: failed to send packet: %.*s", (int)packet_length, packet_data); + 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(); + size_t bytes_written = Write(packet_data, packet_length, status, NULL); + if (log) { + size_t binary_start_offset = 0; + if (strncmp(packet_data, "$vFile:pwrite:", strlen("$vFile:pwrite:")) == + 0) { + const char *first_comma = strchr(packet_data, ','); + if (first_comma) { + const char *second_comma = strchr(first_comma + 1, ','); + if (second_comma) + binary_start_offset = second_comma - packet_data + 1; } + } + + // 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); + + if (binary_start_offset) { + StreamString strm; + // Print non binary data header + strm.Printf("<%4" PRIu64 "> send packet: %.*s", (uint64_t)bytes_written, + (int)binary_start_offset, packet_data); + const uint8_t *p; + // Print binary data exactly as sent + for (p = (const uint8_t *)packet_data + binary_start_offset; *p != '#'; + ++p) + strm.Printf("\\x%2.2x", *p); + // Print the checksum + strm.Printf("%*s", (int)3, p); + log->PutString(strm.GetString()); + } else + log->Printf("<%4" PRIu64 "> send packet: %.*s", (uint64_t)bytes_written, + (int)packet_length, packet_data); } - return PacketResult::ErrorSendFailed; -} -GDBRemoteCommunication::PacketResult -GDBRemoteCommunication::GetAck () -{ - StringExtractorGDBRemote packet; - PacketResult result = ReadPacket (packet, GetPacketTimeoutInMicroSeconds (), false); - if (result == PacketResult::Success) - { - if (packet.GetResponseType() == StringExtractorGDBRemote::ResponseType::eAck) - return PacketResult::Success; - else - return PacketResult::ErrorSendAck; - } - return result; -} + m_history.AddPacket(packet.GetString(), packet_length, + History::ePacketTypeSend, bytes_written); -bool -GDBRemoteCommunication::GetSequenceMutex (Mutex::Locker& locker, const char *failure_message) -{ - if (IsRunning()) - return locker.TryLock (m_sequence_mutex, failure_message); - - locker.Lock (m_sequence_mutex); - return true; + if (bytes_written == packet_length) { + if (GetSendAcks()) + return GetAck(); + else + return PacketResult::Success; + } else { + if (log) + log->Printf("error: failed to send packet: %.*s", (int)packet_length, + packet_data); + } + } + return PacketResult::ErrorSendFailed; } - -bool -GDBRemoteCommunication::WaitForNotRunningPrivate (const TimeValue *timeout_ptr) -{ - return m_private_is_running.WaitForValueEqualTo (false, timeout_ptr, NULL); +GDBRemoteCommunication::PacketResult GDBRemoteCommunication::GetAck() { + StringExtractorGDBRemote packet; + PacketResult result = ReadPacket(packet, GetPacketTimeout(), false); + if (result == PacketResult::Success) { + if (packet.GetResponseType() == + StringExtractorGDBRemote::ResponseType::eAck) + return PacketResult::Success; + else + return PacketResult::ErrorSendAck; + } + return result; } GDBRemoteCommunication::PacketResult -GDBRemoteCommunication::ReadPacket (StringExtractorGDBRemote &response, uint32_t timeout_usec, bool sync_on_timeout) -{ - if (m_read_thread_enabled) - return PopPacketFromQueue (response, timeout_usec); - else - return WaitForPacketWithTimeoutMicroSecondsNoLock (response, timeout_usec, sync_on_timeout); +GDBRemoteCommunication::ReadPacket(StringExtractorGDBRemote &response, + Timeout<std::micro> timeout, + bool sync_on_timeout) { + if (m_read_thread_enabled) + return PopPacketFromQueue(response, timeout); + else + return WaitForPacketNoLock(response, timeout, sync_on_timeout); } - // This function is called when a packet is requested. // A whole packet is popped from the packet queue and returned to the caller. // Packets are placed into this queue from the communication read thread. // See GDBRemoteCommunication::AppendBytesToCache. GDBRemoteCommunication::PacketResult -GDBRemoteCommunication::PopPacketFromQueue (StringExtractorGDBRemote &response, uint32_t timeout_usec) -{ - // Calculate absolute timeout value - TimeValue timeout = TimeValue::Now(); - timeout.OffsetWithMicroSeconds(timeout_usec); - - do - { - // scope for the mutex - { - // lock down the packet queue - Mutex::Locker locker(m_packet_queue_mutex); - - // Wait on condition variable. - if (m_packet_queue.size() == 0) - m_condition_queue_not_empty.Wait(m_packet_queue_mutex, &timeout); - - if (m_packet_queue.size() > 0) - { - // get the front element of the queue - response = m_packet_queue.front(); - - // remove the front element - m_packet_queue.pop(); - - // we got a packet - return PacketResult::Success; - } - } - - // Disconnected - if (!IsConnected()) - return PacketResult::ErrorDisconnected; - - // Loop while not timed out - } while (TimeValue::Now() < timeout); - - return PacketResult::ErrorReplyTimeout; +GDBRemoteCommunication::PopPacketFromQueue(StringExtractorGDBRemote &response, + Timeout<std::micro> timeout) { + auto pred = [&] { return !m_packet_queue.empty() && IsConnected(); }; + // lock down the packet queue + std::unique_lock<std::mutex> lock(m_packet_queue_mutex); + + if (!timeout) + m_condition_queue_not_empty.wait(lock, pred); + else { + if (!m_condition_queue_not_empty.wait_for(lock, *timeout, pred)) + return PacketResult::ErrorReplyTimeout; + if (!IsConnected()) + return PacketResult::ErrorDisconnected; + } + + // get the front element of the queue + response = m_packet_queue.front(); + + // remove the front element + m_packet_queue.pop(); + + // we got a packet + return PacketResult::Success; } - GDBRemoteCommunication::PacketResult -GDBRemoteCommunication::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtractorGDBRemote &packet, uint32_t timeout_usec, bool sync_on_timeout) -{ - uint8_t buffer[8192]; - Error error; +GDBRemoteCommunication::WaitForPacketNoLock(StringExtractorGDBRemote &packet, + Timeout<std::micro> timeout, + bool sync_on_timeout) { + uint8_t buffer[8192]; + Error error; - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS | GDBR_LOG_VERBOSE)); + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS | + GDBR_LOG_VERBOSE)); - // Check for a packet from our cache first without trying any reading... - if (CheckForPacket(NULL, 0, packet) != PacketType::Invalid) - return PacketResult::Success; + // Check for a packet from our cache first without trying any reading... + if (CheckForPacket(NULL, 0, packet) != PacketType::Invalid) + return PacketResult::Success; - bool timed_out = false; - bool disconnected = false; - while (IsConnected() && !timed_out) - { - lldb::ConnectionStatus status = eConnectionStatusNoConnection; - size_t bytes_read = Read (buffer, sizeof(buffer), timeout_usec, status, &error); - - if (log) - log->Printf ("%s: Read (buffer, (sizeof(buffer), timeout_usec = 0x%x, status = %s, error = %s) => bytes_read = %" PRIu64, - __PRETTY_FUNCTION__, - timeout_usec, - Communication::ConnectionStatusAsCString (status), - error.AsCString(), - (uint64_t)bytes_read); - - if (bytes_read > 0) - { - if (CheckForPacket(buffer, bytes_read, packet) != PacketType::Invalid) - return PacketResult::Success; - } - else - { - switch (status) - { - case eConnectionStatusTimedOut: - case eConnectionStatusInterrupted: - if (sync_on_timeout) - { - //------------------------------------------------------------------ - /// Sync the remote GDB server and make sure we get a response that - /// corresponds to what we send. - /// - /// Sends a "qEcho" packet and makes sure it gets the exact packet - /// echoed back. If the qEcho packet isn't supported, we send a qC - /// packet and make sure we get a valid thread ID back. We use the - /// "qC" packet since its response if very unique: is responds with - /// "QC%x" where %x is the thread ID of the current thread. This - /// makes the response unique enough from other packet responses to - /// ensure we are back on track. - /// - /// This packet is needed after we time out sending a packet so we - /// can ensure that we are getting the response for the packet we - /// are sending. There are no sequence IDs in the GDB remote - /// protocol (there used to be, but they are not supported anymore) - /// so if you timeout sending packet "abc", you might then send - /// packet "cde" and get the response for the previous "abc" packet. - /// Many responses are "OK" or "" (unsupported) or "EXX" (error) so - /// many responses for packets can look like responses for other - /// packets. So if we timeout, we need to ensure that we can get - /// back on track. If we can't get back on track, we must - /// disconnect. - //------------------------------------------------------------------ - bool sync_success = false; - bool got_actual_response = false; - // We timed out, we need to sync back up with the - char echo_packet[32]; - int echo_packet_len = 0; - RegularExpression response_regex; - - if (m_supports_qEcho == eLazyBoolYes) - { - echo_packet_len = ::snprintf (echo_packet, sizeof(echo_packet), "qEcho:%u", ++m_echo_number); - std::string regex_str = "^"; - regex_str += echo_packet; - regex_str += "$"; - response_regex.Compile(regex_str.c_str()); - } - else - { - echo_packet_len = ::snprintf (echo_packet, sizeof(echo_packet), "qC"); - response_regex.Compile("^QC[0-9A-Fa-f]+$"); - } - - PacketResult echo_packet_result = SendPacketNoLock (echo_packet, echo_packet_len); - if (echo_packet_result == PacketResult::Success) - { - const uint32_t max_retries = 3; - uint32_t successful_responses = 0; - for (uint32_t i=0; i<max_retries; ++i) - { - StringExtractorGDBRemote echo_response; - echo_packet_result = WaitForPacketWithTimeoutMicroSecondsNoLock (echo_response, timeout_usec, false); - if (echo_packet_result == PacketResult::Success) - { - ++successful_responses; - if (response_regex.Execute(echo_response.GetStringRef().c_str())) - { - sync_success = true; - break; - } - else if (successful_responses == 1) - { - // We got something else back as the first successful response, it probably is - // the response to the packet we actually wanted, so copy it over if this - // is the first success and continue to try to get the qEcho response - packet = echo_response; - got_actual_response = true; - } - } - else if (echo_packet_result == PacketResult::ErrorReplyTimeout) - continue; // Packet timed out, continue waiting for a response - else - break; // Something else went wrong getting the packet back, we failed and are done trying - } - } - - // We weren't able to sync back up with the server, we must abort otherwise - // all responses might not be from the right packets... - if (sync_success) - { - // We timed out, but were able to recover - if (got_actual_response) - { - // We initially timed out, but we did get a response that came in before the successful - // reply to our qEcho packet, so lets say everything is fine... - return PacketResult::Success; - } - } - else - { - disconnected = true; - Disconnect(); - } + bool timed_out = false; + bool disconnected = false; + while (IsConnected() && !timed_out) { + lldb::ConnectionStatus status = eConnectionStatusNoConnection; + size_t bytes_read = Read(buffer, sizeof(buffer), timeout, status, &error); + + if (log) + log->Printf("%s: Read (buffer, (sizeof(buffer), timeout = %ld us, " + "status = %s, error = %s) => bytes_read = %" PRIu64, + LLVM_PRETTY_FUNCTION, long(timeout ? timeout->count() : -1), + Communication::ConnectionStatusAsCString(status), + error.AsCString(), (uint64_t)bytes_read); + + if (bytes_read > 0) { + if (CheckForPacket(buffer, bytes_read, packet) != PacketType::Invalid) + return PacketResult::Success; + } else { + switch (status) { + case eConnectionStatusTimedOut: + case eConnectionStatusInterrupted: + if (sync_on_timeout) { + //------------------------------------------------------------------ + /// Sync the remote GDB server and make sure we get a response that + /// corresponds to what we send. + /// + /// Sends a "qEcho" packet and makes sure it gets the exact packet + /// echoed back. If the qEcho packet isn't supported, we send a qC + /// packet and make sure we get a valid thread ID back. We use the + /// "qC" packet since its response if very unique: is responds with + /// "QC%x" where %x is the thread ID of the current thread. This + /// makes the response unique enough from other packet responses to + /// ensure we are back on track. + /// + /// This packet is needed after we time out sending a packet so we + /// can ensure that we are getting the response for the packet we + /// are sending. There are no sequence IDs in the GDB remote + /// protocol (there used to be, but they are not supported anymore) + /// so if you timeout sending packet "abc", you might then send + /// packet "cde" and get the response for the previous "abc" packet. + /// Many responses are "OK" or "" (unsupported) or "EXX" (error) so + /// many responses for packets can look like responses for other + /// packets. So if we timeout, we need to ensure that we can get + /// back on track. If we can't get back on track, we must + /// disconnect. + //------------------------------------------------------------------ + bool sync_success = false; + bool got_actual_response = false; + // We timed out, we need to sync back up with the + char echo_packet[32]; + int echo_packet_len = 0; + RegularExpression response_regex; + + if (m_supports_qEcho == eLazyBoolYes) { + echo_packet_len = ::snprintf(echo_packet, sizeof(echo_packet), + "qEcho:%u", ++m_echo_number); + std::string regex_str = "^"; + regex_str += echo_packet; + regex_str += "$"; + response_regex.Compile(regex_str); + } else { + echo_packet_len = + ::snprintf(echo_packet, sizeof(echo_packet), "qC"); + response_regex.Compile(llvm::StringRef("^QC[0-9A-Fa-f]+$")); + } + + PacketResult echo_packet_result = + SendPacketNoLock(llvm::StringRef(echo_packet, echo_packet_len)); + if (echo_packet_result == PacketResult::Success) { + const uint32_t max_retries = 3; + uint32_t successful_responses = 0; + for (uint32_t i = 0; i < max_retries; ++i) { + StringExtractorGDBRemote echo_response; + echo_packet_result = + WaitForPacketNoLock(echo_response, timeout, false); + if (echo_packet_result == PacketResult::Success) { + ++successful_responses; + if (response_regex.Execute(echo_response.GetStringRef())) { + sync_success = true; + break; + } else if (successful_responses == 1) { + // We got something else back as the first successful + // response, it probably is + // the response to the packet we actually wanted, so copy it + // over if this + // is the first success and continue to try to get the qEcho + // response + packet = echo_response; + got_actual_response = true; } - timed_out = true; - break; - case eConnectionStatusSuccess: - //printf ("status = success but error = %s\n", error.AsCString("<invalid>")); - break; - - case eConnectionStatusEndOfFile: - case eConnectionStatusNoConnection: - case eConnectionStatusLostConnection: - case eConnectionStatusError: - disconnected = true; - Disconnect(); - break; + } else if (echo_packet_result == PacketResult::ErrorReplyTimeout) + continue; // Packet timed out, continue waiting for a response + else + break; // Something else went wrong getting the packet back, we + // failed and are done trying } + } + + // We weren't able to sync back up with the server, we must abort + // otherwise + // all responses might not be from the right packets... + if (sync_success) { + // We timed out, but were able to recover + if (got_actual_response) { + // We initially timed out, but we did get a response that came in + // before the successful + // reply to our qEcho packet, so lets say everything is fine... + return PacketResult::Success; + } + } else { + disconnected = true; + Disconnect(); + } } + timed_out = true; + break; + case eConnectionStatusSuccess: + // printf ("status = success but error = %s\n", + // error.AsCString("<invalid>")); + break; + + case eConnectionStatusEndOfFile: + case eConnectionStatusNoConnection: + case eConnectionStatusLostConnection: + case eConnectionStatusError: + disconnected = true; + Disconnect(); + break; + } } - packet.Clear (); - if (disconnected) - return PacketResult::ErrorDisconnected; - if (timed_out) - return PacketResult::ErrorReplyTimeout; - else - return PacketResult::ErrorReplyFailed; + } + packet.Clear(); + if (disconnected) + return PacketResult::ErrorDisconnected; + if (timed_out) + return PacketResult::ErrorReplyTimeout; + else + return PacketResult::ErrorReplyFailed; } -bool -GDBRemoteCommunication::DecompressPacket () -{ - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS)); - - if (!CompressionIsEnabled()) - return true; - - size_t pkt_size = m_bytes.size(); - - // Smallest possible compressed packet is $N#00 - an uncompressed empty reply, most commonly indicating - // an unsupported packet. Anything less than 5 characters, it's definitely not a compressed packet. - if (pkt_size < 5) - return true; - - if (m_bytes[0] != '$' && m_bytes[0] != '%') - return true; - if (m_bytes[1] != 'C' && m_bytes[1] != 'N') - return true; - - size_t hash_mark_idx = m_bytes.find ('#'); - if (hash_mark_idx == std::string::npos) - return true; - if (hash_mark_idx + 2 >= m_bytes.size()) - return true; - - if (!::isxdigit (m_bytes[hash_mark_idx + 1]) || !::isxdigit (m_bytes[hash_mark_idx + 2])) - return true; - - size_t content_length = pkt_size - 5; // not counting '$', 'C' | 'N', '#', & the two hex checksum chars - size_t content_start = 2; // The first character of the compressed/not-compressed text of the packet - size_t checksum_idx = hash_mark_idx + 1; // The first character of the two hex checksum characters - - // Normally size_of_first_packet == m_bytes.size() but m_bytes may contain multiple packets. - // size_of_first_packet is the size of the initial packet which we'll replace with the decompressed - // version of, leaving the rest of m_bytes unmodified. - size_t size_of_first_packet = hash_mark_idx + 3; - - // Compressed packets ("$C") start with a base10 number which is the size of the uncompressed payload, - // then a : and then the compressed data. e.g. $C1024:<binary>#00 - // Update content_start and content_length to only include the <binary> part of the packet. - - uint64_t decompressed_bufsize = ULONG_MAX; - if (m_bytes[1] == 'C') - { - size_t i = content_start; - while (i < hash_mark_idx && isdigit(m_bytes[i])) - i++; - if (i < hash_mark_idx && m_bytes[i] == ':') - { - i++; - content_start = i; - content_length = hash_mark_idx - content_start; - std::string bufsize_str (m_bytes.data() + 2, i - 2 - 1); - errno = 0; - decompressed_bufsize = ::strtoul (bufsize_str.c_str(), NULL, 10); - if (errno != 0 || decompressed_bufsize == ULONG_MAX) - { - m_bytes.erase (0, size_of_first_packet); - return false; - } - } - } +bool GDBRemoteCommunication::DecompressPacket() { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS)); - if (GetSendAcks ()) - { - char packet_checksum_cstr[3]; - packet_checksum_cstr[0] = m_bytes[checksum_idx]; - packet_checksum_cstr[1] = m_bytes[checksum_idx + 1]; - packet_checksum_cstr[2] = '\0'; - long packet_checksum = strtol (packet_checksum_cstr, NULL, 16); - - long actual_checksum = CalculcateChecksum (m_bytes.data() + 1, hash_mark_idx - 1); - bool success = packet_checksum == actual_checksum; - if (!success) - { - if (log) - log->Printf ("error: checksum mismatch: %.*s expected 0x%2.2x, got 0x%2.2x", - (int)(pkt_size), - m_bytes.c_str(), - (uint8_t)packet_checksum, - (uint8_t)actual_checksum); - } - // Send the ack or nack if needed - if (!success) - { - SendNack(); - m_bytes.erase (0, size_of_first_packet); - return false; - } - else - { - SendAck(); - } - } + if (!CompressionIsEnabled()) + return true; - if (m_bytes[1] == 'N') - { - // This packet was not compressed -- delete the 'N' character at the - // start and the packet may be processed as-is. - m_bytes.erase(1, 1); - return true; - } + size_t pkt_size = m_bytes.size(); - // Reverse the gdb-remote binary escaping that was done to the compressed text to - // guard characters like '$', '#', '}', etc. - std::vector<uint8_t> unescaped_content; - unescaped_content.reserve (content_length); - size_t i = content_start; - while (i < hash_mark_idx) - { - if (m_bytes[i] == '}') - { - i++; - unescaped_content.push_back (m_bytes[i] ^ 0x20); - } - else - { - unescaped_content.push_back (m_bytes[i]); - } - i++; - } + // Smallest possible compressed packet is $N#00 - an uncompressed empty reply, + // most commonly indicating + // an unsupported packet. Anything less than 5 characters, it's definitely + // not a compressed packet. + if (pkt_size < 5) + return true; - uint8_t *decompressed_buffer = nullptr; - size_t decompressed_bytes = 0; + if (m_bytes[0] != '$' && m_bytes[0] != '%') + return true; + if (m_bytes[1] != 'C' && m_bytes[1] != 'N') + return true; - if (decompressed_bufsize != ULONG_MAX) - { - decompressed_buffer = (uint8_t *) malloc (decompressed_bufsize + 1); - if (decompressed_buffer == nullptr) - { - m_bytes.erase (0, size_of_first_packet); - return false; - } + size_t hash_mark_idx = m_bytes.find('#'); + if (hash_mark_idx == std::string::npos) + return true; + if (hash_mark_idx + 2 >= m_bytes.size()) + return true; - } + if (!::isxdigit(m_bytes[hash_mark_idx + 1]) || + !::isxdigit(m_bytes[hash_mark_idx + 2])) + return true; -#if defined (HAVE_LIBCOMPRESSION) - // libcompression is weak linked so check that compression_decode_buffer() is available - if (compression_decode_buffer != NULL && - (m_compression_type == CompressionType::ZlibDeflate - || m_compression_type == CompressionType::LZFSE - || m_compression_type == CompressionType::LZ4)) - { - compression_algorithm compression_type; - if (m_compression_type == CompressionType::ZlibDeflate) - compression_type = COMPRESSION_ZLIB; - else if (m_compression_type == CompressionType::LZFSE) - compression_type = COMPRESSION_LZFSE; - else if (m_compression_type == CompressionType::LZ4) - compression_type = COMPRESSION_LZ4_RAW; - 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 (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); - } + size_t content_length = + pkt_size - + 5; // not counting '$', 'C' | 'N', '#', & the two hex checksum chars + size_t content_start = 2; // The first character of the + // compressed/not-compressed text of the packet + size_t checksum_idx = + hash_mark_idx + + 1; // The first character of the two hex checksum characters + + // Normally size_of_first_packet == m_bytes.size() but m_bytes may contain + // multiple packets. + // size_of_first_packet is the size of the initial packet which we'll replace + // with the decompressed + // version of, leaving the rest of m_bytes unmodified. + size_t size_of_first_packet = hash_mark_idx + 3; + + // Compressed packets ("$C") start with a base10 number which is the size of + // the uncompressed payload, + // then a : and then the compressed data. e.g. $C1024:<binary>#00 + // Update content_start and content_length to only include the <binary> part + // of the packet. + + uint64_t decompressed_bufsize = ULONG_MAX; + if (m_bytes[1] == 'C') { + size_t i = content_start; + while (i < hash_mark_idx && isdigit(m_bytes[i])) + i++; + if (i < hash_mark_idx && m_bytes[i] == ':') { + i++; + content_start = i; + content_length = hash_mark_idx - content_start; + std::string bufsize_str(m_bytes.data() + 2, i - 2 - 1); + errno = 0; + decompressed_bufsize = ::strtoul(bufsize_str.c_str(), NULL, 10); + if (errno != 0 || decompressed_bufsize == ULONG_MAX) { + m_bytes.erase(0, size_of_first_packet); + return false; + } } -#endif - -#if defined (HAVE_LIBZ) - if (decompressed_bytes == 0 - && decompressed_bufsize != ULONG_MAX - && decompressed_buffer != nullptr - && m_compression_type == CompressionType::ZlibDeflate) - { - z_stream stream; - memset (&stream, 0, sizeof (z_stream)); - stream.next_in = (Bytef *) unescaped_content.data(); - stream.avail_in = (uInt) unescaped_content.size(); - stream.total_in = 0; - stream.next_out = (Bytef *) decompressed_buffer; - stream.avail_out = decompressed_bufsize; - stream.total_out = 0; - stream.zalloc = Z_NULL; - stream.zfree = Z_NULL; - stream.opaque = Z_NULL; - - if (inflateInit2 (&stream, -15) == Z_OK) - { - int status = inflate (&stream, Z_NO_FLUSH); - inflateEnd (&stream); - if (status == Z_STREAM_END) - { - decompressed_bytes = stream.total_out; - } - } + } + + if (GetSendAcks()) { + char packet_checksum_cstr[3]; + packet_checksum_cstr[0] = m_bytes[checksum_idx]; + packet_checksum_cstr[1] = m_bytes[checksum_idx + 1]; + packet_checksum_cstr[2] = '\0'; + long packet_checksum = strtol(packet_checksum_cstr, NULL, 16); + + long actual_checksum = CalculcateChecksum( + llvm::StringRef(m_bytes).substr(1, hash_mark_idx - 1)); + bool success = packet_checksum == actual_checksum; + if (!success) { + if (log) + log->Printf( + "error: checksum mismatch: %.*s expected 0x%2.2x, got 0x%2.2x", + (int)(pkt_size), m_bytes.c_str(), (uint8_t)packet_checksum, + (uint8_t)actual_checksum); } -#endif + // Send the ack or nack if needed + if (!success) { + SendNack(); + m_bytes.erase(0, size_of_first_packet); + return false; + } else { + SendAck(); + } + } - if (decompressed_bytes == 0 || decompressed_buffer == nullptr) - { - if (decompressed_buffer) - free (decompressed_buffer); - m_bytes.erase (0, size_of_first_packet); - return false; + if (m_bytes[1] == 'N') { + // This packet was not compressed -- delete the 'N' character at the + // start and the packet may be processed as-is. + m_bytes.erase(1, 1); + return true; + } + + // Reverse the gdb-remote binary escaping that was done to the compressed text + // to + // guard characters like '$', '#', '}', etc. + std::vector<uint8_t> unescaped_content; + unescaped_content.reserve(content_length); + size_t i = content_start; + while (i < hash_mark_idx) { + if (m_bytes[i] == '}') { + i++; + unescaped_content.push_back(m_bytes[i] ^ 0x20); + } else { + unescaped_content.push_back(m_bytes[i]); } + i++; + } + + uint8_t *decompressed_buffer = nullptr; + size_t decompressed_bytes = 0; - std::string new_packet; - new_packet.reserve (decompressed_bytes + 6); - new_packet.push_back (m_bytes[0]); - new_packet.append ((const char *) decompressed_buffer, decompressed_bytes); - new_packet.push_back ('#'); - if (GetSendAcks ()) - { - uint8_t decompressed_checksum = CalculcateChecksum ((const char *) decompressed_buffer, decompressed_bytes); - char decompressed_checksum_str[3]; - snprintf (decompressed_checksum_str, 3, "%02x", decompressed_checksum); - new_packet.append (decompressed_checksum_str); + if (decompressed_bufsize != ULONG_MAX) { + decompressed_buffer = (uint8_t *)malloc(decompressed_bufsize + 1); + if (decompressed_buffer == nullptr) { + m_bytes.erase(0, size_of_first_packet); + return false; } - else - { - new_packet.push_back ('0'); - new_packet.push_back ('0'); + } + +#if defined(HAVE_LIBCOMPRESSION) + // libcompression is weak linked so check that compression_decode_buffer() is + // available + if (compression_decode_buffer != NULL && + (m_compression_type == CompressionType::ZlibDeflate || + m_compression_type == CompressionType::LZFSE || + m_compression_type == CompressionType::LZ4)) { + compression_algorithm compression_type; + if (m_compression_type == CompressionType::ZlibDeflate) + compression_type = COMPRESSION_ZLIB; + else if (m_compression_type == CompressionType::LZFSE) + compression_type = COMPRESSION_LZFSE; + else if (m_compression_type == CompressionType::LZ4) + compression_type = COMPRESSION_LZ4_RAW; + 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 (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); } + } +#endif - m_bytes.replace (0, size_of_first_packet, new_packet.data(), new_packet.size()); +#if defined(HAVE_LIBZ) + if (decompressed_bytes == 0 && decompressed_bufsize != ULONG_MAX && + decompressed_buffer != nullptr && + m_compression_type == CompressionType::ZlibDeflate) { + z_stream stream; + memset(&stream, 0, sizeof(z_stream)); + stream.next_in = (Bytef *)unescaped_content.data(); + stream.avail_in = (uInt)unescaped_content.size(); + stream.total_in = 0; + stream.next_out = (Bytef *)decompressed_buffer; + stream.avail_out = decompressed_bufsize; + stream.total_out = 0; + stream.zalloc = Z_NULL; + stream.zfree = Z_NULL; + stream.opaque = Z_NULL; + + if (inflateInit2(&stream, -15) == Z_OK) { + int status = inflate(&stream, Z_NO_FLUSH); + inflateEnd(&stream); + if (status == Z_STREAM_END) { + decompressed_bytes = stream.total_out; + } + } + } +#endif - free (decompressed_buffer); - return true; + if (decompressed_bytes == 0 || decompressed_buffer == nullptr) { + if (decompressed_buffer) + free(decompressed_buffer); + m_bytes.erase(0, size_of_first_packet); + return false; + } + + std::string new_packet; + new_packet.reserve(decompressed_bytes + 6); + new_packet.push_back(m_bytes[0]); + new_packet.append((const char *)decompressed_buffer, decompressed_bytes); + new_packet.push_back('#'); + if (GetSendAcks()) { + uint8_t decompressed_checksum = CalculcateChecksum( + llvm::StringRef((const char *)decompressed_buffer, decompressed_bytes)); + char decompressed_checksum_str[3]; + snprintf(decompressed_checksum_str, 3, "%02x", decompressed_checksum); + new_packet.append(decompressed_checksum_str); + } else { + new_packet.push_back('0'); + new_packet.push_back('0'); + } + + m_bytes.replace(0, size_of_first_packet, new_packet.data(), + new_packet.size()); + + free(decompressed_buffer); + return true; } GDBRemoteCommunication::PacketType -GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, StringExtractorGDBRemote &packet) -{ - // Put the packet data into the buffer in a thread safe fashion - std::lock_guard<std::recursive_mutex> guard(m_bytes_mutex); - - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS)); - - if (src && src_len > 0) - { - if (log && log->GetVerbose()) - { - StreamString s; - log->Printf ("GDBRemoteCommunication::%s adding %u bytes: %.*s", - __FUNCTION__, - (uint32_t)src_len, - (uint32_t)src_len, - src); - } - m_bytes.append ((const char *)src, src_len); +GDBRemoteCommunication::CheckForPacket(const uint8_t *src, size_t src_len, + StringExtractorGDBRemote &packet) { + // Put the packet data into the buffer in a thread safe fashion + std::lock_guard<std::recursive_mutex> guard(m_bytes_mutex); + + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS)); + + if (src && src_len > 0) { + if (log && log->GetVerbose()) { + StreamString s; + log->Printf("GDBRemoteCommunication::%s adding %u bytes: %.*s", + __FUNCTION__, (uint32_t)src_len, (uint32_t)src_len, src); + } + m_bytes.append((const char *)src, src_len); + } + + bool isNotifyPacket = false; + + // Parse up the packets into gdb remote packets + if (!m_bytes.empty()) { + // end_idx must be one past the last valid packet byte. Start + // it off with an invalid value that is the same as the current + // index. + size_t content_start = 0; + size_t content_length = 0; + size_t total_length = 0; + size_t checksum_idx = std::string::npos; + + // Size of packet before it is decompressed, for logging purposes + size_t original_packet_size = m_bytes.size(); + if (CompressionIsEnabled()) { + if (DecompressPacket() == false) { + packet.Clear(); + return GDBRemoteCommunication::PacketType::Standard; + } } - bool isNotifyPacket = false; - - // Parse up the packets into gdb remote packets - if (!m_bytes.empty()) - { - // end_idx must be one past the last valid packet byte. Start - // it off with an invalid value that is the same as the current - // index. - size_t content_start = 0; - size_t content_length = 0; - size_t total_length = 0; - size_t checksum_idx = std::string::npos; - - // Size of packet before it is decompressed, for logging purposes - size_t original_packet_size = m_bytes.size(); - if (CompressionIsEnabled()) - { - if (DecompressPacket() == false) - { - packet.Clear(); - return GDBRemoteCommunication::PacketType::Standard; - } + switch (m_bytes[0]) { + case '+': // Look for ack + case '-': // Look for cancel + case '\x03': // ^C to halt target + content_length = total_length = 1; // The command is one byte long... + break; + + case '%': // Async notify packet + isNotifyPacket = true; + LLVM_FALLTHROUGH; + + case '$': + // Look for a standard gdb packet? + { + size_t hash_pos = m_bytes.find('#'); + if (hash_pos != std::string::npos) { + if (hash_pos + 2 < m_bytes.size()) { + checksum_idx = hash_pos + 1; + // Skip the dollar sign + content_start = 1; + // Don't include the # in the content or the $ in the content length + content_length = hash_pos - 1; + + total_length = + hash_pos + 3; // Skip the # and the two hex checksum bytes + } else { + // Checksum bytes aren't all here yet + content_length = std::string::npos; + } } - - switch (m_bytes[0]) - { - case '+': // Look for ack - case '-': // Look for cancel - case '\x03': // ^C to halt target - content_length = total_length = 1; // The command is one byte long... - break; - - case '%': // Async notify packet - isNotifyPacket = true; - LLVM_FALLTHROUGH; - - case '$': - // Look for a standard gdb packet? - { - size_t hash_pos = m_bytes.find('#'); - if (hash_pos != std::string::npos) - { - if (hash_pos + 2 < m_bytes.size()) - { - checksum_idx = hash_pos + 1; - // Skip the dollar sign - content_start = 1; - // Don't include the # in the content or the $ in the content length - content_length = hash_pos - 1; - - total_length = hash_pos + 3; // Skip the # and the two hex checksum bytes - } - else - { - // Checksum bytes aren't all here yet - content_length = std::string::npos; - } - } - } - break; - - default: - { - // We have an unexpected byte and we need to flush all bad - // data that is in m_bytes, so we need to find the first - // byte that is a '+' (ACK), '-' (NACK), \x03 (CTRL+C interrupt), - // or '$' character (start of packet header) or of course, - // the end of the data in m_bytes... - const size_t bytes_len = m_bytes.size(); - bool done = false; - uint32_t idx; - for (idx = 1; !done && idx < bytes_len; ++idx) - { - switch (m_bytes[idx]) - { - case '+': - case '-': - case '\x03': - case '%': - case '$': - done = true; - break; - - default: - break; - } - } - if (log) - log->Printf ("GDBRemoteCommunication::%s tossing %u junk bytes: '%.*s'", - __FUNCTION__, idx - 1, idx - 1, m_bytes.c_str()); - m_bytes.erase(0, idx - 1); - } - break; + } + break; + + default: { + // We have an unexpected byte and we need to flush all bad + // data that is in m_bytes, so we need to find the first + // byte that is a '+' (ACK), '-' (NACK), \x03 (CTRL+C interrupt), + // or '$' character (start of packet header) or of course, + // the end of the data in m_bytes... + const size_t bytes_len = m_bytes.size(); + bool done = false; + uint32_t idx; + for (idx = 1; !done && idx < bytes_len; ++idx) { + switch (m_bytes[idx]) { + case '+': + case '-': + case '\x03': + case '%': + case '$': + done = true; + break; + + default: + break; } + } + if (log) + log->Printf("GDBRemoteCommunication::%s tossing %u junk bytes: '%.*s'", + __FUNCTION__, idx - 1, idx - 1, m_bytes.c_str()); + m_bytes.erase(0, idx - 1); + } break; + } - if (content_length == std::string::npos) - { - packet.Clear(); - return GDBRemoteCommunication::PacketType::Invalid; - } - else if (total_length > 0) - { - - // We have a valid packet... - assert (content_length <= m_bytes.size()); - assert (total_length <= m_bytes.size()); - assert (content_length <= total_length); - size_t content_end = content_start + content_length; - - 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); - - bool binary = false; - // Only detect binary for packets that start with a '$' and have a '#CC' checksum - if (m_bytes[0] == '$' && total_length > 4) - { - for (size_t i=0; !binary && i<total_length; ++i) - { - if (isprint (m_bytes[i]) == 0 && isspace (m_bytes[i]) == 0) - { - binary = true; - } - } - } - if (binary) - { - StreamString strm; - // Packet header... - if (CompressionIsEnabled()) - strm.Printf("<%4" PRIu64 ":%" PRIu64 "> read packet: %c", (uint64_t) original_packet_size, (uint64_t)total_length, m_bytes[0]); - else - strm.Printf("<%4" PRIu64 "> read packet: %c", (uint64_t)total_length, m_bytes[0]); - for (size_t i=content_start; i<content_end; ++i) - { - // Remove binary escaped bytes when displaying the packet... - const char ch = m_bytes[i]; - if (ch == 0x7d) - { - // 0x7d is the escape character. The next character is to - // be XOR'd with 0x20. - const char escapee = m_bytes[++i] ^ 0x20; - strm.Printf("%2.2x", escapee); - } - else - { - strm.Printf("%2.2x", (uint8_t)ch); - } - } - // Packet footer... - strm.Printf("%c%c%c", m_bytes[total_length-3], m_bytes[total_length-2], m_bytes[total_length-1]); - log->PutCString(strm.GetString().c_str()); - } - else - { - if (CompressionIsEnabled()) - log->Printf("<%4" PRIu64 ":%" PRIu64 "> read packet: %.*s", (uint64_t) original_packet_size, (uint64_t)total_length, (int)(total_length), m_bytes.c_str()); - else - log->Printf("<%4" PRIu64 "> read packet: %.*s", (uint64_t)total_length, (int)(total_length), m_bytes.c_str()); - } + if (content_length == std::string::npos) { + packet.Clear(); + return GDBRemoteCommunication::PacketType::Invalid; + } else if (total_length > 0) { + + // We have a valid packet... + assert(content_length <= m_bytes.size()); + assert(total_length <= m_bytes.size()); + assert(content_length <= total_length); + size_t content_end = content_start + content_length; + + 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); + + bool binary = false; + // Only detect binary for packets that start with a '$' and have a '#CC' + // checksum + if (m_bytes[0] == '$' && total_length > 4) { + for (size_t i = 0; !binary && i < total_length; ++i) { + if (isprint(m_bytes[i]) == 0 && isspace(m_bytes[i]) == 0) { + binary = true; } - - m_history.AddPacket (m_bytes.c_str(), total_length, History::ePacketTypeRecv, total_length); - - // Clear packet_str in case there is some existing data in it. - packet_str.clear(); - // Copy the packet from m_bytes to packet_str expanding the - // run-length encoding in the process. - // Reserve enough byte for the most common case (no RLE used) - packet_str.reserve(m_bytes.length()); - for (std::string::const_iterator c = m_bytes.begin() + content_start; c != m_bytes.begin() + content_end; ++c) - { - if (*c == '*') - { - // '*' indicates RLE. Next character will give us the - // repeat count and previous character is what is to be - // repeated. - char char_to_repeat = packet_str.back(); - // Number of time the previous character is repeated - int repeat_count = *++c + 3 - ' '; - // We have the char_to_repeat and repeat_count. Now push - // it in the packet. - for (int i = 0; i < repeat_count; ++i) - packet_str.push_back(char_to_repeat); - } - else if (*c == 0x7d) - { - // 0x7d is the escape character. The next character is to - // be XOR'd with 0x20. - char escapee = *++c ^ 0x20; - packet_str.push_back(escapee); - } - else - { - packet_str.push_back(*c); - } + } + } + if (binary) { + StreamString strm; + // Packet header... + if (CompressionIsEnabled()) + strm.Printf("<%4" PRIu64 ":%" PRIu64 "> read packet: %c", + (uint64_t)original_packet_size, (uint64_t)total_length, + m_bytes[0]); + else + strm.Printf("<%4" PRIu64 "> read packet: %c", + (uint64_t)total_length, m_bytes[0]); + for (size_t i = content_start; i < content_end; ++i) { + // Remove binary escaped bytes when displaying the packet... + const char ch = m_bytes[i]; + if (ch == 0x7d) { + // 0x7d is the escape character. The next character is to + // be XOR'd with 0x20. + const char escapee = m_bytes[++i] ^ 0x20; + strm.Printf("%2.2x", escapee); + } else { + strm.Printf("%2.2x", (uint8_t)ch); } - - if (m_bytes[0] == '$' || m_bytes[0] == '%') - { - assert (checksum_idx < m_bytes.size()); - if (::isxdigit (m_bytes[checksum_idx+0]) || - ::isxdigit (m_bytes[checksum_idx+1])) - { - if (GetSendAcks ()) - { - const char *packet_checksum_cstr = &m_bytes[checksum_idx]; - char packet_checksum = strtol (packet_checksum_cstr, NULL, 16); - char actual_checksum = CalculcateChecksum (packet_str.c_str(), packet_str.size()); - success = packet_checksum == actual_checksum; - if (!success) - { - if (log) - log->Printf ("error: checksum mismatch: %.*s expected 0x%2.2x, got 0x%2.2x", - (int)(total_length), - m_bytes.c_str(), - (uint8_t)packet_checksum, - (uint8_t)actual_checksum); - } - // Send the ack or nack if needed - if (!success) - SendNack(); - else - SendAck(); - } - } - else - { - success = false; - if (log) - log->Printf ("error: invalid checksum in packet: '%s'\n", m_bytes.c_str()); - } + } + // Packet footer... + strm.Printf("%c%c%c", m_bytes[total_length - 3], + m_bytes[total_length - 2], m_bytes[total_length - 1]); + log->PutString(strm.GetString()); + } else { + if (CompressionIsEnabled()) + log->Printf("<%4" PRIu64 ":%" PRIu64 "> read packet: %.*s", + (uint64_t)original_packet_size, (uint64_t)total_length, + (int)(total_length), m_bytes.c_str()); + else + log->Printf("<%4" PRIu64 "> read packet: %.*s", + (uint64_t)total_length, (int)(total_length), + m_bytes.c_str()); + } + } + + m_history.AddPacket(m_bytes, total_length, History::ePacketTypeRecv, + total_length); + + // Clear packet_str in case there is some existing data in it. + packet_str.clear(); + // Copy the packet from m_bytes to packet_str expanding the + // run-length encoding in the process. + // Reserve enough byte for the most common case (no RLE used) + packet_str.reserve(m_bytes.length()); + for (std::string::const_iterator c = m_bytes.begin() + content_start; + c != m_bytes.begin() + content_end; ++c) { + if (*c == '*') { + // '*' indicates RLE. Next character will give us the + // repeat count and previous character is what is to be + // repeated. + char char_to_repeat = packet_str.back(); + // Number of time the previous character is repeated + int repeat_count = *++c + 3 - ' '; + // We have the char_to_repeat and repeat_count. Now push + // it in the packet. + for (int i = 0; i < repeat_count; ++i) + packet_str.push_back(char_to_repeat); + } else if (*c == 0x7d) { + // 0x7d is the escape character. The next character is to + // be XOR'd with 0x20. + char escapee = *++c ^ 0x20; + packet_str.push_back(escapee); + } else { + packet_str.push_back(*c); + } + } + + if (m_bytes[0] == '$' || m_bytes[0] == '%') { + assert(checksum_idx < m_bytes.size()); + if (::isxdigit(m_bytes[checksum_idx + 0]) || + ::isxdigit(m_bytes[checksum_idx + 1])) { + if (GetSendAcks()) { + const char *packet_checksum_cstr = &m_bytes[checksum_idx]; + char packet_checksum = strtol(packet_checksum_cstr, NULL, 16); + char actual_checksum = CalculcateChecksum(packet_str); + success = packet_checksum == actual_checksum; + if (!success) { + if (log) + log->Printf("error: checksum mismatch: %.*s expected 0x%2.2x, " + "got 0x%2.2x", + (int)(total_length), m_bytes.c_str(), + (uint8_t)packet_checksum, (uint8_t)actual_checksum); } - - m_bytes.erase(0, total_length); - packet.SetFilePos(0); - - if (isNotifyPacket) - return GDBRemoteCommunication::PacketType::Notify; + // Send the ack or nack if needed + if (!success) + SendNack(); else - return GDBRemoteCommunication::PacketType::Standard; + SendAck(); + } + } else { + success = false; + if (log) + log->Printf("error: invalid checksum in packet: '%s'\n", + m_bytes.c_str()); } + } + + m_bytes.erase(0, total_length); + packet.SetFilePos(0); + + if (isNotifyPacket) + return GDBRemoteCommunication::PacketType::Notify; + else + return GDBRemoteCommunication::PacketType::Standard; } - packet.Clear(); - return GDBRemoteCommunication::PacketType::Invalid; + } + packet.Clear(); + return GDBRemoteCommunication::PacketType::Invalid; } -Error -GDBRemoteCommunication::StartListenThread (const char *hostname, uint16_t port) -{ - Error error; - if (m_listen_thread.IsJoinable()) - { - error.SetErrorString("listen thread already running"); - } +Error GDBRemoteCommunication::StartListenThread(const char *hostname, + uint16_t port) { + Error error; + if (m_listen_thread.IsJoinable()) { + error.SetErrorString("listen thread already running"); + } else { + char listen_url[512]; + if (hostname && hostname[0]) + snprintf(listen_url, sizeof(listen_url), "listen://%s:%i", hostname, + port); else - { - char listen_url[512]; - if (hostname && hostname[0]) - snprintf(listen_url, sizeof(listen_url), "listen://%s:%i", hostname, port); - else - snprintf(listen_url, sizeof(listen_url), "listen://%i", port); - m_listen_url = listen_url; - SetConnection(new ConnectionFileDescriptor()); - m_listen_thread = ThreadLauncher::LaunchThread(listen_url, GDBRemoteCommunication::ListenThread, this, &error); - } - return error; + snprintf(listen_url, sizeof(listen_url), "listen://%i", port); + m_listen_url = listen_url; + SetConnection(new ConnectionFileDescriptor()); + m_listen_thread = ThreadLauncher::LaunchThread( + listen_url, GDBRemoteCommunication::ListenThread, this, &error); + } + return error; } -bool -GDBRemoteCommunication::JoinListenThread () -{ - if (m_listen_thread.IsJoinable()) - m_listen_thread.Join(nullptr); - return true; +bool GDBRemoteCommunication::JoinListenThread() { + if (m_listen_thread.IsJoinable()) + m_listen_thread.Join(nullptr); + return true; } lldb::thread_result_t -GDBRemoteCommunication::ListenThread (lldb::thread_arg_t arg) -{ - GDBRemoteCommunication *comm = (GDBRemoteCommunication *)arg; - Error error; - ConnectionFileDescriptor *connection = (ConnectionFileDescriptor *)comm->GetConnection (); - - if (connection) - { - // Do the listen on another thread so we can continue on... - if (connection->Connect(comm->m_listen_url.c_str(), &error) != eConnectionStatusSuccess) - comm->SetConnection(NULL); - } - return NULL; +GDBRemoteCommunication::ListenThread(lldb::thread_arg_t arg) { + GDBRemoteCommunication *comm = (GDBRemoteCommunication *)arg; + Error error; + ConnectionFileDescriptor *connection = + (ConnectionFileDescriptor *)comm->GetConnection(); + + if (connection) { + // Do the listen on another thread so we can continue on... + if (connection->Connect(comm->m_listen_url.c_str(), &error) != + eConnectionStatusSuccess) + comm->SetConnection(NULL); + } + return NULL; } -Error -GDBRemoteCommunication::StartDebugserverProcess (const char *url, - Platform *platform, - ProcessLaunchInfo &launch_info, - uint16_t *port, - const Args& inferior_args) -{ - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); +Error GDBRemoteCommunication::StartDebugserverProcess( + const char *url, Platform *platform, ProcessLaunchInfo &launch_info, + uint16_t *port, const Args *inferior_args, int pass_comm_fd) { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + if (log) + log->Printf("GDBRemoteCommunication::%s(url=%s, port=%" PRIu16 ")", + __FUNCTION__, url ? url : "<empty>", + port ? *port : uint16_t(0)); + + Error error; + // If we locate debugserver, keep that located version around + static FileSpec g_debugserver_file_spec; + + char debugserver_path[PATH_MAX]; + FileSpec &debugserver_file_spec = launch_info.GetExecutableFile(); + + // Always check to see if we have an environment override for the path + // to the 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); if (log) - log->Printf ("GDBRemoteCommunication::%s(url=%s, port=%" PRIu16 ")", __FUNCTION__, url ? url : "<empty>", port ? *port : uint16_t(0)); - - Error error; - // If we locate debugserver, keep that located version around - static FileSpec g_debugserver_file_spec; - - char debugserver_path[PATH_MAX]; - FileSpec &debugserver_file_spec = launch_info.GetExecutableFile(); - - // Always check to see if we have an environment override for the path - // to the 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); + log->Printf("GDBRemoteCommunication::%s() gdb-remote stub exe path set " + "from environment variable: %s", + __FUNCTION__, env_debugserver_path); + } else + debugserver_file_spec = g_debugserver_file_spec; + bool debugserver_exists = debugserver_file_spec.Exists(); + if (!debugserver_exists) { + // The debugserver binary is in the LLDB.framework/Resources + // directory. + if (HostInfo::GetLLDBPath(ePathTypeSupportExecutableDir, + debugserver_file_spec)) { + debugserver_file_spec.AppendPathComponent(DEBUGSERVER_BASENAME); + debugserver_exists = debugserver_file_spec.Exists(); + if (debugserver_exists) { if (log) - log->Printf ("GDBRemoteCommunication::%s() gdb-remote stub exe path set from environment variable: %s", __FUNCTION__, env_debugserver_path); - } - else - debugserver_file_spec = g_debugserver_file_spec; - bool debugserver_exists = debugserver_file_spec.Exists(); - if (!debugserver_exists) - { - // The debugserver binary is in the LLDB.framework/Resources - // directory. - if (HostInfo::GetLLDBPath(ePathTypeSupportExecutableDir, debugserver_file_spec)) - { - debugserver_file_spec.AppendPathComponent (DEBUGSERVER_BASENAME); - debugserver_exists = debugserver_file_spec.Exists(); - if (debugserver_exists) - { - if (log) - log->Printf ("GDBRemoteCommunication::%s() found gdb-remote stub exe '%s'", __FUNCTION__, debugserver_file_spec.GetPath ().c_str ()); - - g_debugserver_file_spec = debugserver_file_spec; - } - else - { - debugserver_file_spec = platform->LocateExecutable(DEBUGSERVER_BASENAME); - if (debugserver_file_spec) - { - // Platform::LocateExecutable() wouldn't return a path if it doesn't exist - debugserver_exists = true; - } - else - { - if (log) - log->Printf ("GDBRemoteCommunication::%s() could not find gdb-remote stub exe '%s'", __FUNCTION__, debugserver_file_spec.GetPath ().c_str ()); - } - // Don't cache the platform specific GDB server binary as it could change - // from platform to platform - g_debugserver_file_spec.Clear(); - } + log->Printf( + "GDBRemoteCommunication::%s() found gdb-remote stub exe '%s'", + __FUNCTION__, debugserver_file_spec.GetPath().c_str()); + + g_debugserver_file_spec = debugserver_file_spec; + } else { + debugserver_file_spec = + platform->LocateExecutable(DEBUGSERVER_BASENAME); + if (debugserver_file_spec) { + // Platform::LocateExecutable() wouldn't return a path if it doesn't + // exist + debugserver_exists = true; + } else { + if (log) + log->Printf("GDBRemoteCommunication::%s() could not find " + "gdb-remote stub exe '%s'", + __FUNCTION__, debugserver_file_spec.GetPath().c_str()); } + // Don't cache the platform specific GDB server binary as it could + // change + // from platform to platform + g_debugserver_file_spec.Clear(); + } } - - if (debugserver_exists) - { - debugserver_file_spec.GetPath (debugserver_path, sizeof(debugserver_path)); + } + + if (debugserver_exists) { + debugserver_file_spec.GetPath(debugserver_path, sizeof(debugserver_path)); - Args &debugserver_args = launch_info.GetArguments(); - debugserver_args.Clear(); - char arg_cstr[PATH_MAX]; + Args &debugserver_args = launch_info.GetArguments(); + debugserver_args.Clear(); + char arg_cstr[PATH_MAX]; - // Start args with "debugserver /file/path -r --" - debugserver_args.AppendArgument(debugserver_path); + // Start args with "debugserver /file/path -r --" + debugserver_args.AppendArgument(llvm::StringRef(debugserver_path)); #if !defined(__APPLE__) - // First argument to lldb-server must be mode in which to run. - debugserver_args.AppendArgument("gdbserver"); + // First argument to lldb-server must be mode in which to run. + debugserver_args.AppendArgument(llvm::StringRef("gdbserver")); #endif - // If a url is supplied then use it - if (url) - debugserver_args.AppendArgument(url); + // If a url is supplied then use it + if (url) + debugserver_args.AppendArgument(llvm::StringRef(url)); + + if (pass_comm_fd >= 0) { + StreamString fd_arg; + fd_arg.Printf("--fd=%i", pass_comm_fd); + debugserver_args.AppendArgument(fd_arg.GetString()); + // Send "pass_comm_fd" down to the inferior so it can use it to + // communicate back with this process + launch_info.AppendDuplicateFileAction(pass_comm_fd, pass_comm_fd); + } - // use native registers, not the GDB registers - debugserver_args.AppendArgument("--native-regs"); + // use native registers, not the GDB registers + debugserver_args.AppendArgument(llvm::StringRef("--native-regs")); - if (launch_info.GetLaunchInSeparateProcessGroup()) - { - debugserver_args.AppendArgument("--setsid"); - } + if (launch_info.GetLaunchInSeparateProcessGroup()) { + debugserver_args.AppendArgument(llvm::StringRef("--setsid")); + } - llvm::SmallString<PATH_MAX> 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 - - // once data is written to the pipe, debug server is up and running. - Pipe socket_pipe; - - // port is null when debug server should listen on domain socket - - // we're not interested in port value but rather waiting for debug server - // to become available. - if ((port != nullptr && *port == 0) || port == nullptr) - { - if (url) - { - // Create a temporary file to get the stdout/stderr and redirect the - // output of the command into this file. We will later read this file - // if all goes well and fill the data into "command_output_ptr" - -#if defined(__APPLE__) - // Binding to port zero, we need to figure out what port it ends up - // using using a named pipe... - error = socket_pipe.CreateWithUniqueName("debugserver-named-pipe", false, named_pipe_path); - if (error.Fail()) - { - if (log) - log->Printf("GDBRemoteCommunication::%s() " - "named pipe creation failed: %s", - __FUNCTION__, error.AsCString()); - return error; - } - debugserver_args.AppendArgument("--named-pipe"); - debugserver_args.AppendArgument(named_pipe_path.c_str()); -#else - // Binding to port zero, we need to figure out what port it ends up - // using using an unnamed pipe... - error = socket_pipe.CreateNew(true); - if (error.Fail()) - { - if (log) - log->Printf("GDBRemoteCommunication::%s() " - "unnamed pipe creation failed: %s", - __FUNCTION__, error.AsCString()); - return error; - } - int write_fd = socket_pipe.GetWriteFileDescriptor(); - debugserver_args.AppendArgument("--pipe"); - debugserver_args.AppendArgument(std::to_string(write_fd).c_str()); - launch_info.AppendCloseFileAction(socket_pipe.GetReadFileDescriptor()); -#endif - } - else - { - // No host and port given, so lets listen on our end and make the debugserver - // connect to us.. - error = StartListenThread ("127.0.0.1", 0); - if (error.Fail()) - { - if (log) - log->Printf ("GDBRemoteCommunication::%s() unable to start listen thread: %s", __FUNCTION__, error.AsCString()); - return error; - } - - ConnectionFileDescriptor *connection = (ConnectionFileDescriptor *)GetConnection (); - // Wait for 10 seconds to resolve the bound port - *port = connection->GetListeningPort(10); - if (*port > 0) - { - char port_cstr[32]; - snprintf(port_cstr, sizeof(port_cstr), "127.0.0.1:%i", *port); - // Send the host and port down that debugserver and specify an option - // so that it connects back to the port we are listening to in this process - debugserver_args.AppendArgument("--reverse-connect"); - debugserver_args.AppendArgument(port_cstr); - } - else - { - error.SetErrorString ("failed to bind to port 0 on 127.0.0.1"); - if (log) - log->Printf ("GDBRemoteCommunication::%s() failed: %s", __FUNCTION__, error.AsCString()); - return error; - } - } - } - - const char *env_debugserver_log_file = getenv("LLDB_DEBUGSERVER_LOG_FILE"); - if (env_debugserver_log_file) - { - ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-file=%s", env_debugserver_log_file); - debugserver_args.AppendArgument(arg_cstr); - } - + llvm::SmallString<PATH_MAX> 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 - + // once data is written to the pipe, debug server is up and running. + Pipe socket_pipe; + + // port is null when debug server should listen on domain socket - + // we're not interested in port value but rather waiting for debug server + // to become available. + if (pass_comm_fd == -1 && + ((port != nullptr && *port == 0) || port == nullptr)) { + if (url) { +// Create a temporary file to get the stdout/stderr and redirect the +// output of the command into this file. We will later read this file +// if all goes well and fill the data into "command_output_ptr" #if defined(__APPLE__) - const char *env_debugserver_log_flags = getenv("LLDB_DEBUGSERVER_LOG_FLAGS"); - if (env_debugserver_log_flags) - { - ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-flags=%s", env_debugserver_log_flags); - debugserver_args.AppendArgument(arg_cstr); + // Binding to port zero, we need to figure out what port it ends up + // using using a named pipe... + error = socket_pipe.CreateWithUniqueName("debugserver-named-pipe", + false, named_pipe_path); + if (error.Fail()) { + if (log) + log->Printf("GDBRemoteCommunication::%s() " + "named pipe creation failed: %s", + __FUNCTION__, error.AsCString()); + return error; } + debugserver_args.AppendArgument(llvm::StringRef("--named-pipe")); + debugserver_args.AppendArgument(named_pipe_path); #else - const char *env_debugserver_log_channels = getenv("LLDB_SERVER_LOG_CHANNELS"); - if (env_debugserver_log_channels) - { - ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-channels=%s", env_debugserver_log_channels); - debugserver_args.AppendArgument(arg_cstr); + // Binding to port zero, we need to figure out what port it ends up + // using using an unnamed pipe... + error = socket_pipe.CreateNew(true); + if (error.Fail()) { + if (log) + log->Printf("GDBRemoteCommunication::%s() " + "unnamed pipe creation failed: %s", + __FUNCTION__, error.AsCString()); + return error; } + int write_fd = socket_pipe.GetWriteFileDescriptor(); + debugserver_args.AppendArgument(llvm::StringRef("--pipe")); + debugserver_args.AppendArgument(llvm::to_string(write_fd)); + launch_info.AppendCloseFileAction(socket_pipe.GetReadFileDescriptor()); #endif - - // Add additional args, starting with LLDB_DEBUGSERVER_EXTRA_ARG_1 until an env var doesn't come back. - uint32_t env_var_index = 1; - bool has_env_var; - do - { - char env_var_name[64]; - snprintf (env_var_name, sizeof (env_var_name), "LLDB_DEBUGSERVER_EXTRA_ARG_%" PRIu32, env_var_index++); - const char *extra_arg = getenv(env_var_name); - has_env_var = extra_arg != nullptr; - - if (has_env_var) - { - debugserver_args.AppendArgument (extra_arg); - if (log) - log->Printf ("GDBRemoteCommunication::%s adding env var %s contents to stub command line (%s)", __FUNCTION__, env_var_name, extra_arg); - } - } while (has_env_var); - - if (inferior_args.GetArgumentCount() > 0) - { - debugserver_args.AppendArgument ("--"); - debugserver_args.AppendArguments (inferior_args); + } else { + // No host and port given, so lets listen on our end and make the + // debugserver + // connect to us.. + error = StartListenThread("127.0.0.1", 0); + if (error.Fail()) { + if (log) + log->Printf("GDBRemoteCommunication::%s() unable to start listen " + "thread: %s", + __FUNCTION__, error.AsCString()); + return error; } - // Copy the current environment to the gdbserver/debugserver instance - StringList env; - if (Host::GetEnvironment(env)) - { - for (size_t i = 0; i < env.GetSize(); ++i) - launch_info.GetEnvironmentEntries().AppendArgument(env[i].c_str()); + ConnectionFileDescriptor *connection = + (ConnectionFileDescriptor *)GetConnection(); + // Wait for 10 seconds to resolve the bound port + uint16_t port_ = connection->GetListeningPort(10); + if (port_ > 0) { + char port_cstr[32]; + snprintf(port_cstr, sizeof(port_cstr), "127.0.0.1:%i", port_); + // Send the host and port down that debugserver and specify an option + // so that it connects back to the port we are listening to in this + // process + debugserver_args.AppendArgument(llvm::StringRef("--reverse-connect")); + debugserver_args.AppendArgument(llvm::StringRef(port_cstr)); + if (port) + *port = port_; + } else { + error.SetErrorString("failed to bind to port 0 on 127.0.0.1"); + if (log) + log->Printf("GDBRemoteCommunication::%s() failed: %s", __FUNCTION__, + error.AsCString()); + return error; } + } + } - // Close STDIN, STDOUT and STDERR. - launch_info.AppendCloseFileAction (STDIN_FILENO); - launch_info.AppendCloseFileAction (STDOUT_FILENO); - launch_info.AppendCloseFileAction (STDERR_FILENO); + const char *env_debugserver_log_file = getenv("LLDB_DEBUGSERVER_LOG_FILE"); + if (env_debugserver_log_file) { + ::snprintf(arg_cstr, sizeof(arg_cstr), "--log-file=%s", + env_debugserver_log_file); + debugserver_args.AppendArgument(llvm::StringRef(arg_cstr)); + } - // Redirect STDIN, STDOUT and STDERR to "/dev/null". - launch_info.AppendSuppressFileAction (STDIN_FILENO, true, false); - launch_info.AppendSuppressFileAction (STDOUT_FILENO, false, true); - launch_info.AppendSuppressFileAction (STDERR_FILENO, false, true); +#if defined(__APPLE__) + const char *env_debugserver_log_flags = + getenv("LLDB_DEBUGSERVER_LOG_FLAGS"); + if (env_debugserver_log_flags) { + ::snprintf(arg_cstr, sizeof(arg_cstr), "--log-flags=%s", + env_debugserver_log_flags); + debugserver_args.AppendArgument(llvm::StringRef(arg_cstr)); + } +#else + const char *env_debugserver_log_channels = + getenv("LLDB_SERVER_LOG_CHANNELS"); + if (env_debugserver_log_channels) { + ::snprintf(arg_cstr, sizeof(arg_cstr), "--log-channels=%s", + env_debugserver_log_channels); + debugserver_args.AppendArgument(llvm::StringRef(arg_cstr)); + } +#endif + // Add additional args, starting with LLDB_DEBUGSERVER_EXTRA_ARG_1 until an + // env var doesn't come back. + uint32_t env_var_index = 1; + bool has_env_var; + do { + char env_var_name[64]; + snprintf(env_var_name, sizeof(env_var_name), + "LLDB_DEBUGSERVER_EXTRA_ARG_%" PRIu32, env_var_index++); + const char *extra_arg = getenv(env_var_name); + has_env_var = extra_arg != nullptr; + + if (has_env_var) { + debugserver_args.AppendArgument(llvm::StringRef(extra_arg)); if (log) - { - StreamString string_stream; - Platform *const platform = nullptr; - launch_info.Dump(string_stream, platform); - log->Printf("launch info for gdb-remote stub:\n%s", string_stream.GetString().c_str()); - } - error = Host::LaunchProcess(launch_info); - - if (error.Success() && - launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) - { - if (named_pipe_path.size() > 0) - { - error = socket_pipe.OpenAsReader(named_pipe_path, false); - if (error.Fail()) - if (log) - log->Printf("GDBRemoteCommunication::%s() " - "failed to open named pipe %s for reading: %s", - __FUNCTION__, named_pipe_path.c_str(), error.AsCString()); - } - - if (socket_pipe.CanWrite()) - socket_pipe.CloseWriteFileDescriptor(); - if (socket_pipe.CanRead()) - { - char port_cstr[PATH_MAX] = {0}; - port_cstr[0] = '\0'; - size_t num_bytes = sizeof(port_cstr); - // Read port from pipe with 10 second timeout. - error = socket_pipe.ReadWithTimeout(port_cstr, num_bytes, - std::chrono::seconds{10}, num_bytes); - if (error.Success() && (port != nullptr)) - { - assert(num_bytes > 0 && port_cstr[num_bytes-1] == '\0'); - *port = StringConvert::ToUInt32(port_cstr, 0); - if (log) - log->Printf("GDBRemoteCommunication::%s() " - "debugserver listens %u port", - __FUNCTION__, *port); - } - else - { - if (log) - log->Printf("GDBRemoteCommunication::%s() " - "failed to read a port value from pipe %s: %s", - __FUNCTION__, named_pipe_path.c_str(), error.AsCString()); - - } - socket_pipe.Close(); - } - - if (named_pipe_path.size() > 0) - { - const auto err = socket_pipe.Delete(named_pipe_path); - if (err.Fail()) - { - if (log) - log->Printf ("GDBRemoteCommunication::%s failed to delete pipe %s: %s", - __FUNCTION__, named_pipe_path.c_str(), err.AsCString()); - } - } + log->Printf("GDBRemoteCommunication::%s adding env var %s contents " + "to stub command line (%s)", + __FUNCTION__, env_var_name, extra_arg); + } + } while (has_env_var); + + if (inferior_args && inferior_args->GetArgumentCount() > 0) { + debugserver_args.AppendArgument(llvm::StringRef("--")); + debugserver_args.AppendArguments(*inferior_args); + } - // Make sure we actually connect with the debugserver... - JoinListenThread(); - } + // Copy the current environment to the gdbserver/debugserver instance + StringList env; + if (Host::GetEnvironment(env)) { + for (size_t i = 0; i < env.GetSize(); ++i) + launch_info.GetEnvironmentEntries().AppendArgument(env[i]); } - else - { - error.SetErrorStringWithFormat ("unable to locate " DEBUGSERVER_BASENAME ); + + // Close STDIN, STDOUT and STDERR. + launch_info.AppendCloseFileAction(STDIN_FILENO); + launch_info.AppendCloseFileAction(STDOUT_FILENO); + launch_info.AppendCloseFileAction(STDERR_FILENO); + + // Redirect STDIN, STDOUT and STDERR to "/dev/null". + launch_info.AppendSuppressFileAction(STDIN_FILENO, true, false); + launch_info.AppendSuppressFileAction(STDOUT_FILENO, false, true); + launch_info.AppendSuppressFileAction(STDERR_FILENO, false, true); + + if (log) { + StreamString string_stream; + Platform *const platform = nullptr; + launch_info.Dump(string_stream, platform); + log->Printf("launch info for gdb-remote stub:\n%s", + string_stream.GetData()); } + error = Host::LaunchProcess(launch_info); + + if (error.Success() && + (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) && + pass_comm_fd == -1) { + if (named_pipe_path.size() > 0) { + error = socket_pipe.OpenAsReader(named_pipe_path, false); + if (error.Fail()) + if (log) + log->Printf("GDBRemoteCommunication::%s() " + "failed to open named pipe %s for reading: %s", + __FUNCTION__, named_pipe_path.c_str(), + error.AsCString()); + } + + if (socket_pipe.CanWrite()) + socket_pipe.CloseWriteFileDescriptor(); + if (socket_pipe.CanRead()) { + char port_cstr[PATH_MAX] = {0}; + port_cstr[0] = '\0'; + size_t num_bytes = sizeof(port_cstr); + // Read port from pipe with 10 second timeout. + error = socket_pipe.ReadWithTimeout( + port_cstr, num_bytes, std::chrono::seconds{10}, num_bytes); + if (error.Success() && (port != nullptr)) { + assert(num_bytes > 0 && port_cstr[num_bytes - 1] == '\0'); + *port = StringConvert::ToUInt32(port_cstr, 0); + if (log) + log->Printf("GDBRemoteCommunication::%s() " + "debugserver listens %u port", + __FUNCTION__, *port); + } else { + if (log) + log->Printf("GDBRemoteCommunication::%s() " + "failed to read a port value from pipe %s: %s", + __FUNCTION__, named_pipe_path.c_str(), + error.AsCString()); + } + socket_pipe.Close(); + } + + if (named_pipe_path.size() > 0) { + const auto err = socket_pipe.Delete(named_pipe_path); + if (err.Fail()) { + if (log) + log->Printf( + "GDBRemoteCommunication::%s failed to delete pipe %s: %s", + __FUNCTION__, named_pipe_path.c_str(), err.AsCString()); + } + } - if (error.Fail()) - { - if (log) - log->Printf ("GDBRemoteCommunication::%s() failed: %s", __FUNCTION__, error.AsCString()); + // Make sure we actually connect with the debugserver... + JoinListenThread(); } + } else { + error.SetErrorStringWithFormat("unable to locate " DEBUGSERVER_BASENAME); + } - return error; -} + if (error.Fail()) { + if (log) + log->Printf("GDBRemoteCommunication::%s() failed: %s", __FUNCTION__, + error.AsCString()); + } -void -GDBRemoteCommunication::DumpHistory(Stream &strm) -{ - m_history.Dump (strm); + return error; } -GDBRemoteCommunication::ScopedTimeout::ScopedTimeout (GDBRemoteCommunication& gdb_comm, - uint32_t timeout) : - m_gdb_comm (gdb_comm) -{ - m_saved_timeout = m_gdb_comm.SetPacketTimeout (timeout); +void GDBRemoteCommunication::DumpHistory(Stream &strm) { m_history.Dump(strm); } + +GDBRemoteCommunication::ScopedTimeout::ScopedTimeout( + GDBRemoteCommunication &gdb_comm, std::chrono::seconds timeout) + : m_gdb_comm(gdb_comm) { + m_saved_timeout = m_gdb_comm.SetPacketTimeout(timeout); } -GDBRemoteCommunication::ScopedTimeout::~ScopedTimeout () -{ - m_gdb_comm.SetPacketTimeout (m_saved_timeout); +GDBRemoteCommunication::ScopedTimeout::~ScopedTimeout() { + m_gdb_comm.SetPacketTimeout(m_saved_timeout); } -// This function is called via the Communications class read thread when bytes become available -// for this connection. This function will consume all incoming bytes and try to parse whole -// packets as they become available. Full packets are placed in a queue, so that all packet -// requests can simply pop from this queue. Async notification packets will be dispatched +// This function is called via the Communications class read thread when bytes +// become available +// for this connection. This function will consume all incoming bytes and try to +// parse whole +// packets as they become available. Full packets are placed in a queue, so that +// all packet +// requests can simply pop from this queue. Async notification packets will be +// dispatched // immediately to the ProcessGDBRemote Async thread via an event. -void GDBRemoteCommunication::AppendBytesToCache (const uint8_t * bytes, size_t len, bool broadcast, lldb::ConnectionStatus status) -{ - StringExtractorGDBRemote packet; - - while (true) - { - PacketType type = CheckForPacket(bytes, len, packet); - - // scrub the data so we do not pass it back to CheckForPacket - // on future passes of the loop - bytes = nullptr; - len = 0; - - // we may have received no packet so lets bail out - if (type == PacketType::Invalid) - break; - - if (type == PacketType::Standard) - { - // scope for the mutex - { - // lock down the packet queue - Mutex::Locker locker(m_packet_queue_mutex); - // push a new packet into the queue - m_packet_queue.push(packet); - // Signal condition variable that we have a packet - m_condition_queue_not_empty.Signal(); - - } - } +void GDBRemoteCommunication::AppendBytesToCache(const uint8_t *bytes, + size_t len, bool broadcast, + lldb::ConnectionStatus status) { + StringExtractorGDBRemote packet; + + while (true) { + PacketType type = CheckForPacket(bytes, len, packet); + + // scrub the data so we do not pass it back to CheckForPacket + // on future passes of the loop + bytes = nullptr; + len = 0; + + // we may have received no packet so lets bail out + if (type == PacketType::Invalid) + break; + + if (type == PacketType::Standard) { + // scope for the mutex + { + // lock down the packet queue + std::lock_guard<std::mutex> guard(m_packet_queue_mutex); + // push a new packet into the queue + m_packet_queue.push(packet); + // Signal condition variable that we have a packet + m_condition_queue_not_empty.notify_one(); + } + } - if (type == PacketType::Notify) - { - // put this packet into an event - const char *pdata = packet.GetStringRef().c_str(); + if (type == PacketType::Notify) { + // put this packet into an event + const char *pdata = packet.GetStringRef().c_str(); - // as the communication class, we are a broadcaster and the - // async thread is tuned to listen to us - BroadcastEvent( - eBroadcastBitGdbReadThreadGotNotify, - new EventDataBytes(pdata)); - } + // as the communication class, we are a broadcaster and the + // async thread is tuned to listen to us + BroadcastEvent(eBroadcastBitGdbReadThreadGotNotify, + new EventDataBytes(pdata)); } + } } diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h index 2a01bce..1f3fa17 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h @@ -12,365 +12,275 @@ // C Includes // C++ Includes -#include <string> +#include <condition_variable> +#include <mutex> #include <queue> +#include <string> #include <vector> // Other libraries and framework includes // Project includes -#include "lldb/lldb-public.h" #include "lldb/Core/Communication.h" #include "lldb/Core/Listener.h" #include "lldb/Host/HostThread.h" -#include "lldb/Host/Mutex.h" #include "lldb/Host/Predicate.h" -#include "lldb/Host/TimeValue.h" #include "lldb/Interpreter/Args.h" +#include "lldb/lldb-public.h" #include "Utility/StringExtractorGDBRemote.h" namespace lldb_private { namespace process_gdb_remote { -typedef enum -{ - eStoppointInvalid = -1, - eBreakpointSoftware = 0, - eBreakpointHardware, - eWatchpointWrite, - eWatchpointRead, - eWatchpointReadWrite +typedef enum { + eStoppointInvalid = -1, + eBreakpointSoftware = 0, + eBreakpointHardware, + eWatchpointWrite, + eWatchpointRead, + eWatchpointReadWrite } GDBStoppointType; -enum class CompressionType -{ - None = 0, // no compression - ZlibDeflate, // zlib's deflate compression scheme, requires zlib or Apple's libcompression - LZFSE, // an Apple compression scheme, requires Apple's libcompression - LZ4, // lz compression - called "lz4 raw" in libcompression terms, compat with https://code.google.com/p/lz4/ - LZMA, // Lempel–Ziv–Markov chain algorithm +enum class CompressionType { + None = 0, // no compression + ZlibDeflate, // zlib's deflate compression scheme, requires zlib or Apple's + // libcompression + LZFSE, // an Apple compression scheme, requires Apple's libcompression + LZ4, // lz compression - called "lz4 raw" in libcompression terms, compat with + // https://code.google.com/p/lz4/ + LZMA, // Lempel–Ziv–Markov chain algorithm }; class ProcessGDBRemote; -class GDBRemoteCommunication : public Communication -{ +class GDBRemoteCommunication : public Communication { public: - enum - { - eBroadcastBitRunPacketSent = kLoUserBroadcastBit, - eBroadcastBitGdbReadThreadGotNotify = kLoUserBroadcastBit << 1 // Sent when we received a notify packet. - }; + enum { + eBroadcastBitRunPacketSent = kLoUserBroadcastBit, + eBroadcastBitGdbReadThreadGotNotify = + kLoUserBroadcastBit << 1 // Sent when we received a notify packet. + }; + + enum class PacketType { Invalid = 0, Standard, Notify }; + + enum class PacketResult { + Success = 0, // Success + ErrorSendFailed, // Error sending the packet + ErrorSendAck, // Didn't get an ack back after sending a packet + ErrorReplyFailed, // Error getting the reply + ErrorReplyTimeout, // Timed out waiting for reply + ErrorReplyInvalid, // Got a reply but it wasn't valid for the packet that + // was sent + ErrorReplyAck, // Sending reply ack failed + ErrorDisconnected, // We were disconnected + ErrorNoSequenceLock // We couldn't get the sequence lock for a multi-packet + // request + }; + + // Class to change the timeout for a given scope and restore it to the + // original value when the + // created ScopedTimeout object got out of scope + class ScopedTimeout { + public: + ScopedTimeout(GDBRemoteCommunication &gdb_comm, + std::chrono::seconds timeout); + ~ScopedTimeout(); + + private: + GDBRemoteCommunication &m_gdb_comm; + std::chrono::seconds m_saved_timeout; + }; + + GDBRemoteCommunication(const char *comm_name, const char *listener_name); + + ~GDBRemoteCommunication() override; + + PacketResult GetAck(); + + size_t SendAck(); + + size_t SendNack(); + + char CalculcateChecksum(llvm::StringRef payload); + + PacketType CheckForPacket(const uint8_t *src, size_t src_len, + StringExtractorGDBRemote &packet); + + bool GetSendAcks() { return m_send_acks; } + + //------------------------------------------------------------------ + // Set the global packet timeout. + // + // For clients, this is the timeout that gets used when sending + // packets and waiting for responses. For servers, this is used when waiting + // for ACKs. + //------------------------------------------------------------------ + std::chrono::seconds SetPacketTimeout(std::chrono::seconds packet_timeout) { + const auto old_packet_timeout = m_packet_timeout; + m_packet_timeout = packet_timeout; + return old_packet_timeout; + } + + std::chrono::seconds GetPacketTimeout() const { return m_packet_timeout; } + + //------------------------------------------------------------------ + // Start a debugserver instance on the current host using the + // supplied connection URL. + //------------------------------------------------------------------ + Error StartDebugserverProcess( + const char *url, + Platform *platform, // If non nullptr, then check with the platform for + // the GDB server binary if it can't be located + ProcessLaunchInfo &launch_info, uint16_t *port, const Args *inferior_args, + int pass_comm_fd); // Communication file descriptor to pass during + // fork/exec to avoid having to connect/accept + + void DumpHistory(Stream &strm); - enum class PacketType - { - Invalid = 0, - Standard, - Notify - }; - - enum class PacketResult - { - Success = 0, // Success - ErrorSendFailed, // Error sending the packet - ErrorSendAck, // Didn't get an ack back after sending a packet - ErrorReplyFailed, // Error getting the reply - ErrorReplyTimeout, // Timed out waiting for reply - ErrorReplyInvalid, // Got a reply but it wasn't valid for the packet that was sent - ErrorReplyAck, // Sending reply ack failed - ErrorDisconnected, // We were disconnected - ErrorNoSequenceLock // We couldn't get the sequence lock for a multi-packet request +protected: + class History { + public: + enum PacketType { + ePacketTypeInvalid = 0, + ePacketTypeSend, + ePacketTypeRecv }; - // Class to change the timeout for a given scope and restore it to the original value when the - // created ScopedTimeout object got out of scope - class ScopedTimeout - { - public: - ScopedTimeout (GDBRemoteCommunication& gdb_comm, uint32_t timeout); - ~ScopedTimeout (); - - private: - GDBRemoteCommunication& m_gdb_comm; - uint32_t m_saved_timeout; + 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; }; - GDBRemoteCommunication(const char *comm_name, - const char *listener_name); - - ~GDBRemoteCommunication() override; - - PacketResult - GetAck (); - - size_t - SendAck (); + History(uint32_t size); - size_t - SendNack (); + ~History(); - char - CalculcateChecksum (const char *payload, - size_t payload_length); + // For single char packets for ack, nack and /x03 + void AddPacket(char packet_char, PacketType type, + uint32_t bytes_transmitted); - bool - GetSequenceMutex(Mutex::Locker& locker, const char *failure_message = nullptr); + void AddPacket(const std::string &src, uint32_t src_len, PacketType type, + uint32_t bytes_transmitted); - PacketType - CheckForPacket (const uint8_t *src, - size_t src_len, - StringExtractorGDBRemote &packet); + void Dump(Stream &strm) const; - bool - IsRunning() const - { - return m_public_is_running.GetValue(); - } + void Dump(Log *log) const; - bool - GetSendAcks () - { - return m_send_acks; - } + bool DidDumpToLog() const { return m_dumped_to_log; } - //------------------------------------------------------------------ - // Client and server must implement these pure virtual functions - //------------------------------------------------------------------ - virtual bool - GetThreadSuffixSupported () = 0; - - //------------------------------------------------------------------ - // Set the global packet timeout. - // - // For clients, this is the timeout that gets used when sending - // packets and waiting for responses. For servers, this might not - // get used, and if it doesn't this should be moved to the - // GDBRemoteCommunicationClient. - //------------------------------------------------------------------ - uint32_t - SetPacketTimeout (uint32_t packet_timeout) - { - const uint32_t old_packet_timeout = m_packet_timeout; - m_packet_timeout = packet_timeout; - return old_packet_timeout; + protected: + uint32_t GetFirstSavedPacketIndex() const { + if (m_total_packet_count < m_packets.size()) + return 0; + else + return m_curr_idx + 1; } - uint32_t - GetPacketTimeoutInMicroSeconds () const - { - return m_packet_timeout * TimeValue::MicroSecPerSec; + uint32_t GetNumPacketsInHistory() const { + if (m_total_packet_count < m_packets.size()) + return m_total_packet_count; + else + return (uint32_t)m_packets.size(); } - //------------------------------------------------------------------ - // Start a debugserver instance on the current host using the - // supplied connection URL. - //------------------------------------------------------------------ - Error - StartDebugserverProcess(const char *url, - Platform *platform, // If non nullptr, then check with the platform for the GDB server binary if it can't be located - ProcessLaunchInfo &launch_info, - uint16_t *port, - const Args& inferior_args = Args()); - - void - DumpHistory(Stream &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; - }; - - uint32_t m_packet_timeout; - uint32_t m_echo_number; - LazyBool m_supports_qEcho; -#ifdef ENABLE_MUTEX_ERROR_CHECKING - TrackingMutex m_sequence_mutex; -#else - Mutex m_sequence_mutex; // Restrict access to sending/receiving packets to a single thread at a time -#endif - Predicate<bool> m_public_is_running; - 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 - // a single process - - CompressionType m_compression_type; - - PacketResult - SendPacket (const char *payload, - size_t payload_length); - - PacketResult - SendPacketNoLock (const char *payload, - size_t payload_length); - - PacketResult - ReadPacket (StringExtractorGDBRemote &response, uint32_t timeout_usec, bool sync_on_timeout); - - // Pop a packet from the queue in a thread safe manner - PacketResult - PopPacketFromQueue (StringExtractorGDBRemote &response, uint32_t timeout_usec); - - PacketResult - WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtractorGDBRemote &response, - uint32_t timeout_usec, - bool sync_on_timeout); - - bool - WaitForNotRunningPrivate (const TimeValue *timeout_ptr); - - bool - CompressionIsEnabled () - { - return m_compression_type != CompressionType::None; + uint32_t GetNextIndex() { + ++m_total_packet_count; + const uint32_t idx = m_curr_idx; + m_curr_idx = NormalizeIndex(idx + 1); + return idx; } - // If compression is enabled, decompress the packet in m_bytes and update - // m_bytes with the uncompressed version. - // Returns 'true' packet was decompressed and m_bytes is the now-decompressed text. - // Returns 'false' if unable to decompress or if the checksum was invalid. - // - // NB: Once the packet has been decompressed, checksum cannot be computed based - // on m_bytes. The checksum was for the compressed packet. - bool - DecompressPacket (); - - Error - StartListenThread (const char *hostname = "127.0.0.1", uint16_t port = 0); - - bool - JoinListenThread (); - - static lldb::thread_result_t - ListenThread (lldb::thread_arg_t arg); - - // GDB-Remote read thread - // . this thread constantly tries to read from the communication - // class and stores all packets received in a queue. The usual - // threads read requests simply pop packets off the queue in the - // usual order. - // This setup allows us to intercept and handle async packets, such - // as the notify packet. - - // This method is defined as part of communication.h - // when the read thread gets any bytes it will pass them on to this function - void AppendBytesToCache(const uint8_t * bytes, - size_t len, - bool broadcast, - lldb::ConnectionStatus status) override; + 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; + }; + + std::chrono::seconds m_packet_timeout; + uint32_t m_echo_number; + LazyBool m_supports_qEcho; + 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 + // a single process + + CompressionType m_compression_type; + + PacketResult SendPacketNoLock(llvm::StringRef payload); + + PacketResult ReadPacket(StringExtractorGDBRemote &response, + Timeout<std::micro> timeout, bool sync_on_timeout); + + // Pop a packet from the queue in a thread safe manner + PacketResult PopPacketFromQueue(StringExtractorGDBRemote &response, + Timeout<std::micro> timeout); + + PacketResult WaitForPacketNoLock(StringExtractorGDBRemote &response, + Timeout<std::micro> timeout, + bool sync_on_timeout); + + bool CompressionIsEnabled() { + return m_compression_type != CompressionType::None; + } + + // If compression is enabled, decompress the packet in m_bytes and update + // m_bytes with the uncompressed version. + // Returns 'true' packet was decompressed and m_bytes is the now-decompressed + // text. + // Returns 'false' if unable to decompress or if the checksum was invalid. + // + // NB: Once the packet has been decompressed, checksum cannot be computed + // based + // on m_bytes. The checksum was for the compressed packet. + bool DecompressPacket(); + + Error StartListenThread(const char *hostname = "127.0.0.1", + uint16_t port = 0); + + bool JoinListenThread(); + + static lldb::thread_result_t ListenThread(lldb::thread_arg_t arg); + + // GDB-Remote read thread + // . this thread constantly tries to read from the communication + // class and stores all packets received in a queue. The usual + // threads read requests simply pop packets off the queue in the + // usual order. + // This setup allows us to intercept and handle async packets, such + // as the notify packet. + + // This method is defined as part of communication.h + // when the read thread gets any bytes it will pass them on to this function + void AppendBytesToCache(const uint8_t *bytes, size_t len, bool broadcast, + lldb::ConnectionStatus status) override; private: - std::queue<StringExtractorGDBRemote> m_packet_queue; // The packet queue - lldb_private::Mutex m_packet_queue_mutex; // Mutex for accessing queue - Condition m_condition_queue_not_empty; // Condition variable to wait for packets + std::queue<StringExtractorGDBRemote> m_packet_queue; // The packet queue + std::mutex m_packet_queue_mutex; // Mutex for accessing queue + std::condition_variable + m_condition_queue_not_empty; // Condition variable to wait for packets - HostThread m_listen_thread; - std::string m_listen_url; + HostThread m_listen_thread; + std::string m_listen_url; - DISALLOW_COPY_AND_ASSIGN (GDBRemoteCommunication); + DISALLOW_COPY_AND_ASSIGN(GDBRemoteCommunication); }; } // namespace process_gdb_remote diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index a792bbb..b70f090 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -7,7 +7,6 @@ // //===----------------------------------------------------------------------===// - #include "GDBRemoteCommunicationClient.h" // C Includes @@ -15,48 +14,48 @@ #include <sys/stat.h> // C++ Includes -#include <sstream> #include <numeric> +#include <sstream> // Other libraries and framework includes -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/Triple.h" -#include "lldb/Interpreter/Args.h" +#include "lldb/Core/DataBufferHeap.h" #include "lldb/Core/Log.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/State.h" #include "lldb/Core/StreamGDBRemote.h" #include "lldb/Core/StreamString.h" -#include "lldb/Host/ConnectionFileDescriptor.h" -#include "lldb/Host/Endian.h" -#include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" #include "lldb/Host/StringConvert.h" -#include "lldb/Host/TimeValue.h" +#include "lldb/Interpreter/Args.h" #include "lldb/Symbol/Symbol.h" -#include "lldb/Target/Target.h" #include "lldb/Target/MemoryRegionInfo.h" +#include "lldb/Target/Target.h" #include "lldb/Target/UnixSignals.h" +#include "lldb/Utility/JSON.h" +#include "lldb/Utility/LLDBAssert.h" // Project includes -#include "Utility/StringExtractorGDBRemote.h" #include "ProcessGDBRemote.h" #include "ProcessGDBRemoteLog.h" +#include "Utility/StringExtractorGDBRemote.h" #include "lldb/Host/Config.h" -#if defined (HAVE_LIBCOMPRESSION) +#include "llvm/ADT/StringSwitch.h" + +#if defined(HAVE_LIBCOMPRESSION) #include <compression.h> #endif using namespace lldb; using namespace lldb_private; using namespace lldb_private::process_gdb_remote; +using namespace std::chrono; //---------------------------------------------------------------------- // GDBRemoteCommunicationClient constructor //---------------------------------------------------------------------- GDBRemoteCommunicationClient::GDBRemoteCommunicationClient() - : GDBRemoteCommunication("gdb-remote.client", "gdb-remote.client.rx_packet"), + : GDBRemoteClientBase("gdb-remote.client", "gdb-remote.client.rx_packet"), m_supports_not_sending_acks(eLazyBoolCalculate), m_supports_thread_suffix(eLazyBoolCalculate), m_supports_threads_in_stop_reply(eLazyBoolCalculate), @@ -77,8 +76,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient() m_watchpoints_trigger_after_instruction(eLazyBoolCalculate), m_attach_or_wait_reply(eLazyBoolCalculate), m_prepare_for_reg_writing_reply(eLazyBoolCalculate), - m_supports_p(eLazyBoolCalculate), - m_supports_x(eLazyBoolCalculate), + m_supports_p(eLazyBoolCalculate), m_supports_x(eLazyBoolCalculate), m_avoid_g_packets(eLazyBoolCalculate), m_supports_QSaveRegisterState(eLazyBoolCalculate), m_supports_qXfer_auxv_read(eLazyBoolCalculate), @@ -88,503 +86,449 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient() m_supports_augmented_libraries_svr4_read(eLazyBoolCalculate), m_supports_jThreadExtendedInfo(eLazyBoolCalculate), m_supports_jLoadedDynamicLibrariesInfos(eLazyBoolCalculate), - m_supports_qProcessInfoPID(true), - m_supports_qfProcessInfo(true), - m_supports_qUserName(true), - m_supports_qGroupName(true), - m_supports_qThreadStopInfo(true), - m_supports_z0(true), - m_supports_z1(true), - m_supports_z2(true), - m_supports_z3(true), - m_supports_z4(true), - m_supports_QEnvironment(true), - m_supports_QEnvironmentHexEncoded(true), - m_supports_qSymbol(true), - m_qSymbol_requests_done(false), - m_supports_qModuleInfo(true), - m_supports_jThreadsInfo(true), - m_curr_pid(LLDB_INVALID_PROCESS_ID), - m_curr_tid(LLDB_INVALID_THREAD_ID), + m_supports_jGetSharedCacheInfo(eLazyBoolCalculate), + m_supports_qProcessInfoPID(true), m_supports_qfProcessInfo(true), + m_supports_qUserName(true), m_supports_qGroupName(true), + m_supports_qThreadStopInfo(true), m_supports_z0(true), + m_supports_z1(true), m_supports_z2(true), m_supports_z3(true), + m_supports_z4(true), m_supports_QEnvironment(true), + m_supports_QEnvironmentHexEncoded(true), m_supports_qSymbol(true), + m_qSymbol_requests_done(false), m_supports_qModuleInfo(true), + m_supports_jThreadsInfo(true), m_supports_jModulesInfo(true), + m_curr_pid(LLDB_INVALID_PROCESS_ID), m_curr_tid(LLDB_INVALID_THREAD_ID), m_curr_tid_run(LLDB_INVALID_THREAD_ID), - m_num_supported_hardware_watchpoints(0), - m_async_mutex(), - m_async_packet_predicate(false), - m_async_packet(), - m_async_result(PacketResult::Success), - m_async_response(), - m_async_signal(-1), - m_interrupt_sent(false), - m_thread_id_to_used_usec_map(), - m_host_arch(), - m_process_arch(), - m_os_version_major(UINT32_MAX), - m_os_version_minor(UINT32_MAX), - m_os_version_update(UINT32_MAX), - m_os_build(), - m_os_kernel(), - m_hostname(), - m_gdb_server_name(), - m_gdb_server_version(UINT32_MAX), - m_default_packet_timeout(0), - m_max_packet_size(0) -{ -} + m_num_supported_hardware_watchpoints(0), m_host_arch(), m_process_arch(), + m_os_version_major(UINT32_MAX), m_os_version_minor(UINT32_MAX), + m_os_version_update(UINT32_MAX), m_os_build(), m_os_kernel(), + m_hostname(), m_gdb_server_name(), m_gdb_server_version(UINT32_MAX), + m_default_packet_timeout(0), m_max_packet_size(0), + m_qSupported_response(), m_supported_async_json_packets_is_valid(false), + m_supported_async_json_packets_sp() {} //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- -GDBRemoteCommunicationClient::~GDBRemoteCommunicationClient() -{ - if (IsConnected()) - Disconnect(); -} - -bool -GDBRemoteCommunicationClient::HandshakeWithServer (Error *error_ptr) -{ - ResetDiscoverableSettings(false); - - // Start the read thread after we send the handshake ack since if we - // fail to send the handshake ack, there is no reason to continue... - if (SendAck()) - { - // Wait for any responses that might have been queued up in the remote - // GDB server and flush them all - StringExtractorGDBRemote response; - PacketResult packet_result = PacketResult::Success; - const uint32_t timeout_usec = 10 * 1000; // Wait for 10 ms for a response - while (packet_result == PacketResult::Success) - packet_result = ReadPacket (response, timeout_usec, false); - - // The return value from QueryNoAckModeSupported() is true if the packet - // was sent and _any_ response (including UNIMPLEMENTED) was received), - // or false if no response was received. This quickly tells us if we have - // a live connection to a remote GDB server... - if (QueryNoAckModeSupported()) - { - return true; - } - else - { - if (error_ptr) - error_ptr->SetErrorString("failed to get reply to handshake packet"); - } - } - else - { - if (error_ptr) - error_ptr->SetErrorString("failed to send the handshake ack"); - } - return false; +GDBRemoteCommunicationClient::~GDBRemoteCommunicationClient() { + if (IsConnected()) + Disconnect(); } -bool -GDBRemoteCommunicationClient::GetEchoSupported () -{ - if (m_supports_qEcho == eLazyBoolCalculate) - { - GetRemoteQSupported(); - } - return m_supports_qEcho == eLazyBoolYes; -} +bool GDBRemoteCommunicationClient::HandshakeWithServer(Error *error_ptr) { + ResetDiscoverableSettings(false); + // Start the read thread after we send the handshake ack since if we + // fail to send the handshake ack, there is no reason to continue... + if (SendAck()) { + // Wait for any responses that might have been queued up in the remote + // GDB server and flush them all + StringExtractorGDBRemote response; + PacketResult packet_result = PacketResult::Success; + while (packet_result == PacketResult::Success) + packet_result = ReadPacket(response, milliseconds(10), false); -bool -GDBRemoteCommunicationClient::GetAugmentedLibrariesSVR4ReadSupported () -{ - if (m_supports_augmented_libraries_svr4_read == eLazyBoolCalculate) - { - GetRemoteQSupported(); + // The return value from QueryNoAckModeSupported() is true if the packet + // was sent and _any_ response (including UNIMPLEMENTED) was received), + // or false if no response was received. This quickly tells us if we have + // a live connection to a remote GDB server... + if (QueryNoAckModeSupported()) { + return true; + } else { + if (error_ptr) + error_ptr->SetErrorString("failed to get reply to handshake packet"); } - return m_supports_augmented_libraries_svr4_read == eLazyBoolYes; + } else { + if (error_ptr) + error_ptr->SetErrorString("failed to send the handshake ack"); + } + return false; } -bool -GDBRemoteCommunicationClient::GetQXferLibrariesSVR4ReadSupported () -{ - if (m_supports_qXfer_libraries_svr4_read == eLazyBoolCalculate) - { - GetRemoteQSupported(); - } - return m_supports_qXfer_libraries_svr4_read == eLazyBoolYes; +bool GDBRemoteCommunicationClient::GetEchoSupported() { + if (m_supports_qEcho == eLazyBoolCalculate) { + GetRemoteQSupported(); + } + return m_supports_qEcho == eLazyBoolYes; } -bool -GDBRemoteCommunicationClient::GetQXferLibrariesReadSupported () -{ - if (m_supports_qXfer_libraries_read == eLazyBoolCalculate) - { - GetRemoteQSupported(); - } - return m_supports_qXfer_libraries_read == eLazyBoolYes; +bool GDBRemoteCommunicationClient::GetAugmentedLibrariesSVR4ReadSupported() { + if (m_supports_augmented_libraries_svr4_read == eLazyBoolCalculate) { + GetRemoteQSupported(); + } + return m_supports_augmented_libraries_svr4_read == eLazyBoolYes; } -bool -GDBRemoteCommunicationClient::GetQXferAuxvReadSupported () -{ - if (m_supports_qXfer_auxv_read == eLazyBoolCalculate) - { - GetRemoteQSupported(); - } - return m_supports_qXfer_auxv_read == eLazyBoolYes; +bool GDBRemoteCommunicationClient::GetQXferLibrariesSVR4ReadSupported() { + if (m_supports_qXfer_libraries_svr4_read == eLazyBoolCalculate) { + GetRemoteQSupported(); + } + return m_supports_qXfer_libraries_svr4_read == eLazyBoolYes; } -bool -GDBRemoteCommunicationClient::GetQXferFeaturesReadSupported () -{ - if (m_supports_qXfer_features_read == eLazyBoolCalculate) - { - GetRemoteQSupported(); - } - return m_supports_qXfer_features_read == eLazyBoolYes; +bool GDBRemoteCommunicationClient::GetQXferLibrariesReadSupported() { + if (m_supports_qXfer_libraries_read == eLazyBoolCalculate) { + GetRemoteQSupported(); + } + return m_supports_qXfer_libraries_read == eLazyBoolYes; } -uint64_t -GDBRemoteCommunicationClient::GetRemoteMaxPacketSize() -{ - if (m_max_packet_size == 0) - { - GetRemoteQSupported(); - } - return m_max_packet_size; +bool GDBRemoteCommunicationClient::GetQXferAuxvReadSupported() { + if (m_supports_qXfer_auxv_read == eLazyBoolCalculate) { + GetRemoteQSupported(); + } + return m_supports_qXfer_auxv_read == eLazyBoolYes; } -bool -GDBRemoteCommunicationClient::QueryNoAckModeSupported () -{ - if (m_supports_not_sending_acks == eLazyBoolCalculate) - { - m_send_acks = true; - m_supports_not_sending_acks = eLazyBoolNo; - - // This is the first real packet that we'll send in a debug session and it may take a little - // longer than normal to receive a reply. Wait at least 6 seconds for a reply to this packet. - - const uint32_t minimum_timeout = 6; - uint32_t old_timeout = GetPacketTimeoutInMicroSeconds() / lldb_private::TimeValue::MicroSecPerSec; - GDBRemoteCommunication::ScopedTimeout timeout (*this, std::max (old_timeout, minimum_timeout)); - - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("QStartNoAckMode", response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - { - m_send_acks = false; - m_supports_not_sending_acks = eLazyBoolYes; - } - return true; - } - } - return false; +bool GDBRemoteCommunicationClient::GetQXferFeaturesReadSupported() { + if (m_supports_qXfer_features_read == eLazyBoolCalculate) { + GetRemoteQSupported(); + } + return m_supports_qXfer_features_read == eLazyBoolYes; } -void -GDBRemoteCommunicationClient::GetListThreadsInStopReplySupported () -{ - if (m_supports_threads_in_stop_reply == eLazyBoolCalculate) - { - m_supports_threads_in_stop_reply = eLazyBoolNo; - - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("QListThreadsInStopReply", response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - m_supports_threads_in_stop_reply = eLazyBoolYes; - } - } +uint64_t GDBRemoteCommunicationClient::GetRemoteMaxPacketSize() { + if (m_max_packet_size == 0) { + GetRemoteQSupported(); + } + return m_max_packet_size; } -bool -GDBRemoteCommunicationClient::GetVAttachOrWaitSupported () -{ - if (m_attach_or_wait_reply == eLazyBoolCalculate) - { - m_attach_or_wait_reply = eLazyBoolNo; - - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("qVAttachOrWaitSupported", response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - m_attach_or_wait_reply = eLazyBoolYes; - } - } - if (m_attach_or_wait_reply == eLazyBoolYes) - return true; - else - return false; -} +bool GDBRemoteCommunicationClient::QueryNoAckModeSupported() { + if (m_supports_not_sending_acks == eLazyBoolCalculate) { + m_send_acks = true; + m_supports_not_sending_acks = eLazyBoolNo; -bool -GDBRemoteCommunicationClient::GetSyncThreadStateSupported () -{ - if (m_prepare_for_reg_writing_reply == eLazyBoolCalculate) - { - m_prepare_for_reg_writing_reply = eLazyBoolNo; - - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("qSyncThreadStateSupported", response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - m_prepare_for_reg_writing_reply = eLazyBoolYes; - } + // This is the first real packet that we'll send in a debug session and it + // may take a little + // longer than normal to receive a reply. Wait at least 6 seconds for a + // reply to this packet. + + ScopedTimeout timeout(*this, std::max(GetPacketTimeout(), seconds(6))); + + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse("QStartNoAckMode", response, false) == + PacketResult::Success) { + if (response.IsOKResponse()) { + m_send_acks = false; + m_supports_not_sending_acks = eLazyBoolYes; + } + return true; } - if (m_prepare_for_reg_writing_reply == eLazyBoolYes) - return true; - else - return false; + } + return false; } +void GDBRemoteCommunicationClient::GetListThreadsInStopReplySupported() { + if (m_supports_threads_in_stop_reply == eLazyBoolCalculate) { + m_supports_threads_in_stop_reply = eLazyBoolNo; -void -GDBRemoteCommunicationClient::ResetDiscoverableSettings (bool did_exec) -{ - if (did_exec == false) - { - // Hard reset everything, this is when we first connect to a GDB server - m_supports_not_sending_acks = eLazyBoolCalculate; - m_supports_thread_suffix = eLazyBoolCalculate; - m_supports_threads_in_stop_reply = eLazyBoolCalculate; - m_supports_vCont_c = eLazyBoolCalculate; - m_supports_vCont_C = eLazyBoolCalculate; - m_supports_vCont_s = eLazyBoolCalculate; - m_supports_vCont_S = eLazyBoolCalculate; - m_supports_p = eLazyBoolCalculate; - m_supports_x = eLazyBoolCalculate; - m_supports_QSaveRegisterState = eLazyBoolCalculate; - m_qHostInfo_is_valid = eLazyBoolCalculate; - m_curr_pid_is_valid = eLazyBoolCalculate; - m_qGDBServerVersion_is_valid = eLazyBoolCalculate; - m_supports_alloc_dealloc_memory = eLazyBoolCalculate; - m_supports_memory_region_info = eLazyBoolCalculate; - m_prepare_for_reg_writing_reply = eLazyBoolCalculate; - m_attach_or_wait_reply = eLazyBoolCalculate; - m_avoid_g_packets = eLazyBoolCalculate; - m_supports_qXfer_auxv_read = eLazyBoolCalculate; - m_supports_qXfer_libraries_read = eLazyBoolCalculate; - m_supports_qXfer_libraries_svr4_read = eLazyBoolCalculate; - m_supports_qXfer_features_read = eLazyBoolCalculate; - m_supports_augmented_libraries_svr4_read = eLazyBoolCalculate; - m_supports_qProcessInfoPID = true; - m_supports_qfProcessInfo = true; - m_supports_qUserName = true; - m_supports_qGroupName = true; - m_supports_qThreadStopInfo = true; - m_supports_z0 = true; - m_supports_z1 = true; - m_supports_z2 = true; - m_supports_z3 = true; - m_supports_z4 = true; - m_supports_QEnvironment = true; - m_supports_QEnvironmentHexEncoded = true; - m_supports_qSymbol = true; - m_qSymbol_requests_done = false; - m_supports_qModuleInfo = true; - m_host_arch.Clear(); - m_os_version_major = UINT32_MAX; - m_os_version_minor = UINT32_MAX; - m_os_version_update = UINT32_MAX; - m_os_build.clear(); - m_os_kernel.clear(); - m_hostname.clear(); - m_gdb_server_name.clear(); - m_gdb_server_version = UINT32_MAX; - m_default_packet_timeout = 0; - m_max_packet_size = 0; + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse("QListThreadsInStopReply", response, + false) == PacketResult::Success) { + if (response.IsOKResponse()) + m_supports_threads_in_stop_reply = eLazyBoolYes; } - - // These flags should be reset when we first connect to a GDB server - // and when our inferior process execs - m_qProcessInfo_is_valid = eLazyBoolCalculate; - m_process_arch.Clear(); + } } -void -GDBRemoteCommunicationClient::GetRemoteQSupported () -{ - // Clear out any capabilities we expect to see in the qSupported response - m_supports_qXfer_auxv_read = eLazyBoolNo; - m_supports_qXfer_libraries_read = eLazyBoolNo; - m_supports_qXfer_libraries_svr4_read = eLazyBoolNo; - m_supports_augmented_libraries_svr4_read = eLazyBoolNo; - m_supports_qXfer_features_read = eLazyBoolNo; - m_max_packet_size = UINT64_MAX; // It's supposed to always be there, but if not, we assume no limit - - // build the qSupported packet - std::vector<std::string> features = {"xmlRegisters=i386,arm,mips"}; - StreamString packet; - packet.PutCString( "qSupported" ); - for ( uint32_t i = 0; i < features.size( ); ++i ) - { - packet.PutCString( i==0 ? ":" : ";"); - packet.PutCString( features[i].c_str( ) ); - } +bool GDBRemoteCommunicationClient::GetVAttachOrWaitSupported() { + if (m_attach_or_wait_reply == eLazyBoolCalculate) { + m_attach_or_wait_reply = eLazyBoolNo; StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet.GetData(), - response, - /*send_async=*/false) == PacketResult::Success) - { - const char *response_cstr = response.GetStringRef().c_str(); - if (::strstr (response_cstr, "qXfer:auxv:read+")) - m_supports_qXfer_auxv_read = eLazyBoolYes; - if (::strstr (response_cstr, "qXfer:libraries-svr4:read+")) - m_supports_qXfer_libraries_svr4_read = eLazyBoolYes; - if (::strstr (response_cstr, "augmented-libraries-svr4-read")) - { - m_supports_qXfer_libraries_svr4_read = eLazyBoolYes; // implied - m_supports_augmented_libraries_svr4_read = eLazyBoolYes; - } - if (::strstr (response_cstr, "qXfer:libraries:read+")) - m_supports_qXfer_libraries_read = eLazyBoolYes; - if (::strstr (response_cstr, "qXfer:features:read+")) - m_supports_qXfer_features_read = eLazyBoolYes; - - - // Look for a list of compressions in the features list e.g. - // qXfer:features:read+;PacketSize=20000;qEcho+;SupportedCompressions=zlib-deflate,lzma - const char *features_list = ::strstr (response_cstr, "qXfer:features:"); - if (features_list) - { - const char *compressions = ::strstr (features_list, "SupportedCompressions="); - if (compressions) - { - std::vector<std::string> supported_compressions; - compressions += sizeof ("SupportedCompressions=") - 1; - const char *end_of_compressions = strchr (compressions, ';'); - if (end_of_compressions == NULL) - { - end_of_compressions = strchr (compressions, '\0'); - } - const char *current_compression = compressions; - while (current_compression < end_of_compressions) - { - const char *next_compression_name = strchr (current_compression, ','); - const char *end_of_this_word = next_compression_name; - if (next_compression_name == NULL || end_of_compressions < next_compression_name) - { - end_of_this_word = end_of_compressions; - } - - if (end_of_this_word) - { - if (end_of_this_word == current_compression) - { - current_compression++; - } - else - { - std::string this_compression (current_compression, end_of_this_word - current_compression); - supported_compressions.push_back (this_compression); - current_compression = end_of_this_word + 1; - } - } - else - { - supported_compressions.push_back (current_compression); - current_compression = end_of_compressions; - } - } + if (SendPacketAndWaitForResponse("qVAttachOrWaitSupported", response, + false) == PacketResult::Success) { + if (response.IsOKResponse()) + m_attach_or_wait_reply = eLazyBoolYes; + } + } + if (m_attach_or_wait_reply == eLazyBoolYes) + return true; + else + return false; +} - if (supported_compressions.size() > 0) - { - MaybeEnableCompression (supported_compressions); - } - } - } +bool GDBRemoteCommunicationClient::GetSyncThreadStateSupported() { + if (m_prepare_for_reg_writing_reply == eLazyBoolCalculate) { + m_prepare_for_reg_writing_reply = eLazyBoolNo; - if (::strstr (response_cstr, "qEcho")) - m_supports_qEcho = eLazyBoolYes; - else - m_supports_qEcho = eLazyBoolNo; - - const char *packet_size_str = ::strstr (response_cstr, "PacketSize="); - if (packet_size_str) - { - StringExtractorGDBRemote packet_response(packet_size_str + strlen("PacketSize=")); - m_max_packet_size = packet_response.GetHexMaxU64(/*little_endian=*/false, UINT64_MAX); - if (m_max_packet_size == 0) - { - m_max_packet_size = UINT64_MAX; // Must have been a garbled response - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); - if (log) - log->Printf ("Garbled PacketSize spec in qSupported response"); - } - } + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse("qSyncThreadStateSupported", response, + false) == PacketResult::Success) { + if (response.IsOKResponse()) + m_prepare_for_reg_writing_reply = eLazyBoolYes; } + } + if (m_prepare_for_reg_writing_reply == eLazyBoolYes) + return true; + else + return false; } -bool -GDBRemoteCommunicationClient::GetThreadSuffixSupported () -{ - if (m_supports_thread_suffix == eLazyBoolCalculate) - { - StringExtractorGDBRemote response; - m_supports_thread_suffix = eLazyBoolNo; - if (SendPacketAndWaitForResponse("QThreadSuffixSupported", response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - m_supports_thread_suffix = eLazyBoolYes; - } +void GDBRemoteCommunicationClient::ResetDiscoverableSettings(bool did_exec) { + if (did_exec == false) { + // Hard reset everything, this is when we first connect to a GDB server + m_supports_not_sending_acks = eLazyBoolCalculate; + m_supports_thread_suffix = eLazyBoolCalculate; + m_supports_threads_in_stop_reply = eLazyBoolCalculate; + m_supports_vCont_c = eLazyBoolCalculate; + m_supports_vCont_C = eLazyBoolCalculate; + m_supports_vCont_s = eLazyBoolCalculate; + m_supports_vCont_S = eLazyBoolCalculate; + m_supports_p = eLazyBoolCalculate; + m_supports_x = eLazyBoolCalculate; + m_supports_QSaveRegisterState = eLazyBoolCalculate; + m_qHostInfo_is_valid = eLazyBoolCalculate; + m_curr_pid_is_valid = eLazyBoolCalculate; + m_qGDBServerVersion_is_valid = eLazyBoolCalculate; + m_supports_alloc_dealloc_memory = eLazyBoolCalculate; + m_supports_memory_region_info = eLazyBoolCalculate; + m_prepare_for_reg_writing_reply = eLazyBoolCalculate; + m_attach_or_wait_reply = eLazyBoolCalculate; + m_avoid_g_packets = eLazyBoolCalculate; + m_supports_qXfer_auxv_read = eLazyBoolCalculate; + m_supports_qXfer_libraries_read = eLazyBoolCalculate; + m_supports_qXfer_libraries_svr4_read = eLazyBoolCalculate; + m_supports_qXfer_features_read = eLazyBoolCalculate; + m_supports_augmented_libraries_svr4_read = eLazyBoolCalculate; + m_supports_qProcessInfoPID = true; + m_supports_qfProcessInfo = true; + m_supports_qUserName = true; + m_supports_qGroupName = true; + m_supports_qThreadStopInfo = true; + m_supports_z0 = true; + m_supports_z1 = true; + m_supports_z2 = true; + m_supports_z3 = true; + m_supports_z4 = true; + m_supports_QEnvironment = true; + m_supports_QEnvironmentHexEncoded = true; + m_supports_qSymbol = true; + m_qSymbol_requests_done = false; + m_supports_qModuleInfo = true; + m_host_arch.Clear(); + m_os_version_major = UINT32_MAX; + m_os_version_minor = UINT32_MAX; + m_os_version_update = UINT32_MAX; + m_os_build.clear(); + m_os_kernel.clear(); + m_hostname.clear(); + m_gdb_server_name.clear(); + m_gdb_server_version = UINT32_MAX; + m_default_packet_timeout = seconds(0); + m_max_packet_size = 0; + m_qSupported_response.clear(); + m_supported_async_json_packets_is_valid = false; + m_supported_async_json_packets_sp.reset(); + m_supports_jModulesInfo = true; + } + + // These flags should be reset when we first connect to a GDB server + // and when our inferior process execs + m_qProcessInfo_is_valid = eLazyBoolCalculate; + m_process_arch.Clear(); +} + +void GDBRemoteCommunicationClient::GetRemoteQSupported() { + // Clear out any capabilities we expect to see in the qSupported response + m_supports_qXfer_auxv_read = eLazyBoolNo; + m_supports_qXfer_libraries_read = eLazyBoolNo; + m_supports_qXfer_libraries_svr4_read = eLazyBoolNo; + m_supports_augmented_libraries_svr4_read = eLazyBoolNo; + m_supports_qXfer_features_read = eLazyBoolNo; + m_max_packet_size = UINT64_MAX; // It's supposed to always be there, but if + // not, we assume no limit + + // build the qSupported packet + std::vector<std::string> features = {"xmlRegisters=i386,arm,mips"}; + StreamString packet; + packet.PutCString("qSupported"); + for (uint32_t i = 0; i < features.size(); ++i) { + packet.PutCString(i == 0 ? ":" : ";"); + packet.PutCString(features[i]); + } + + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet.GetString(), response, + /*send_async=*/false) == + PacketResult::Success) { + const char *response_cstr = response.GetStringRef().c_str(); + + // Hang on to the qSupported packet, so that platforms can do custom + // configuration of the transport before attaching/launching the + // process. + m_qSupported_response = response_cstr; + + if (::strstr(response_cstr, "qXfer:auxv:read+")) + m_supports_qXfer_auxv_read = eLazyBoolYes; + if (::strstr(response_cstr, "qXfer:libraries-svr4:read+")) + m_supports_qXfer_libraries_svr4_read = eLazyBoolYes; + if (::strstr(response_cstr, "augmented-libraries-svr4-read")) { + m_supports_qXfer_libraries_svr4_read = eLazyBoolYes; // implied + m_supports_augmented_libraries_svr4_read = eLazyBoolYes; + } + if (::strstr(response_cstr, "qXfer:libraries:read+")) + m_supports_qXfer_libraries_read = eLazyBoolYes; + if (::strstr(response_cstr, "qXfer:features:read+")) + m_supports_qXfer_features_read = eLazyBoolYes; + + // Look for a list of compressions in the features list e.g. + // qXfer:features:read+;PacketSize=20000;qEcho+;SupportedCompressions=zlib-deflate,lzma + const char *features_list = ::strstr(response_cstr, "qXfer:features:"); + if (features_list) { + const char *compressions = + ::strstr(features_list, "SupportedCompressions="); + if (compressions) { + std::vector<std::string> supported_compressions; + compressions += sizeof("SupportedCompressions=") - 1; + const char *end_of_compressions = strchr(compressions, ';'); + if (end_of_compressions == NULL) { + end_of_compressions = strchr(compressions, '\0'); + } + const char *current_compression = compressions; + while (current_compression < end_of_compressions) { + const char *next_compression_name = strchr(current_compression, ','); + const char *end_of_this_word = next_compression_name; + if (next_compression_name == NULL || + end_of_compressions < next_compression_name) { + end_of_this_word = end_of_compressions; + } + + if (end_of_this_word) { + if (end_of_this_word == current_compression) { + current_compression++; + } else { + std::string this_compression( + current_compression, end_of_this_word - current_compression); + supported_compressions.push_back(this_compression); + current_compression = end_of_this_word + 1; + } + } else { + supported_compressions.push_back(current_compression); + current_compression = end_of_compressions; + } + } + + if (supported_compressions.size() > 0) { + MaybeEnableCompression(supported_compressions); + } + } + } + + if (::strstr(response_cstr, "qEcho")) + m_supports_qEcho = eLazyBoolYes; + else + m_supports_qEcho = eLazyBoolNo; + + const char *packet_size_str = ::strstr(response_cstr, "PacketSize="); + if (packet_size_str) { + StringExtractorGDBRemote packet_response(packet_size_str + + strlen("PacketSize=")); + m_max_packet_size = + packet_response.GetHexMaxU64(/*little_endian=*/false, UINT64_MAX); + if (m_max_packet_size == 0) { + m_max_packet_size = UINT64_MAX; // Must have been a garbled response + Log *log( + ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + if (log) + log->Printf("Garbled PacketSize spec in qSupported response"); + } } - return m_supports_thread_suffix; + } } -bool -GDBRemoteCommunicationClient::GetVContSupported (char flavor) -{ - if (m_supports_vCont_c == eLazyBoolCalculate) - { - StringExtractorGDBRemote response; - m_supports_vCont_any = eLazyBoolNo; - m_supports_vCont_all = eLazyBoolNo; - m_supports_vCont_c = eLazyBoolNo; - m_supports_vCont_C = eLazyBoolNo; - m_supports_vCont_s = eLazyBoolNo; - m_supports_vCont_S = eLazyBoolNo; - if (SendPacketAndWaitForResponse("vCont?", response, false) == PacketResult::Success) - { - const char *response_cstr = response.GetStringRef().c_str(); - if (::strstr (response_cstr, ";c")) - m_supports_vCont_c = eLazyBoolYes; - - if (::strstr (response_cstr, ";C")) - m_supports_vCont_C = eLazyBoolYes; - - if (::strstr (response_cstr, ";s")) - m_supports_vCont_s = eLazyBoolYes; - - if (::strstr (response_cstr, ";S")) - m_supports_vCont_S = eLazyBoolYes; - - if (m_supports_vCont_c == eLazyBoolYes && - m_supports_vCont_C == eLazyBoolYes && - m_supports_vCont_s == eLazyBoolYes && - m_supports_vCont_S == eLazyBoolYes) - { - m_supports_vCont_all = eLazyBoolYes; - } - - if (m_supports_vCont_c == eLazyBoolYes || - m_supports_vCont_C == eLazyBoolYes || - m_supports_vCont_s == eLazyBoolYes || - m_supports_vCont_S == eLazyBoolYes) - { - m_supports_vCont_any = eLazyBoolYes; - } - } - } - - switch (flavor) - { - case 'a': return m_supports_vCont_any; - case 'A': return m_supports_vCont_all; - case 'c': return m_supports_vCont_c; - case 'C': return m_supports_vCont_C; - case 's': return m_supports_vCont_s; - case 'S': return m_supports_vCont_S; - default: break; + +bool GDBRemoteCommunicationClient::GetThreadSuffixSupported() { + if (m_supports_thread_suffix == eLazyBoolCalculate) { + StringExtractorGDBRemote response; + m_supports_thread_suffix = eLazyBoolNo; + if (SendPacketAndWaitForResponse("QThreadSuffixSupported", response, + false) == PacketResult::Success) { + if (response.IsOKResponse()) + m_supports_thread_suffix = eLazyBoolYes; } - return false; + } + return m_supports_thread_suffix; +} +bool GDBRemoteCommunicationClient::GetVContSupported(char flavor) { + if (m_supports_vCont_c == eLazyBoolCalculate) { + StringExtractorGDBRemote response; + m_supports_vCont_any = eLazyBoolNo; + m_supports_vCont_all = eLazyBoolNo; + m_supports_vCont_c = eLazyBoolNo; + m_supports_vCont_C = eLazyBoolNo; + m_supports_vCont_s = eLazyBoolNo; + m_supports_vCont_S = eLazyBoolNo; + if (SendPacketAndWaitForResponse("vCont?", response, false) == + PacketResult::Success) { + const char *response_cstr = response.GetStringRef().c_str(); + if (::strstr(response_cstr, ";c")) + m_supports_vCont_c = eLazyBoolYes; + + if (::strstr(response_cstr, ";C")) + m_supports_vCont_C = eLazyBoolYes; + + if (::strstr(response_cstr, ";s")) + m_supports_vCont_s = eLazyBoolYes; + + if (::strstr(response_cstr, ";S")) + m_supports_vCont_S = eLazyBoolYes; + + if (m_supports_vCont_c == eLazyBoolYes && + m_supports_vCont_C == eLazyBoolYes && + m_supports_vCont_s == eLazyBoolYes && + m_supports_vCont_S == eLazyBoolYes) { + m_supports_vCont_all = eLazyBoolYes; + } + + if (m_supports_vCont_c == eLazyBoolYes || + m_supports_vCont_C == eLazyBoolYes || + m_supports_vCont_s == eLazyBoolYes || + m_supports_vCont_S == eLazyBoolYes) { + m_supports_vCont_any = eLazyBoolYes; + } + } + } + + switch (flavor) { + case 'a': + return m_supports_vCont_any; + case 'A': + return m_supports_vCont_all; + case 'c': + return m_supports_vCont_c; + case 'C': + return m_supports_vCont_C; + case 's': + return m_supports_vCont_s; + case 'S': + return m_supports_vCont_S; + default: + break; + } + return false; +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationClient::SendThreadSpecificPacketAndWaitForResponse( + lldb::tid_t tid, StreamString &&payload, StringExtractorGDBRemote &response, + bool send_async) { + Lock lock(*this, send_async); + if (!lock) { + if (Log *log = ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet( + GDBR_LOG_PROCESS | GDBR_LOG_PACKETS)) + log->Printf("GDBRemoteCommunicationClient::%s: Didn't get sequence mutex " + "for %s packet.", + __FUNCTION__, payload.GetData()); + return PacketResult::ErrorNoSequenceLock; + } + + if (GetThreadSuffixSupported()) + payload.Printf(";thread:%4.4" PRIx64 ";", tid); + else { + if (!SetCurrentThread(tid)) + return PacketResult::ErrorSendFailed; + } + + return SendPacketAndWaitForResponseNoLock(payload.GetString(), response); } // Check if the target supports 'p' packet. It sends out a 'p' @@ -592,4043 +536,3095 @@ GDBRemoteCommunicationClient::GetVContSupported (char flavor) // that support is available. // // Takes a valid thread ID because p needs to apply to a thread. -bool -GDBRemoteCommunicationClient::GetpPacketSupported (lldb::tid_t tid) -{ - if (m_supports_p == eLazyBoolCalculate) - { - StringExtractorGDBRemote response; - m_supports_p = eLazyBoolNo; - char packet[256]; - if (GetThreadSuffixSupported()) - snprintf(packet, sizeof(packet), "p0;thread:%" PRIx64 ";", tid); - else - snprintf(packet, sizeof(packet), "p0"); - - if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success) - { - if (response.IsNormalResponse()) - m_supports_p = eLazyBoolYes; - } - } - return m_supports_p; -} - -StructuredData::ObjectSP -GDBRemoteCommunicationClient::GetThreadsInfo() -{ - // Get information on all threads at one using the "jThreadsInfo" packet - StructuredData::ObjectSP object_sp; - - if (m_supports_jThreadsInfo) - { - StringExtractorGDBRemote response; - response.SetResponseValidatorToJSON(); - if (SendPacketAndWaitForResponse("jThreadsInfo", response, false) == PacketResult::Success) - { - if (response.IsUnsupportedResponse()) - { - m_supports_jThreadsInfo = false; - } - else if (!response.Empty()) - { - object_sp = StructuredData::ParseJSON (response.GetStringRef()); - } - } +bool GDBRemoteCommunicationClient::GetpPacketSupported(lldb::tid_t tid) { + if (m_supports_p == eLazyBoolCalculate) { + m_supports_p = eLazyBoolNo; + StreamString payload; + payload.PutCString("p0"); + StringExtractorGDBRemote response; + if (SendThreadSpecificPacketAndWaitForResponse(tid, std::move(payload), + response, false) == + PacketResult::Success && + response.IsNormalResponse()) { + m_supports_p = eLazyBoolYes; } - return object_sp; + } + return m_supports_p; } +StructuredData::ObjectSP GDBRemoteCommunicationClient::GetThreadsInfo() { + // Get information on all threads at one using the "jThreadsInfo" packet + StructuredData::ObjectSP object_sp; -bool -GDBRemoteCommunicationClient::GetThreadExtendedInfoSupported () -{ - if (m_supports_jThreadExtendedInfo == eLazyBoolCalculate) - { - StringExtractorGDBRemote response; - m_supports_jThreadExtendedInfo = eLazyBoolNo; - if (SendPacketAndWaitForResponse("jThreadExtendedInfo:", response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - { - m_supports_jThreadExtendedInfo = eLazyBoolYes; - } - } + if (m_supports_jThreadsInfo) { + StringExtractorGDBRemote response; + response.SetResponseValidatorToJSON(); + if (SendPacketAndWaitForResponse("jThreadsInfo", response, false) == + PacketResult::Success) { + if (response.IsUnsupportedResponse()) { + m_supports_jThreadsInfo = false; + } else if (!response.Empty()) { + object_sp = StructuredData::ParseJSON(response.GetStringRef()); + } } - return m_supports_jThreadExtendedInfo; + } + return object_sp; } -bool -GDBRemoteCommunicationClient::GetLoadedDynamicLibrariesInfosSupported () -{ - if (m_supports_jLoadedDynamicLibrariesInfos == eLazyBoolCalculate) - { - StringExtractorGDBRemote response; - m_supports_jLoadedDynamicLibrariesInfos = eLazyBoolNo; - if (SendPacketAndWaitForResponse("jGetLoadedDynamicLibrariesInfos:", response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - { - m_supports_jLoadedDynamicLibrariesInfos = eLazyBoolYes; - } - } +bool GDBRemoteCommunicationClient::GetThreadExtendedInfoSupported() { + if (m_supports_jThreadExtendedInfo == eLazyBoolCalculate) { + StringExtractorGDBRemote response; + m_supports_jThreadExtendedInfo = eLazyBoolNo; + if (SendPacketAndWaitForResponse("jThreadExtendedInfo:", response, false) == + PacketResult::Success) { + if (response.IsOKResponse()) { + m_supports_jThreadExtendedInfo = eLazyBoolYes; + } } - return m_supports_jLoadedDynamicLibrariesInfos; + } + return m_supports_jThreadExtendedInfo; } -bool -GDBRemoteCommunicationClient::GetxPacketSupported () -{ - if (m_supports_x == eLazyBoolCalculate) - { - StringExtractorGDBRemote response; - m_supports_x = eLazyBoolNo; - char packet[256]; - snprintf (packet, sizeof (packet), "x0,0"); - if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - m_supports_x = eLazyBoolYes; - } +bool GDBRemoteCommunicationClient::GetLoadedDynamicLibrariesInfosSupported() { + if (m_supports_jLoadedDynamicLibrariesInfos == eLazyBoolCalculate) { + StringExtractorGDBRemote response; + m_supports_jLoadedDynamicLibrariesInfos = eLazyBoolNo; + if (SendPacketAndWaitForResponse("jGetLoadedDynamicLibrariesInfos:", + response, + false) == PacketResult::Success) { + if (response.IsOKResponse()) { + m_supports_jLoadedDynamicLibrariesInfos = eLazyBoolYes; + } } - return m_supports_x; + } + return m_supports_jLoadedDynamicLibrariesInfos; } -GDBRemoteCommunicationClient::PacketResult -GDBRemoteCommunicationClient::SendPacketsAndConcatenateResponses -( - const char *payload_prefix, - std::string &response_string -) -{ - Mutex::Locker locker; - if (!GetSequenceMutex(locker, - "ProcessGDBRemote::SendPacketsAndConcatenateResponses() failed due to not getting the sequence mutex")) - { - Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_PROCESS | GDBR_LOG_PACKETS)); - if (log) - log->Printf("error: failed to get packet sequence mutex, not sending packets with prefix '%s'", - payload_prefix); - return PacketResult::ErrorNoSequenceLock; - } - - response_string = ""; - std::string payload_prefix_str(payload_prefix); - unsigned int response_size = 0x1000; - if (response_size > GetRemoteMaxPacketSize()) { // May send qSupported packet - response_size = GetRemoteMaxPacketSize(); - } - - for (unsigned int offset = 0; true; offset += response_size) - { - StringExtractorGDBRemote this_response; - // Construct payload - char sizeDescriptor[128]; - snprintf(sizeDescriptor, sizeof(sizeDescriptor), "%x,%x", offset, response_size); - PacketResult result = SendPacketAndWaitForResponse((payload_prefix_str + sizeDescriptor).c_str(), - this_response, - /*send_async=*/false); - if (result != PacketResult::Success) - return result; - - const std::string &this_string = this_response.GetStringRef(); - - // Check for m or l as first character; l seems to mean this is the last chunk - char first_char = *this_string.c_str(); - if (first_char != 'm' && first_char != 'l') - { - return PacketResult::ErrorReplyInvalid; - } - // Concatenate the result so far (skipping 'm' or 'l') - response_string.append(this_string, 1, std::string::npos); - if (first_char == 'l') - // We're done - return PacketResult::Success; +bool GDBRemoteCommunicationClient::GetSharedCacheInfoSupported() { + if (m_supports_jGetSharedCacheInfo == eLazyBoolCalculate) { + StringExtractorGDBRemote response; + m_supports_jGetSharedCacheInfo = eLazyBoolNo; + if (SendPacketAndWaitForResponse("jGetSharedCacheInfo:", response, false) == + PacketResult::Success) { + if (response.IsOKResponse()) { + m_supports_jGetSharedCacheInfo = eLazyBoolYes; + } } + } + return m_supports_jGetSharedCacheInfo; } -GDBRemoteCommunicationClient::PacketResult -GDBRemoteCommunicationClient::SendPacketAndWaitForResponse -( - const char *payload, - StringExtractorGDBRemote &response, - bool send_async -) -{ - return SendPacketAndWaitForResponse (payload, - ::strlen (payload), - response, - send_async); -} - -GDBRemoteCommunicationClient::PacketResult -GDBRemoteCommunicationClient::SendPacketAndWaitForResponseNoLock (const char *payload, - size_t payload_length, - StringExtractorGDBRemote &response) -{ - PacketResult packet_result = SendPacketNoLock(payload, payload_length); - if (packet_result == PacketResult::Success) - { - const size_t max_response_retries = 3; - for (size_t i=0; i<max_response_retries; ++i) - { - packet_result = ReadPacket(response, GetPacketTimeoutInMicroSeconds (), true); - // Make sure we received a response - if (packet_result != PacketResult::Success) - return packet_result; - // Make sure our response is valid for the payload that was sent - if (response.ValidateResponse()) - return packet_result; - // Response says it wasn't valid - Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS); - if (log) - log->Printf("error: packet with payload \"%*s\" got invalid response \"%s\": %s", - (int)payload_length, - payload, - response.GetStringRef().c_str(), - (i == (max_response_retries - 1)) ? "using invalid response and giving up" : "ignoring response and waiting for another"); - } +bool GDBRemoteCommunicationClient::GetxPacketSupported() { + if (m_supports_x == eLazyBoolCalculate) { + StringExtractorGDBRemote response; + m_supports_x = eLazyBoolNo; + char packet[256]; + snprintf(packet, sizeof(packet), "x0,0"); + if (SendPacketAndWaitForResponse(packet, response, false) == + PacketResult::Success) { + if (response.IsOKResponse()) + m_supports_x = eLazyBoolYes; } - return packet_result; + } + return m_supports_x; } GDBRemoteCommunicationClient::PacketResult -GDBRemoteCommunicationClient::SendPacketAndWaitForResponse -( - const char *payload, - size_t payload_length, - StringExtractorGDBRemote &response, - bool send_async -) -{ - PacketResult packet_result = PacketResult::ErrorSendFailed; - Mutex::Locker locker; - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); - - // In order to stop async notifications from being processed in the middle of the - // send/receive sequence Hijack the broadcast. Then rebroadcast any events when we are done. - static ListenerSP hijack_listener_sp(Listener::MakeListener("lldb.NotifyHijacker")); - HijackBroadcaster(hijack_listener_sp, eBroadcastBitGdbReadThreadGotNotify); - - if (GetSequenceMutex (locker)) - { - packet_result = SendPacketAndWaitForResponseNoLock (payload, payload_length, response); - } - else - { - if (send_async) - { - if (IsRunning()) - { - std::lock_guard<std::recursive_mutex> guard(m_async_mutex); - m_async_packet.assign(payload, payload_length); - m_async_response.CopyResponseValidator(response); - m_async_packet_predicate.SetValue (true, eBroadcastNever); - - if (log) - log->Printf ("async: async packet = %s", m_async_packet.c_str()); - - bool timed_out = false; - if (SendInterrupt(locker, 2, timed_out)) - { - if (m_interrupt_sent) - { - m_interrupt_sent = false; - TimeValue timeout_time; - timeout_time = TimeValue::Now(); - timeout_time.OffsetWithSeconds (m_packet_timeout); - - if (log) - log->Printf ("async: sent interrupt"); - - if (m_async_packet_predicate.WaitForValueEqualTo (false, &timeout_time, &timed_out)) - { - if (log) - log->Printf ("async: got response"); - - // Swap the response buffer to avoid malloc and string copy - response.GetStringRef().swap (m_async_response.GetStringRef()); - packet_result = m_async_result; - } - else - { - if (log) - log->Printf ("async: timed out waiting for response"); - } - - // Make sure we wait until the continue packet has been sent again... - if (m_private_is_running.WaitForValueEqualTo (true, &timeout_time, &timed_out)) - { - if (log) - { - if (timed_out) - log->Printf ("async: timed out waiting for process to resume, but process was resumed"); - else - log->Printf ("async: async packet sent"); - } - } - else - { - if (log) - log->Printf ("async: timed out waiting for process to resume"); - } - } - else - { - // We had a racy condition where we went to send the interrupt - // yet we were able to get the lock, so the process must have - // just stopped? - if (log) - log->Printf ("async: got lock without sending interrupt"); - // Send the packet normally since we got the lock - packet_result = SendPacketAndWaitForResponseNoLock (payload, payload_length, response); - } - } - else - { - if (log) - log->Printf ("async: failed to interrupt"); - } - - m_async_response.SetResponseValidator(nullptr, nullptr); - - } - else - { - if (log) - log->Printf ("async: not running, async is ignored"); - } - } - else - { - if (log) - log->Printf("error: failed to get packet sequence mutex, not sending packet '%*s'", (int) payload_length, payload); - } - } - - // Remove our Hijacking listener from the broadcast. - RestoreBroadcaster(); - - // If a notification event occurred, rebroadcast since it can now be processed safely. - EventSP event_sp; - if (hijack_listener_sp->GetNextEvent(event_sp)) - BroadcastEvent(event_sp); - - return packet_result; -} - -static const char *end_delimiter = "--end--;"; -static const int end_delimiter_len = 8; - -std::string -GDBRemoteCommunicationClient::HarmonizeThreadIdsForProfileData -( ProcessGDBRemote *process, - StringExtractorGDBRemote& profileDataExtractor -) -{ - std::map<uint64_t, uint32_t> new_thread_id_to_used_usec_map; - std::stringstream final_output; - std::string name, value; - - // Going to assuming thread_used_usec comes first, else bail out. - while (profileDataExtractor.GetNameColonValue(name, value)) - { - if (name.compare("thread_used_id") == 0) - { - StringExtractor threadIDHexExtractor(value.c_str()); - uint64_t thread_id = threadIDHexExtractor.GetHexMaxU64(false, 0); - - bool has_used_usec = false; - uint32_t curr_used_usec = 0; - std::string usec_name, usec_value; - uint32_t input_file_pos = profileDataExtractor.GetFilePos(); - if (profileDataExtractor.GetNameColonValue(usec_name, usec_value)) - { - if (usec_name.compare("thread_used_usec") == 0) - { - has_used_usec = true; - curr_used_usec = strtoull(usec_value.c_str(), NULL, 0); - } - else - { - // We didn't find what we want, it is probably - // an older version. Bail out. - profileDataExtractor.SetFilePos(input_file_pos); - } - } - - if (has_used_usec) - { - uint32_t prev_used_usec = 0; - std::map<uint64_t, uint32_t>::iterator iterator = m_thread_id_to_used_usec_map.find(thread_id); - if (iterator != m_thread_id_to_used_usec_map.end()) - { - prev_used_usec = m_thread_id_to_used_usec_map[thread_id]; - } - - uint32_t real_used_usec = curr_used_usec - prev_used_usec; - // A good first time record is one that runs for at least 0.25 sec - bool good_first_time = (prev_used_usec == 0) && (real_used_usec > 250000); - bool good_subsequent_time = (prev_used_usec > 0) && - ((real_used_usec > 0) || (process->HasAssignedIndexIDToThread(thread_id))); - - if (good_first_time || good_subsequent_time) - { - // We try to avoid doing too many index id reservation, - // resulting in fast increase of index ids. - - final_output << name << ":"; - int32_t index_id = process->AssignIndexIDToThread(thread_id); - final_output << index_id << ";"; - - final_output << usec_name << ":" << usec_value << ";"; - } - else - { - // Skip past 'thread_used_name'. - std::string local_name, local_value; - profileDataExtractor.GetNameColonValue(local_name, local_value); - } - - // Store current time as previous time so that they can be compared later. - new_thread_id_to_used_usec_map[thread_id] = curr_used_usec; - } - else - { - // Bail out and use old string. - final_output << name << ":" << value << ";"; - } - } - else - { - final_output << name << ":" << value << ";"; - } - } - final_output << end_delimiter; - m_thread_id_to_used_usec_map = new_thread_id_to_used_usec_map; - - return final_output.str(); -} - -bool -GDBRemoteCommunicationClient::SendvContPacket -( - ProcessGDBRemote *process, - const char *payload, - size_t packet_length, - StringExtractorGDBRemote &response -) -{ - - m_curr_tid = LLDB_INVALID_THREAD_ID; - Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); - if (log) - log->Printf("GDBRemoteCommunicationClient::%s ()", __FUNCTION__); - - // we want to lock down packet sending while we continue - Mutex::Locker locker(m_sequence_mutex); - - // here we broadcast this before we even send the packet!! - // this signals doContinue() to exit - BroadcastEvent(eBroadcastBitRunPacketSent, NULL); - - // set the public state to running - m_public_is_running.SetValue(true, eBroadcastNever); - - // Set the starting continue packet into "continue_packet". This packet - // may change if we are interrupted and we continue after an async packet... - std::string continue_packet(payload, packet_length); - - if (log) - log->Printf("GDBRemoteCommunicationClient::%s () sending vCont packet: %s", __FUNCTION__, continue_packet.c_str()); - - if (SendPacketNoLock(continue_packet.c_str(), continue_packet.size()) != PacketResult::Success) - return false; - - // set the private state to running and broadcast this - m_private_is_running.SetValue(true, eBroadcastAlways); - +GDBRemoteCommunicationClient::SendPacketsAndConcatenateResponses( + const char *payload_prefix, std::string &response_string) { + Lock lock(*this, false); + if (!lock) { + Log *log(ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(GDBR_LOG_PROCESS | + GDBR_LOG_PACKETS)); if (log) - log->Printf("GDBRemoteCommunicationClient::%s () ReadPacket(%s)", __FUNCTION__, continue_packet.c_str()); - - // wait for the response to the vCont - if (ReadPacket(response, UINT32_MAX, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - return true; - } - - return false; -} - -StateType -GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse -( - ProcessGDBRemote *process, - const char *payload, - size_t packet_length, - StringExtractorGDBRemote &response -) -{ - m_curr_tid = LLDB_INVALID_THREAD_ID; - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); - if (log) - log->Printf ("GDBRemoteCommunicationClient::%s ()", __FUNCTION__); - - Mutex::Locker locker(m_sequence_mutex); - StateType state = eStateRunning; - - m_public_is_running.SetValue (true, eBroadcastNever); - // Set the starting continue packet into "continue_packet". This packet - // may change if we are interrupted and we continue after an async packet... - std::string continue_packet(payload, packet_length); - - const auto sigstop_signo = process->GetUnixSignals()->GetSignalNumberFromName("SIGSTOP"); - const auto sigint_signo = process->GetUnixSignals()->GetSignalNumberFromName("SIGINT"); - - bool got_async_packet = false; - bool broadcast_sent = false; - - while (state == eStateRunning) - { - if (!got_async_packet) - { - if (log) - log->Printf ("GDBRemoteCommunicationClient::%s () sending continue packet: %s", __FUNCTION__, continue_packet.c_str()); - if (SendPacketNoLock(continue_packet.c_str(), continue_packet.size()) != PacketResult::Success) - state = eStateInvalid; - else - m_interrupt_sent = false; - - if (! broadcast_sent) - { - BroadcastEvent(eBroadcastBitRunPacketSent, NULL); - broadcast_sent = true; - } - - m_private_is_running.SetValue (true, eBroadcastAlways); - } - - got_async_packet = false; - - if (log) - log->Printf ("GDBRemoteCommunicationClient::%s () ReadPacket(%s)", __FUNCTION__, continue_packet.c_str()); - - if (ReadPacket(response, UINT32_MAX, false) == PacketResult::Success) - { - if (response.Empty()) - state = eStateInvalid; - else - { - const char stop_type = response.GetChar(); - if (log) - log->Printf ("GDBRemoteCommunicationClient::%s () got packet: %s", __FUNCTION__, response.GetStringRef().c_str()); - switch (stop_type) - { - case 'T': - case 'S': - { - if (process->GetStopID() == 0) - { - if (process->GetID() == LLDB_INVALID_PROCESS_ID) - { - lldb::pid_t pid = GetCurrentProcessID (); - if (pid != LLDB_INVALID_PROCESS_ID) - process->SetID (pid); - } - process->BuildDynamicRegisterInfo (true); - } - - // Privately notify any internal threads that we have stopped - // in case we wanted to interrupt our process, yet we might - // send a packet and continue without returning control to the - // user. - m_private_is_running.SetValue (false, eBroadcastAlways); - - const uint8_t signo = response.GetHexU8 (UINT8_MAX); - - bool continue_after_async = m_async_signal != -1 || m_async_packet_predicate.GetValue(); - if (continue_after_async || m_interrupt_sent) - { - // We sent an interrupt packet to stop the inferior process - // for an async signal or to send an async packet while running - // but we might have been single stepping and received the - // stop packet for the step instead of for the interrupt packet. - // Typically when an interrupt is sent a SIGINT or SIGSTOP - // is used, so if we get anything else, we need to try and - // get another stop reply packet that may have been sent - // due to sending the interrupt when the target is stopped - // which will just re-send a copy of the last stop reply - // packet. If we don't do this, then the reply for our - // async packet will be the repeat stop reply packet and cause - // a lot of trouble for us! We also have some debugserver - // binaries that would send two stop replies anytime the process - // was interrupted, so we need to also check for an extra - // stop reply packet if we interrupted the process - const bool received_nonstop_signal = signo != sigint_signo && signo != sigstop_signo; - if (m_interrupt_sent || received_nonstop_signal) - { - if (received_nonstop_signal) - continue_after_async = false; - - // Try for a very brief time (0.1s) to get another stop reply - // packet to make sure it doesn't get in the way - StringExtractorGDBRemote extra_stop_reply_packet; - uint32_t timeout_usec = 100000; - if (ReadPacket (extra_stop_reply_packet, timeout_usec, false) == PacketResult::Success) - { - switch (extra_stop_reply_packet.GetChar()) - { - case 'T': - case 'S': - // We did get an extra stop reply, which means - // our interrupt didn't stop the target so we - // shouldn't continue after the async signal - // or packet is sent... - continue_after_async = false; - break; - } - } - } - } - - if (m_async_signal != -1) - { - if (log) - log->Printf ("async: send signo = %s", Host::GetSignalAsCString (m_async_signal)); - - // Save off the async signal we are supposed to send - const int async_signal = m_async_signal; - // Clear the async signal member so we don't end up - // sending the signal multiple times... - m_async_signal = -1; - // Check which signal we stopped with - if (signo == async_signal) - { - if (log) - log->Printf ("async: stopped with signal %s, we are done running", Host::GetSignalAsCString (signo)); - - // We already stopped with a signal that we wanted - // to stop with, so we are done - } - else - { - // We stopped with a different signal that the one - // we wanted to stop with, so now we must resume - // with the signal we want - char signal_packet[32]; - int signal_packet_len = 0; - signal_packet_len = ::snprintf (signal_packet, - sizeof (signal_packet), - "C%2.2x", - async_signal); - - if (log) - log->Printf ("async: stopped with signal %s, resume with %s", - Host::GetSignalAsCString (signo), - Host::GetSignalAsCString (async_signal)); - - // Set the continue packet to resume even if the - // interrupt didn't cause our stop (ignore continue_after_async) - continue_packet.assign(signal_packet, signal_packet_len); - continue; - } - } - else if (m_async_packet_predicate.GetValue()) - { - Log * packet_log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS)); - - // We are supposed to send an asynchronous packet while - // we are running. - m_async_response.Clear(); - if (m_async_packet.empty()) - { - m_async_result = PacketResult::ErrorSendFailed; - if (packet_log) - packet_log->Printf ("async: error: empty async packet"); - - } - else - { - if (packet_log) - packet_log->Printf ("async: sending packet"); - - m_async_result = SendPacketAndWaitForResponse (&m_async_packet[0], - m_async_packet.size(), - m_async_response, - false); - } - // Let the other thread that was trying to send the async - // packet know that the packet has been sent and response is - // ready... - m_async_packet_predicate.SetValue(false, eBroadcastAlways); - - if (packet_log) - packet_log->Printf ("async: sent packet, continue_after_async = %i", continue_after_async); - - // Set the continue packet to resume if our interrupt - // for the async packet did cause the stop - if (continue_after_async) - { - // Reverting this for now as it is causing deadlocks - // in programs (<rdar://problem/11529853>). In the future - // we should check our thread list and "do the right thing" - // for new threads that show up while we stop and run async - // packets. Setting the packet to 'c' to continue all threads - // is the right thing to do 99.99% of the time because if a - // thread was single stepping, and we sent an interrupt, we - // will notice above that we didn't stop due to an interrupt - // but stopped due to stepping and we would _not_ continue. - continue_packet.assign (1, 'c'); - continue; - } - } - // Stop with signal and thread info - state = eStateStopped; - } - break; - - case 'W': - case 'X': - // process exited - state = eStateExited; - break; - - case 'O': - // STDOUT - { - got_async_packet = true; - std::string inferior_stdout; - inferior_stdout.reserve(response.GetBytesLeft () / 2); - - uint8_t ch; - while (response.GetHexU8Ex(ch)) - { - if (ch != 0) - inferior_stdout.append(1, (char)ch); - } - process->AppendSTDOUT (inferior_stdout.c_str(), inferior_stdout.size()); - } - break; - - case 'A': - // Async miscellaneous reply. Right now, only profile data is coming through this channel. - { - got_async_packet = true; - std::string input = response.GetStringRef().substr(1); // '1' to move beyond 'A' - if (m_partial_profile_data.length() > 0) - { - m_partial_profile_data.append(input); - input = m_partial_profile_data; - m_partial_profile_data.clear(); - } - - size_t found, pos = 0, len = input.length(); - while ((found = input.find(end_delimiter, pos)) != std::string::npos) - { - StringExtractorGDBRemote profileDataExtractor(input.substr(pos, found).c_str()); - std::string profile_data = HarmonizeThreadIdsForProfileData(process, profileDataExtractor); - process->BroadcastAsyncProfileData (profile_data); - - pos = found + end_delimiter_len; - } - - if (pos < len) - { - // Last incomplete chunk. - m_partial_profile_data = input.substr(pos); - } - } - break; - - case 'E': - // ERROR - state = eStateInvalid; - break; - - default: - if (log) - log->Printf ("GDBRemoteCommunicationClient::%s () unrecognized async packet", __FUNCTION__); - state = eStateInvalid; - break; - } - } - } - else - { - if (log) - log->Printf ("GDBRemoteCommunicationClient::%s () ReadPacket(...) => false", __FUNCTION__); - state = eStateInvalid; - } - } - if (log) - log->Printf ("GDBRemoteCommunicationClient::%s () => %s", __FUNCTION__, StateAsCString(state)); - response.SetFilePos(0); - m_private_is_running.SetValue (false, eBroadcastAlways); - m_public_is_running.SetValue (false, eBroadcastAlways); - return state; -} - -bool -GDBRemoteCommunicationClient::SendAsyncSignal (int signo) -{ - std::lock_guard<std::recursive_mutex> guard(m_async_mutex); - m_async_signal = signo; - bool timed_out = false; - Mutex::Locker locker; - if (SendInterrupt (locker, 1, timed_out)) - return true; - m_async_signal = -1; - return false; -} - -// This function takes a mutex locker as a parameter in case the GetSequenceMutex -// actually succeeds. If it doesn't succeed in acquiring the sequence mutex -// (the expected result), then it will send the halt packet. If it does succeed -// then the caller that requested the interrupt will want to keep the sequence -// locked down so that no one else can send packets while the caller has control. -// This function usually gets called when we are running and need to stop the -// target. It can also be used when we are running and we need to do something -// else (like read/write memory), so we need to interrupt the running process -// (gdb remote protocol requires this), and do what we need to do, then resume. - -bool -GDBRemoteCommunicationClient::SendInterrupt -( - Mutex::Locker& locker, - uint32_t seconds_to_wait_for_stop, - bool &timed_out -) -{ - timed_out = false; - Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_PROCESS | GDBR_LOG_PACKETS)); - - if (IsRunning()) - { - // Only send an interrupt if our debugserver is running... - if (GetSequenceMutex (locker)) - { - if (log) - log->Printf ("SendInterrupt () - got sequence mutex without having to interrupt"); - } - else - { - // Someone has the mutex locked waiting for a response or for the - // inferior to stop, so send the interrupt on the down low... - char ctrl_c = '\x03'; - ConnectionStatus status = eConnectionStatusSuccess; - size_t bytes_written = Write (&ctrl_c, 1, status, NULL); - if (log) - log->PutCString("send packet: \\x03"); - if (bytes_written > 0) - { - m_interrupt_sent = true; - if (seconds_to_wait_for_stop) - { - TimeValue timeout; - if (seconds_to_wait_for_stop) - { - timeout = TimeValue::Now(); - timeout.OffsetWithSeconds (seconds_to_wait_for_stop); - } - if (m_private_is_running.WaitForValueEqualTo (false, &timeout, &timed_out)) - { - if (log) - log->PutCString ("SendInterrupt () - sent interrupt, private state stopped"); - return true; - } - else - { - if (log) - log->Printf ("SendInterrupt () - sent interrupt, timed out wating for async thread resume"); - } - } - else - { - if (log) - log->Printf ("SendInterrupt () - sent interrupt, not waiting for stop..."); - return true; - } - } - else - { - if (log) - log->Printf ("SendInterrupt () - failed to write interrupt"); - } - return false; - } - } - else - { - if (log) - log->Printf ("SendInterrupt () - not running"); - } - return true; -} - -lldb::pid_t -GDBRemoteCommunicationClient::GetCurrentProcessID (bool allow_lazy) -{ - if (allow_lazy && m_curr_pid_is_valid == eLazyBoolYes) - return m_curr_pid; - - // First try to retrieve the pid via the qProcessInfo request. - GetCurrentProcessInfo (allow_lazy); - if (m_curr_pid_is_valid == eLazyBoolYes) - { - // We really got it. + log->Printf("error: failed to get packet sequence mutex, not sending " + "packets with prefix '%s'", + payload_prefix); + return PacketResult::ErrorNoSequenceLock; + } + + response_string = ""; + std::string payload_prefix_str(payload_prefix); + unsigned int response_size = 0x1000; + if (response_size > GetRemoteMaxPacketSize()) { // May send qSupported packet + response_size = GetRemoteMaxPacketSize(); + } + + for (unsigned int offset = 0; true; offset += response_size) { + StringExtractorGDBRemote this_response; + // Construct payload + char sizeDescriptor[128]; + snprintf(sizeDescriptor, sizeof(sizeDescriptor), "%x,%x", offset, + response_size); + PacketResult result = SendPacketAndWaitForResponseNoLock( + payload_prefix_str + sizeDescriptor, this_response); + if (result != PacketResult::Success) + return result; + + const std::string &this_string = this_response.GetStringRef(); + + // Check for m or l as first character; l seems to mean this is the last + // chunk + char first_char = *this_string.c_str(); + if (first_char != 'm' && first_char != 'l') { + return PacketResult::ErrorReplyInvalid; + } + // Concatenate the result so far (skipping 'm' or 'l') + response_string.append(this_string, 1, std::string::npos); + if (first_char == 'l') + // We're done + return PacketResult::Success; + } +} + +lldb::pid_t GDBRemoteCommunicationClient::GetCurrentProcessID(bool allow_lazy) { + if (allow_lazy && m_curr_pid_is_valid == eLazyBoolYes) + return m_curr_pid; + + // First try to retrieve the pid via the qProcessInfo request. + GetCurrentProcessInfo(allow_lazy); + if (m_curr_pid_is_valid == eLazyBoolYes) { + // We really got it. + return m_curr_pid; + } else { + // If we don't get a response for qProcessInfo, check if $qC gives us a + // result. + // $qC only returns a real process id on older debugserver and lldb-platform + // stubs. + // The gdb remote protocol documents $qC as returning the thread id, which + // newer + // debugserver and lldb-gdbserver stubs return correctly. + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse("qC", response, false) == + PacketResult::Success) { + if (response.GetChar() == 'Q') { + if (response.GetChar() == 'C') { + m_curr_pid = response.GetHexMaxU32(false, LLDB_INVALID_PROCESS_ID); + if (m_curr_pid != LLDB_INVALID_PROCESS_ID) { + m_curr_pid_is_valid = eLazyBoolYes; + return m_curr_pid; + } + } + } + } + + // If we don't get a response for $qC, check if $qfThreadID gives us a + // result. + if (m_curr_pid == LLDB_INVALID_PROCESS_ID) { + std::vector<lldb::tid_t> thread_ids; + bool sequence_mutex_unavailable; + size_t size; + size = GetCurrentThreadIDs(thread_ids, sequence_mutex_unavailable); + if (size && sequence_mutex_unavailable == false) { + m_curr_pid = thread_ids.front(); + m_curr_pid_is_valid = eLazyBoolYes; return m_curr_pid; + } + } + } + + return LLDB_INVALID_PROCESS_ID; +} + +bool GDBRemoteCommunicationClient::GetLaunchSuccess(std::string &error_str) { + error_str.clear(); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse("qLaunchSuccess", response, false) == + PacketResult::Success) { + if (response.IsOKResponse()) + return true; + if (response.GetChar() == 'E') { + // A string the describes what failed when launching... + error_str = response.GetStringRef().substr(1); + } else { + error_str.assign("unknown error occurred launching process"); + } + } else { + error_str.assign("timed out waiting for app to launch"); + } + return false; +} + +int GDBRemoteCommunicationClient::SendArgumentsPacket( + const ProcessLaunchInfo &launch_info) { + // Since we don't get the send argv0 separate from the executable path, we + // need to + // make sure to use the actual executable path found in the launch_info... + std::vector<const char *> argv; + FileSpec exe_file = launch_info.GetExecutableFile(); + std::string exe_path; + const char *arg = NULL; + const Args &launch_args = launch_info.GetArguments(); + if (exe_file) + exe_path = exe_file.GetPath(false); + else { + arg = launch_args.GetArgumentAtIndex(0); + if (arg) + exe_path = arg; + } + if (!exe_path.empty()) { + argv.push_back(exe_path.c_str()); + for (uint32_t i = 1; (arg = launch_args.GetArgumentAtIndex(i)) != NULL; + ++i) { + if (arg) + argv.push_back(arg); + } + } + if (!argv.empty()) { + StreamString packet; + packet.PutChar('A'); + for (size_t i = 0, n = argv.size(); i < n; ++i) { + arg = argv[i]; + const int arg_len = strlen(arg); + if (i > 0) + packet.PutChar(','); + packet.Printf("%i,%i,", arg_len * 2, (int)i); + packet.PutBytesAsRawHex8(arg, arg_len); } - else - { - // If we don't get a response for qProcessInfo, check if $qC gives us a result. - // $qC only returns a real process id on older debugserver and lldb-platform stubs. - // The gdb remote protocol documents $qC as returning the thread id, which newer - // debugserver and lldb-gdbserver stubs return correctly. - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("qC", strlen("qC"), response, false) == PacketResult::Success) - { - if (response.GetChar() == 'Q') - { - if (response.GetChar() == 'C') - { - m_curr_pid = response.GetHexMaxU32 (false, LLDB_INVALID_PROCESS_ID); - if (m_curr_pid != LLDB_INVALID_PROCESS_ID) - { - m_curr_pid_is_valid = eLazyBoolYes; - return m_curr_pid; - } - } - } - } - - // If we don't get a response for $qC, check if $qfThreadID gives us a result. - if (m_curr_pid == LLDB_INVALID_PROCESS_ID) - { - std::vector<lldb::tid_t> thread_ids; - bool sequence_mutex_unavailable; - size_t size; - size = GetCurrentThreadIDs (thread_ids, sequence_mutex_unavailable); - if (size && sequence_mutex_unavailable == false) - { - m_curr_pid = thread_ids.front(); - m_curr_pid_is_valid = eLazyBoolYes; - return m_curr_pid; - } - } - } - - return LLDB_INVALID_PROCESS_ID; -} -bool -GDBRemoteCommunicationClient::GetLaunchSuccess (std::string &error_str) -{ - error_str.clear(); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("qLaunchSuccess", strlen("qLaunchSuccess"), response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - return true; - if (response.GetChar() == 'E') - { - // A string the describes what failed when launching... - error_str = response.GetStringRef().substr(1); - } - else - { - error_str.assign ("unknown error occurred launching process"); - } - } - else - { - error_str.assign ("timed out waiting for app to launch"); + if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == + PacketResult::Success) { + if (response.IsOKResponse()) + return 0; + uint8_t error = response.GetError(); + if (error) + return error; } - return false; + } + return -1; } -int -GDBRemoteCommunicationClient::SendArgumentsPacket (const ProcessLaunchInfo &launch_info) -{ - // Since we don't get the send argv0 separate from the executable path, we need to - // make sure to use the actual executable path found in the launch_info... - std::vector<const char *> argv; - FileSpec exe_file = launch_info.GetExecutableFile(); - std::string exe_path; - const char *arg = NULL; - const Args &launch_args = launch_info.GetArguments(); - if (exe_file) - exe_path = exe_file.GetPath(false); - else - { - arg = launch_args.GetArgumentAtIndex(0); - if (arg) - exe_path = arg; - } - if (!exe_path.empty()) - { - argv.push_back(exe_path.c_str()); - for (uint32_t i=1; (arg = launch_args.GetArgumentAtIndex(i)) != NULL; ++i) - { - if (arg) - argv.push_back(arg); +int GDBRemoteCommunicationClient::SendEnvironmentPacket( + char const *name_equal_value) { + 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) { + if (isprint(*p)) { + switch (*p) { + case '$': + case '#': + case '*': + case '}': + send_hex_encoding = true; + break; + default: + break; } + } else { + // We have non printable characters, lets hex encode this... + send_hex_encoding = true; + } } - if (!argv.empty()) - { - StreamString packet; - packet.PutChar('A'); - for (size_t i = 0, n = argv.size(); i < n; ++i) - { - arg = argv[i]; - const int arg_len = strlen(arg); - if (i > 0) - packet.PutChar(','); - packet.Printf("%i,%i,", arg_len * 2, (int)i); - packet.PutBytesAsRawHex8 (arg, arg_len); - } - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - return 0; - uint8_t error = response.GetError(); - if (error) - return error; + StringExtractorGDBRemote response; + if (send_hex_encoding) { + if (m_supports_QEnvironmentHexEncoded) { + packet.PutCString("QEnvironmentHexEncoded:"); + packet.PutBytesAsRawHex8(name_equal_value, strlen(name_equal_value)); + if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == + PacketResult::Success) { + if (response.IsOKResponse()) + return 0; + uint8_t error = response.GetError(); + if (error) + return error; + if (response.IsUnsupportedResponse()) + m_supports_QEnvironmentHexEncoded = false; } - } - return -1; -} + } -int -GDBRemoteCommunicationClient::SendEnvironmentPacket (char const *name_equal_value) -{ - 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) - { - if (isprint(*p)) - { - switch (*p) - { - case '$': - case '#': - case '*': - case '}': - send_hex_encoding = true; - break; - default: - break; - } - } - else - { - // We have non printable characters, lets hex encode this... - send_hex_encoding = true; - } - } - - StringExtractorGDBRemote response; - if (send_hex_encoding) - { - if (m_supports_QEnvironmentHexEncoded) - { - packet.PutCString("QEnvironmentHexEncoded:"); - packet.PutBytesAsRawHex8 (name_equal_value, strlen(name_equal_value)); - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - return 0; - uint8_t error = response.GetError(); - if (error) - return error; - if (response.IsUnsupportedResponse()) - m_supports_QEnvironmentHexEncoded = false; - } - } - - } - else if (m_supports_QEnvironment) - { - packet.Printf("QEnvironment:%s", name_equal_value); - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - return 0; - uint8_t error = response.GetError(); - if (error) - return error; - if (response.IsUnsupportedResponse()) - m_supports_QEnvironment = false; - } - } + } else if (m_supports_QEnvironment) { + packet.Printf("QEnvironment:%s", name_equal_value); + if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == + PacketResult::Success) { + if (response.IsOKResponse()) + return 0; + uint8_t error = response.GetError(); + if (error) + return error; + if (response.IsUnsupportedResponse()) + m_supports_QEnvironment = false; + } } - return -1; + } + return -1; } -int -GDBRemoteCommunicationClient::SendLaunchArchPacket (char const *arch) -{ - if (arch && arch[0]) - { - StreamString packet; - packet.Printf("QLaunchArch:%s", arch); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - return 0; - uint8_t error = response.GetError(); - if (error) - return error; - } +int GDBRemoteCommunicationClient::SendLaunchArchPacket(char const *arch) { + if (arch && arch[0]) { + StreamString packet; + packet.Printf("QLaunchArch:%s", arch); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == + PacketResult::Success) { + if (response.IsOKResponse()) + return 0; + uint8_t error = response.GetError(); + if (error) + return error; } - return -1; + } + return -1; } -int -GDBRemoteCommunicationClient::SendLaunchEventDataPacket (char const *data, bool *was_supported) -{ - if (data && *data != '\0') - { - StreamString packet; - packet.Printf("QSetProcessEvent:%s", data); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - { - if (was_supported) - *was_supported = true; - return 0; - } - else if (response.IsUnsupportedResponse()) - { - if (was_supported) - *was_supported = false; - return -1; - } - else - { - uint8_t error = response.GetError(); - if (was_supported) - *was_supported = true; - if (error) - return error; - } - } +int GDBRemoteCommunicationClient::SendLaunchEventDataPacket( + char const *data, bool *was_supported) { + if (data && *data != '\0') { + StreamString packet; + packet.Printf("QSetProcessEvent:%s", data); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == + PacketResult::Success) { + if (response.IsOKResponse()) { + if (was_supported) + *was_supported = true; + return 0; + } else if (response.IsUnsupportedResponse()) { + if (was_supported) + *was_supported = false; + return -1; + } else { + uint8_t error = response.GetError(); + if (was_supported) + *was_supported = true; + if (error) + return error; + } } - return -1; + } + return -1; } -bool -GDBRemoteCommunicationClient::GetOSVersion (uint32_t &major, - uint32_t &minor, - uint32_t &update) -{ - if (GetHostInfo ()) - { - if (m_os_version_major != UINT32_MAX) - { - major = m_os_version_major; - minor = m_os_version_minor; - update = m_os_version_update; - return true; - } +bool GDBRemoteCommunicationClient::GetOSVersion(uint32_t &major, + uint32_t &minor, + uint32_t &update) { + if (GetHostInfo()) { + if (m_os_version_major != UINT32_MAX) { + major = m_os_version_major; + minor = m_os_version_minor; + update = m_os_version_update; + return true; } - return false; + } + return false; } -bool -GDBRemoteCommunicationClient::GetOSBuildString (std::string &s) -{ - if (GetHostInfo ()) - { - if (!m_os_build.empty()) - { - s = m_os_build; - return true; - } +bool GDBRemoteCommunicationClient::GetOSBuildString(std::string &s) { + if (GetHostInfo()) { + if (!m_os_build.empty()) { + s = m_os_build; + return true; } - s.clear(); - return false; + } + s.clear(); + return false; } - -bool -GDBRemoteCommunicationClient::GetOSKernelDescription (std::string &s) -{ - if (GetHostInfo ()) - { - if (!m_os_kernel.empty()) - { - s = m_os_kernel; - return true; - } +bool GDBRemoteCommunicationClient::GetOSKernelDescription(std::string &s) { + if (GetHostInfo()) { + if (!m_os_kernel.empty()) { + s = m_os_kernel; + return true; } - s.clear(); - return false; + } + s.clear(); + return false; } -bool -GDBRemoteCommunicationClient::GetHostname (std::string &s) -{ - if (GetHostInfo ()) - { - if (!m_hostname.empty()) - { - s = m_hostname; - return true; - } +bool GDBRemoteCommunicationClient::GetHostname(std::string &s) { + if (GetHostInfo()) { + if (!m_hostname.empty()) { + s = m_hostname; + return true; } - s.clear(); - return false; + } + s.clear(); + return false; } -ArchSpec -GDBRemoteCommunicationClient::GetSystemArchitecture () -{ - if (GetHostInfo ()) - return m_host_arch; - return ArchSpec(); +ArchSpec GDBRemoteCommunicationClient::GetSystemArchitecture() { + if (GetHostInfo()) + return m_host_arch; + return ArchSpec(); } const lldb_private::ArchSpec & -GDBRemoteCommunicationClient::GetProcessArchitecture () -{ - if (m_qProcessInfo_is_valid == eLazyBoolCalculate) - GetCurrentProcessInfo (); - return m_process_arch; +GDBRemoteCommunicationClient::GetProcessArchitecture() { + if (m_qProcessInfo_is_valid == eLazyBoolCalculate) + GetCurrentProcessInfo(); + return m_process_arch; } -bool -GDBRemoteCommunicationClient::GetGDBServerVersion() -{ - if (m_qGDBServerVersion_is_valid == eLazyBoolCalculate) - { - m_gdb_server_name.clear(); - m_gdb_server_version = 0; - m_qGDBServerVersion_is_valid = eLazyBoolNo; - - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse ("qGDBServerVersion", response, false) == PacketResult::Success) - { - if (response.IsNormalResponse()) - { - std::string name; - std::string value; - bool success = false; - while (response.GetNameColonValue(name, value)) - { - if (name.compare("name") == 0) - { - success = true; - m_gdb_server_name.swap(value); - } - else if (name.compare("version") == 0) - { - size_t dot_pos = value.find('.'); - if (dot_pos != std::string::npos) - value[dot_pos] = '\0'; - const uint32_t version = StringConvert::ToUInt32(value.c_str(), UINT32_MAX, 0); - if (version != UINT32_MAX) - { - success = true; - m_gdb_server_version = version; - } - } - } - if (success) - m_qGDBServerVersion_is_valid = eLazyBoolYes; - } - } - } - return m_qGDBServerVersion_is_valid == eLazyBoolYes; -} +bool GDBRemoteCommunicationClient::GetGDBServerVersion() { + if (m_qGDBServerVersion_is_valid == eLazyBoolCalculate) { + m_gdb_server_name.clear(); + m_gdb_server_version = 0; + m_qGDBServerVersion_is_valid = eLazyBoolNo; -void -GDBRemoteCommunicationClient::MaybeEnableCompression (std::vector<std::string> supported_compressions) -{ - CompressionType avail_type = CompressionType::None; - std::string avail_name; - -#if defined (HAVE_LIBCOMPRESSION) - // libcompression is weak linked so test if compression_decode_buffer() is available - if (compression_decode_buffer != NULL && avail_type == CompressionType::None) - { - for (auto compression : supported_compressions) - { - if (compression == "lzfse") - { - avail_type = CompressionType::LZFSE; - avail_name = compression; - break; - } - } - } + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse("qGDBServerVersion", response, false) == + PacketResult::Success) { + if (response.IsNormalResponse()) { + llvm::StringRef name, value; + bool success = false; + while (response.GetNameColonValue(name, value)) { + if (name.equals("name")) { + success = true; + m_gdb_server_name = value; + } else if (name.equals("version")) { + llvm::StringRef major, minor; + std::tie(major, minor) = value.split('.'); + if (!major.getAsInteger(0, m_gdb_server_version)) + success = true; + } + } + if (success) + m_qGDBServerVersion_is_valid = eLazyBoolYes; + } + } + } + return m_qGDBServerVersion_is_valid == eLazyBoolYes; +} + +void GDBRemoteCommunicationClient::MaybeEnableCompression( + std::vector<std::string> supported_compressions) { + CompressionType avail_type = CompressionType::None; + std::string avail_name; + +#if defined(HAVE_LIBCOMPRESSION) + // libcompression is weak linked so test if compression_decode_buffer() is + // available + if (compression_decode_buffer != NULL && + avail_type == CompressionType::None) { + for (auto compression : supported_compressions) { + if (compression == "lzfse") { + avail_type = CompressionType::LZFSE; + avail_name = compression; + break; + } + } + } #endif -#if defined (HAVE_LIBCOMPRESSION) - // libcompression is weak linked so test if compression_decode_buffer() is available - if (compression_decode_buffer != NULL && avail_type == CompressionType::None) - { - for (auto compression : supported_compressions) - { - if (compression == "zlib-deflate") - { - avail_type = CompressionType::ZlibDeflate; - avail_name = compression; - break; - } - } - } +#if defined(HAVE_LIBCOMPRESSION) + // libcompression is weak linked so test if compression_decode_buffer() is + // available + if (compression_decode_buffer != NULL && + avail_type == CompressionType::None) { + for (auto compression : supported_compressions) { + if (compression == "zlib-deflate") { + avail_type = CompressionType::ZlibDeflate; + avail_name = compression; + break; + } + } + } #endif -#if defined (HAVE_LIBZ) - if (avail_type == CompressionType::None) - { - for (auto compression : supported_compressions) - { - if (compression == "zlib-deflate") - { - avail_type = CompressionType::ZlibDeflate; - avail_name = compression; - break; - } - } +#if defined(HAVE_LIBZ) + if (avail_type == CompressionType::None) { + for (auto compression : supported_compressions) { + if (compression == "zlib-deflate") { + avail_type = CompressionType::ZlibDeflate; + avail_name = compression; + break; + } } + } #endif -#if defined (HAVE_LIBCOMPRESSION) - // libcompression is weak linked so test if compression_decode_buffer() is available - if (compression_decode_buffer != NULL && avail_type == CompressionType::None) - { - for (auto compression : supported_compressions) - { - if (compression == "lz4") - { - avail_type = CompressionType::LZ4; - avail_name = compression; - break; - } - } - } +#if defined(HAVE_LIBCOMPRESSION) + // libcompression is weak linked so test if compression_decode_buffer() is + // available + if (compression_decode_buffer != NULL && + avail_type == CompressionType::None) { + for (auto compression : supported_compressions) { + if (compression == "lz4") { + avail_type = CompressionType::LZ4; + avail_name = compression; + break; + } + } + } #endif -#if defined (HAVE_LIBCOMPRESSION) - // libcompression is weak linked so test if compression_decode_buffer() is available - if (compression_decode_buffer != NULL && avail_type == CompressionType::None) - { - for (auto compression : supported_compressions) - { - if (compression == "lzma") - { - avail_type = CompressionType::LZMA; - avail_name = compression; - break; - } - } - } +#if defined(HAVE_LIBCOMPRESSION) + // libcompression is weak linked so test if compression_decode_buffer() is + // available + if (compression_decode_buffer != NULL && + avail_type == CompressionType::None) { + for (auto compression : supported_compressions) { + if (compression == "lzma") { + avail_type = CompressionType::LZMA; + avail_name = compression; + break; + } + } + } #endif - if (avail_type != CompressionType::None) - { - StringExtractorGDBRemote response; - std::string packet = "QEnableCompression:type:" + avail_name + ";"; - if (SendPacketAndWaitForResponse (packet.c_str(), response, false) != PacketResult::Success) - return; - - if (response.IsOKResponse()) - { - m_compression_type = avail_type; - } - } -} + if (avail_type != CompressionType::None) { + StringExtractorGDBRemote response; + std::string packet = "QEnableCompression:type:" + avail_name + ";"; + if (SendPacketAndWaitForResponse(packet, response, false) != + PacketResult::Success) + return; -const char * -GDBRemoteCommunicationClient::GetGDBServerProgramName() -{ - if (GetGDBServerVersion()) - { - if (!m_gdb_server_name.empty()) - return m_gdb_server_name.c_str(); + if (response.IsOKResponse()) { + m_compression_type = avail_type; } - return NULL; + } } -uint32_t -GDBRemoteCommunicationClient::GetGDBServerProgramVersion() -{ - if (GetGDBServerVersion()) - return m_gdb_server_version; - return 0; +const char *GDBRemoteCommunicationClient::GetGDBServerProgramName() { + if (GetGDBServerVersion()) { + if (!m_gdb_server_name.empty()) + return m_gdb_server_name.c_str(); + } + return NULL; } -bool -GDBRemoteCommunicationClient::GetDefaultThreadId (lldb::tid_t &tid) -{ - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("qC",response,false) != PacketResult::Success) - return false; - - if (!response.IsNormalResponse()) - return false; - - if (response.GetChar() == 'Q' && response.GetChar() == 'C') - tid = response.GetHexMaxU32(true, -1); - - return true; +uint32_t GDBRemoteCommunicationClient::GetGDBServerProgramVersion() { + if (GetGDBServerVersion()) + return m_gdb_server_version; + return 0; } -bool -GDBRemoteCommunicationClient::GetHostInfo (bool force) -{ - Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_PROCESS)); - - if (force || m_qHostInfo_is_valid == eLazyBoolCalculate) - { - m_qHostInfo_is_valid = eLazyBoolNo; - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse ("qHostInfo", response, false) == PacketResult::Success) - { - if (response.IsNormalResponse()) - { - std::string name; - std::string value; - uint32_t cpu = LLDB_INVALID_CPUTYPE; - uint32_t sub = 0; - std::string arch_name; - std::string os_name; - std::string vendor_name; - std::string triple; - std::string distribution_id; - uint32_t pointer_byte_size = 0; - StringExtractor extractor; - ByteOrder byte_order = eByteOrderInvalid; - uint32_t num_keys_decoded = 0; - while (response.GetNameColonValue(name, value)) - { - if (name.compare("cputype") == 0) - { - // exception type in big endian hex - cpu = StringConvert::ToUInt32 (value.c_str(), LLDB_INVALID_CPUTYPE, 0); - if (cpu != LLDB_INVALID_CPUTYPE) - ++num_keys_decoded; - } - else if (name.compare("cpusubtype") == 0) - { - // exception count in big endian hex - sub = StringConvert::ToUInt32 (value.c_str(), 0, 0); - if (sub != 0) - ++num_keys_decoded; - } - else if (name.compare("arch") == 0) - { - arch_name.swap (value); - ++num_keys_decoded; - } - else if (name.compare("triple") == 0) - { - extractor.GetStringRef ().swap (value); - extractor.SetFilePos(0); - extractor.GetHexByteString (triple); - ++num_keys_decoded; - } - else if (name.compare ("distribution_id") == 0) - { - extractor.GetStringRef ().swap (value); - extractor.SetFilePos (0); - extractor.GetHexByteString (distribution_id); - ++num_keys_decoded; - } - else if (name.compare("os_build") == 0) - { - extractor.GetStringRef().swap(value); - extractor.SetFilePos(0); - extractor.GetHexByteString (m_os_build); - ++num_keys_decoded; - } - else if (name.compare("hostname") == 0) - { - extractor.GetStringRef().swap(value); - extractor.SetFilePos(0); - extractor.GetHexByteString (m_hostname); - ++num_keys_decoded; - } - else if (name.compare("os_kernel") == 0) - { - extractor.GetStringRef().swap(value); - extractor.SetFilePos(0); - extractor.GetHexByteString (m_os_kernel); - ++num_keys_decoded; - } - else if (name.compare("ostype") == 0) - { - os_name.swap (value); - ++num_keys_decoded; - } - else if (name.compare("vendor") == 0) - { - vendor_name.swap(value); - ++num_keys_decoded; - } - else if (name.compare("endian") == 0) - { - ++num_keys_decoded; - if (value.compare("little") == 0) - byte_order = eByteOrderLittle; - else if (value.compare("big") == 0) - byte_order = eByteOrderBig; - else if (value.compare("pdp") == 0) - byte_order = eByteOrderPDP; - else - --num_keys_decoded; - } - else if (name.compare("ptrsize") == 0) - { - pointer_byte_size = StringConvert::ToUInt32 (value.c_str(), 0, 0); - if (pointer_byte_size != 0) - ++num_keys_decoded; - } - else if ((name.compare("os_version") == 0) || - (name.compare("version") == 0)) // Older debugserver binaries used the "version" key instead of "os_version"... - { - Args::StringToVersion (value.c_str(), - m_os_version_major, - m_os_version_minor, - m_os_version_update); - if (m_os_version_major != UINT32_MAX) - ++num_keys_decoded; - } - else if (name.compare("watchpoint_exceptions_received") == 0) - { - ++num_keys_decoded; - if (strcmp(value.c_str(),"before") == 0) - m_watchpoints_trigger_after_instruction = eLazyBoolNo; - else if (strcmp(value.c_str(),"after") == 0) - m_watchpoints_trigger_after_instruction = eLazyBoolYes; - else - --num_keys_decoded; - } - else if (name.compare("default_packet_timeout") == 0) - { - m_default_packet_timeout = StringConvert::ToUInt32(value.c_str(), 0); - if (m_default_packet_timeout > 0) - { - SetPacketTimeout(m_default_packet_timeout); - ++num_keys_decoded; - } - } +bool GDBRemoteCommunicationClient::GetDefaultThreadId(lldb::tid_t &tid) { + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse("qC", response, false) != + PacketResult::Success) + return false; - } - - if (num_keys_decoded > 0) - m_qHostInfo_is_valid = eLazyBoolYes; - - if (triple.empty()) - { - if (arch_name.empty()) - { - if (cpu != LLDB_INVALID_CPUTYPE) - { - m_host_arch.SetArchitecture (eArchTypeMachO, cpu, sub); - if (pointer_byte_size) - { - assert (pointer_byte_size == m_host_arch.GetAddressByteSize()); - } - if (byte_order != eByteOrderInvalid) - { - assert (byte_order == m_host_arch.GetByteOrder()); - } - - if (!vendor_name.empty()) - m_host_arch.GetTriple().setVendorName (llvm::StringRef (vendor_name)); - if (!os_name.empty()) - m_host_arch.GetTriple().setOSName (llvm::StringRef (os_name)); - - } - } - else - { - std::string triple; - triple += arch_name; - if (!vendor_name.empty() || !os_name.empty()) - { - triple += '-'; - if (vendor_name.empty()) - triple += "unknown"; - else - triple += vendor_name; - triple += '-'; - if (os_name.empty()) - triple += "unknown"; - else - triple += os_name; - } - m_host_arch.SetTriple (triple.c_str()); - - llvm::Triple &host_triple = m_host_arch.GetTriple(); - if (host_triple.getVendor() == llvm::Triple::Apple && host_triple.getOS() == llvm::Triple::Darwin) - { - switch (m_host_arch.GetMachine()) - { - case llvm::Triple::aarch64: - case llvm::Triple::arm: - case llvm::Triple::thumb: - host_triple.setOS(llvm::Triple::IOS); - break; - default: - host_triple.setOS(llvm::Triple::MacOSX); - break; - } - } - if (pointer_byte_size) - { - assert (pointer_byte_size == m_host_arch.GetAddressByteSize()); - } - if (byte_order != eByteOrderInvalid) - { - assert (byte_order == m_host_arch.GetByteOrder()); - } - - } - } - else - { - m_host_arch.SetTriple (triple.c_str()); - if (pointer_byte_size) - { - assert (pointer_byte_size == m_host_arch.GetAddressByteSize()); - } - if (byte_order != eByteOrderInvalid) - { - assert (byte_order == m_host_arch.GetByteOrder()); - } + if (!response.IsNormalResponse()) + return false; - if (log) - log->Printf ("GDBRemoteCommunicationClient::%s parsed host architecture as %s, triple as %s from triple text %s", __FUNCTION__, m_host_arch.GetArchitectureName () ? m_host_arch.GetArchitectureName () : "<null-arch-name>", m_host_arch.GetTriple ().getTriple ().c_str(), triple.c_str ()); - } - if (!distribution_id.empty ()) - m_host_arch.SetDistributionId (distribution_id.c_str ()); - } - } - } - return m_qHostInfo_is_valid == eLazyBoolYes; -} + if (response.GetChar() == 'Q' && response.GetChar() == 'C') + tid = response.GetHexMaxU32(true, -1); -int -GDBRemoteCommunicationClient::SendAttach -( - lldb::pid_t pid, - StringExtractorGDBRemote& response -) -{ - if (pid != LLDB_INVALID_PROCESS_ID) - { - char packet[64]; - const int packet_len = ::snprintf (packet, sizeof(packet), "vAttach;%" PRIx64, pid); - assert (packet_len < (int)sizeof(packet)); - if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) - { - if (response.IsErrorResponse()) - return response.GetError(); - return 0; - } - } - return -1; + return true; } -int -GDBRemoteCommunicationClient::SendStdinNotification (const char* data, size_t data_len) -{ - StreamString packet; - packet.PutCString("I"); - packet.PutBytesAsRawHex8(data, data_len); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) - { - return 0; - } - return response.GetError(); +bool GDBRemoteCommunicationClient::GetHostInfo(bool force) { + Log *log(ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(GDBR_LOG_PROCESS)); + if (force || m_qHostInfo_is_valid == eLazyBoolCalculate) { + m_qHostInfo_is_valid = eLazyBoolNo; + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse("qHostInfo", response, false) == + PacketResult::Success) { + if (response.IsNormalResponse()) { + llvm::StringRef name; + llvm::StringRef value; + uint32_t cpu = LLDB_INVALID_CPUTYPE; + uint32_t sub = 0; + std::string arch_name; + std::string os_name; + std::string vendor_name; + std::string triple; + std::string distribution_id; + uint32_t pointer_byte_size = 0; + ByteOrder byte_order = eByteOrderInvalid; + uint32_t num_keys_decoded = 0; + while (response.GetNameColonValue(name, value)) { + if (name.equals("cputype")) { + // exception type in big endian hex + if (!value.getAsInteger(0, cpu)) + ++num_keys_decoded; + } else if (name.equals("cpusubtype")) { + // exception count in big endian hex + if (!value.getAsInteger(0, sub)) + ++num_keys_decoded; + } else if (name.equals("arch")) { + arch_name = value; + ++num_keys_decoded; + } else if (name.equals("triple")) { + StringExtractor extractor(value); + extractor.GetHexByteString(triple); + ++num_keys_decoded; + } else if (name.equals("distribution_id")) { + StringExtractor extractor(value); + extractor.GetHexByteString(distribution_id); + ++num_keys_decoded; + } else if (name.equals("os_build")) { + StringExtractor extractor(value); + extractor.GetHexByteString(m_os_build); + ++num_keys_decoded; + } else if (name.equals("hostname")) { + StringExtractor extractor(value); + extractor.GetHexByteString(m_hostname); + ++num_keys_decoded; + } else if (name.equals("os_kernel")) { + StringExtractor extractor(value); + extractor.GetHexByteString(m_os_kernel); + ++num_keys_decoded; + } else if (name.equals("ostype")) { + os_name = value; + ++num_keys_decoded; + } else if (name.equals("vendor")) { + vendor_name = value; + ++num_keys_decoded; + } else if (name.equals("endian")) { + byte_order = llvm::StringSwitch<lldb::ByteOrder>(value) + .Case("little", eByteOrderLittle) + .Case("big", eByteOrderBig) + .Case("pdp", eByteOrderPDP) + .Default(eByteOrderInvalid); + if (byte_order != eByteOrderInvalid) + ++num_keys_decoded; + } else if (name.equals("ptrsize")) { + if (!value.getAsInteger(0, pointer_byte_size)) + ++num_keys_decoded; + } else if (name.equals("os_version") || + name.equals( + "version")) // Older debugserver binaries used the + // "version" key instead of + // "os_version"... + { + Args::StringToVersion(value, m_os_version_major, m_os_version_minor, + m_os_version_update); + if (m_os_version_major != UINT32_MAX) + ++num_keys_decoded; + } else if (name.equals("watchpoint_exceptions_received")) { + m_watchpoints_trigger_after_instruction = + llvm::StringSwitch<LazyBool>(value) + .Case("before", eLazyBoolNo) + .Case("after", eLazyBoolYes) + .Default(eLazyBoolCalculate); + if (m_watchpoints_trigger_after_instruction != eLazyBoolCalculate) + ++num_keys_decoded; + } else if (name.equals("default_packet_timeout")) { + uint32_t timeout_seconds; + if (!value.getAsInteger(0, timeout_seconds)) { + m_default_packet_timeout = seconds(timeout_seconds); + SetPacketTimeout(m_default_packet_timeout); + ++num_keys_decoded; + } + } + } + + if (num_keys_decoded > 0) + m_qHostInfo_is_valid = eLazyBoolYes; + + if (triple.empty()) { + if (arch_name.empty()) { + if (cpu != LLDB_INVALID_CPUTYPE) { + m_host_arch.SetArchitecture(eArchTypeMachO, cpu, sub); + if (pointer_byte_size) { + assert(pointer_byte_size == m_host_arch.GetAddressByteSize()); + } + if (byte_order != eByteOrderInvalid) { + assert(byte_order == m_host_arch.GetByteOrder()); + } + + if (!vendor_name.empty()) + m_host_arch.GetTriple().setVendorName( + llvm::StringRef(vendor_name)); + if (!os_name.empty()) + m_host_arch.GetTriple().setOSName(llvm::StringRef(os_name)); + } + } else { + std::string triple; + triple += arch_name; + if (!vendor_name.empty() || !os_name.empty()) { + triple += '-'; + if (vendor_name.empty()) + triple += "unknown"; + else + triple += vendor_name; + triple += '-'; + if (os_name.empty()) + triple += "unknown"; + else + triple += os_name; + } + m_host_arch.SetTriple(triple.c_str()); + + llvm::Triple &host_triple = m_host_arch.GetTriple(); + if (host_triple.getVendor() == llvm::Triple::Apple && + host_triple.getOS() == llvm::Triple::Darwin) { + switch (m_host_arch.GetMachine()) { + case llvm::Triple::aarch64: + case llvm::Triple::arm: + case llvm::Triple::thumb: + host_triple.setOS(llvm::Triple::IOS); + break; + default: + host_triple.setOS(llvm::Triple::MacOSX); + break; + } + } + if (pointer_byte_size) { + assert(pointer_byte_size == m_host_arch.GetAddressByteSize()); + } + if (byte_order != eByteOrderInvalid) { + assert(byte_order == m_host_arch.GetByteOrder()); + } + } + } else { + m_host_arch.SetTriple(triple.c_str()); + if (pointer_byte_size) { + assert(pointer_byte_size == m_host_arch.GetAddressByteSize()); + } + if (byte_order != eByteOrderInvalid) { + assert(byte_order == m_host_arch.GetByteOrder()); + } + + if (log) + log->Printf("GDBRemoteCommunicationClient::%s parsed host " + "architecture as %s, triple as %s from triple text %s", + __FUNCTION__, m_host_arch.GetArchitectureName() + ? m_host_arch.GetArchitectureName() + : "<null-arch-name>", + m_host_arch.GetTriple().getTriple().c_str(), + triple.c_str()); + } + if (!distribution_id.empty()) + m_host_arch.SetDistributionId(distribution_id.c_str()); + } + } + } + return m_qHostInfo_is_valid == eLazyBoolYes; +} + +int GDBRemoteCommunicationClient::SendAttach( + lldb::pid_t pid, StringExtractorGDBRemote &response) { + if (pid != LLDB_INVALID_PROCESS_ID) { + char packet[64]; + const int packet_len = + ::snprintf(packet, sizeof(packet), "vAttach;%" PRIx64, pid); + UNUSED_IF_ASSERT_DISABLED(packet_len); + assert(packet_len < (int)sizeof(packet)); + if (SendPacketAndWaitForResponse(packet, response, false) == + PacketResult::Success) { + if (response.IsErrorResponse()) + return response.GetError(); + return 0; + } + } + return -1; +} + +int GDBRemoteCommunicationClient::SendStdinNotification(const char *data, + size_t data_len) { + StreamString packet; + packet.PutCString("I"); + packet.PutBytesAsRawHex8(data, data_len); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == + PacketResult::Success) { + return 0; + } + return response.GetError(); } const lldb_private::ArchSpec & -GDBRemoteCommunicationClient::GetHostArchitecture () -{ - if (m_qHostInfo_is_valid == eLazyBoolCalculate) - GetHostInfo (); - return m_host_arch; +GDBRemoteCommunicationClient::GetHostArchitecture() { + if (m_qHostInfo_is_valid == eLazyBoolCalculate) + GetHostInfo(); + return m_host_arch; } -uint32_t -GDBRemoteCommunicationClient::GetHostDefaultPacketTimeout () -{ - if (m_qHostInfo_is_valid == eLazyBoolCalculate) - GetHostInfo (); - return m_default_packet_timeout; +seconds GDBRemoteCommunicationClient::GetHostDefaultPacketTimeout() { + if (m_qHostInfo_is_valid == eLazyBoolCalculate) + GetHostInfo(); + return m_default_packet_timeout; } -addr_t -GDBRemoteCommunicationClient::AllocateMemory (size_t size, uint32_t permissions) -{ - if (m_supports_alloc_dealloc_memory != eLazyBoolNo) - { - m_supports_alloc_dealloc_memory = eLazyBoolYes; - char packet[64]; - const int packet_len = ::snprintf (packet, sizeof(packet), "_M%" PRIx64 ",%s%s%s", - (uint64_t)size, - permissions & lldb::ePermissionsReadable ? "r" : "", - permissions & lldb::ePermissionsWritable ? "w" : "", - permissions & lldb::ePermissionsExecutable ? "x" : ""); - assert (packet_len < (int)sizeof(packet)); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) - { - if (response.IsUnsupportedResponse()) - m_supports_alloc_dealloc_memory = eLazyBoolNo; - else if (!response.IsErrorResponse()) - return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS); - } - else - { - m_supports_alloc_dealloc_memory = eLazyBoolNo; - } - } - return LLDB_INVALID_ADDRESS; +addr_t GDBRemoteCommunicationClient::AllocateMemory(size_t size, + uint32_t permissions) { + if (m_supports_alloc_dealloc_memory != eLazyBoolNo) { + m_supports_alloc_dealloc_memory = eLazyBoolYes; + char packet[64]; + const int packet_len = ::snprintf( + packet, sizeof(packet), "_M%" PRIx64 ",%s%s%s", (uint64_t)size, + permissions & lldb::ePermissionsReadable ? "r" : "", + permissions & lldb::ePermissionsWritable ? "w" : "", + permissions & lldb::ePermissionsExecutable ? "x" : ""); + assert(packet_len < (int)sizeof(packet)); + UNUSED_IF_ASSERT_DISABLED(packet_len); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, response, false) == + PacketResult::Success) { + if (response.IsUnsupportedResponse()) + m_supports_alloc_dealloc_memory = eLazyBoolNo; + else if (!response.IsErrorResponse()) + return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS); + } else { + m_supports_alloc_dealloc_memory = eLazyBoolNo; + } + } + return LLDB_INVALID_ADDRESS; +} + +bool GDBRemoteCommunicationClient::DeallocateMemory(addr_t addr) { + if (m_supports_alloc_dealloc_memory != eLazyBoolNo) { + m_supports_alloc_dealloc_memory = eLazyBoolYes; + char packet[64]; + const int packet_len = + ::snprintf(packet, sizeof(packet), "_m%" PRIx64, (uint64_t)addr); + assert(packet_len < (int)sizeof(packet)); + UNUSED_IF_ASSERT_DISABLED(packet_len); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, response, false) == + PacketResult::Success) { + if (response.IsUnsupportedResponse()) + m_supports_alloc_dealloc_memory = eLazyBoolNo; + else if (response.IsOKResponse()) + return true; + } else { + m_supports_alloc_dealloc_memory = eLazyBoolNo; + } + } + return false; +} + +Error GDBRemoteCommunicationClient::Detach(bool keep_stopped) { + Error error; + + if (keep_stopped) { + if (m_supports_detach_stay_stopped == eLazyBoolCalculate) { + char packet[64]; + const int packet_len = + ::snprintf(packet, sizeof(packet), "qSupportsDetachAndStayStopped:"); + assert(packet_len < (int)sizeof(packet)); + UNUSED_IF_ASSERT_DISABLED(packet_len); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, response, false) == + PacketResult::Success && + response.IsOKResponse()) { + m_supports_detach_stay_stopped = eLazyBoolYes; + } else { + m_supports_detach_stay_stopped = eLazyBoolNo; + } + } + + if (m_supports_detach_stay_stopped == eLazyBoolNo) { + error.SetErrorString("Stays stopped not supported by this target."); + return error; + } else { + StringExtractorGDBRemote response; + PacketResult packet_result = + SendPacketAndWaitForResponse("D1", response, false); + if (packet_result != PacketResult::Success) + error.SetErrorString("Sending extended disconnect packet failed."); + } + } else { + StringExtractorGDBRemote response; + PacketResult packet_result = + SendPacketAndWaitForResponse("D", response, false); + if (packet_result != PacketResult::Success) + error.SetErrorString("Sending disconnect packet failed."); + } + return error; } -bool -GDBRemoteCommunicationClient::DeallocateMemory (addr_t addr) -{ - if (m_supports_alloc_dealloc_memory != eLazyBoolNo) - { - m_supports_alloc_dealloc_memory = eLazyBoolYes; - char packet[64]; - const int packet_len = ::snprintf(packet, sizeof(packet), "_m%" PRIx64, (uint64_t)addr); - assert (packet_len < (int)sizeof(packet)); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) - { - if (response.IsUnsupportedResponse()) - m_supports_alloc_dealloc_memory = eLazyBoolNo; - else if (response.IsOKResponse()) - return true; - } - else - { - m_supports_alloc_dealloc_memory = eLazyBoolNo; - } - } - return false; -} +Error GDBRemoteCommunicationClient::GetMemoryRegionInfo( + lldb::addr_t addr, lldb_private::MemoryRegionInfo ®ion_info) { + Error error; + region_info.Clear(); -Error -GDBRemoteCommunicationClient::Detach (bool keep_stopped) -{ - Error error; - - if (keep_stopped) - { - if (m_supports_detach_stay_stopped == eLazyBoolCalculate) - { - char packet[64]; - const int packet_len = ::snprintf(packet, sizeof(packet), "qSupportsDetachAndStayStopped:"); - assert (packet_len < (int)sizeof(packet)); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success - && response.IsOKResponse()) - { - m_supports_detach_stay_stopped = eLazyBoolYes; - } + if (m_supports_memory_region_info != eLazyBoolNo) { + m_supports_memory_region_info = eLazyBoolYes; + char packet[64]; + const int packet_len = ::snprintf( + packet, sizeof(packet), "qMemoryRegionInfo:%" PRIx64, (uint64_t)addr); + assert(packet_len < (int)sizeof(packet)); + UNUSED_IF_ASSERT_DISABLED(packet_len); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, response, false) == + PacketResult::Success) { + llvm::StringRef name; + llvm::StringRef value; + addr_t addr_value = LLDB_INVALID_ADDRESS; + bool success = true; + bool saw_permissions = false; + while (success && response.GetNameColonValue(name, value)) { + if (name.equals("start")) { + if (!value.getAsInteger(16, addr_value)) + region_info.GetRange().SetRangeBase(addr_value); + } else if (name.equals("size")) { + if (!value.getAsInteger(16, addr_value)) + region_info.GetRange().SetByteSize(addr_value); + } else if (name.equals("permissions") && + region_info.GetRange().IsValid()) { + saw_permissions = true; + if (region_info.GetRange().Contains(addr)) { + if (value.find('r') != llvm::StringRef::npos) + region_info.SetReadable(MemoryRegionInfo::eYes); else - { - m_supports_detach_stay_stopped = eLazyBoolNo; - } - } + region_info.SetReadable(MemoryRegionInfo::eNo); - if (m_supports_detach_stay_stopped == eLazyBoolNo) - { - error.SetErrorString("Stays stopped not supported by this target."); - return error; - } - else - { - StringExtractorGDBRemote response; - PacketResult packet_result = SendPacketAndWaitForResponse ("D1", 2, response, false); - if (packet_result != PacketResult::Success) - error.SetErrorString ("Sending extended disconnect packet failed."); - } - } - else - { - StringExtractorGDBRemote response; - PacketResult packet_result = SendPacketAndWaitForResponse ("D", 1, response, false); - if (packet_result != PacketResult::Success) - error.SetErrorString ("Sending disconnect packet failed."); - } - return error; -} + if (value.find('w') != llvm::StringRef::npos) + region_info.SetWritable(MemoryRegionInfo::eYes); + else + region_info.SetWritable(MemoryRegionInfo::eNo); -Error -GDBRemoteCommunicationClient::GetMemoryRegionInfo (lldb::addr_t addr, - lldb_private::MemoryRegionInfo ®ion_info) -{ - Error error; + if (value.find('x') != llvm::StringRef::npos) + region_info.SetExecutable(MemoryRegionInfo::eYes); + else + region_info.SetExecutable(MemoryRegionInfo::eNo); + + region_info.SetMapped(MemoryRegionInfo::eYes); + } else { + // The reported region does not contain this address -- we're + // looking at an unmapped page + region_info.SetReadable(MemoryRegionInfo::eNo); + region_info.SetWritable(MemoryRegionInfo::eNo); + region_info.SetExecutable(MemoryRegionInfo::eNo); + region_info.SetMapped(MemoryRegionInfo::eNo); + } + } else if (name.equals("name")) { + StringExtractorGDBRemote name_extractor(value); + std::string name; + name_extractor.GetHexByteString(name); + region_info.SetName(name.c_str()); + } else if (name.equals("error")) { + StringExtractorGDBRemote error_extractor(value); + std::string error_string; + // Now convert the HEX bytes into a string value + error_extractor.GetHexByteString(error_string); + error.SetErrorString(error_string.c_str()); + } + } + + // We got a valid address range back but no permissions -- which means + // this is an unmapped page + if (region_info.GetRange().IsValid() && saw_permissions == false) { + region_info.SetReadable(MemoryRegionInfo::eNo); + region_info.SetWritable(MemoryRegionInfo::eNo); + region_info.SetExecutable(MemoryRegionInfo::eNo); + region_info.SetMapped(MemoryRegionInfo::eNo); + } + } else { + m_supports_memory_region_info = eLazyBoolNo; + } + } + + if (m_supports_memory_region_info == eLazyBoolNo) { + error.SetErrorString("qMemoryRegionInfo is not supported"); + } + if (error.Fail()) region_info.Clear(); - - if (m_supports_memory_region_info != eLazyBoolNo) - { - m_supports_memory_region_info = eLazyBoolYes; - char packet[64]; - const int packet_len = ::snprintf(packet, sizeof(packet), "qMemoryRegionInfo:%" PRIx64, (uint64_t)addr); - assert (packet_len < (int)sizeof(packet)); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) - { - std::string name; - std::string value; - addr_t addr_value; - bool success = true; - bool saw_permissions = false; - while (success && response.GetNameColonValue(name, value)) - { - if (name.compare ("start") == 0) - { - addr_value = StringConvert::ToUInt64(value.c_str(), LLDB_INVALID_ADDRESS, 16, &success); - if (success) - region_info.GetRange().SetRangeBase(addr_value); - } - else if (name.compare ("size") == 0) - { - addr_value = StringConvert::ToUInt64(value.c_str(), 0, 16, &success); - if (success) - region_info.GetRange().SetByteSize (addr_value); - } - else if (name.compare ("permissions") == 0 && region_info.GetRange().IsValid()) - { - saw_permissions = true; - if (region_info.GetRange().Contains (addr)) - { - if (value.find('r') != std::string::npos) - region_info.SetReadable (MemoryRegionInfo::eYes); - else - region_info.SetReadable (MemoryRegionInfo::eNo); - - if (value.find('w') != std::string::npos) - region_info.SetWritable (MemoryRegionInfo::eYes); - else - region_info.SetWritable (MemoryRegionInfo::eNo); - - if (value.find('x') != std::string::npos) - region_info.SetExecutable (MemoryRegionInfo::eYes); - else - region_info.SetExecutable (MemoryRegionInfo::eNo); - - region_info.SetMapped(MemoryRegionInfo::eYes); - } - else - { - // The reported region does not contain this address -- we're looking at an unmapped page - region_info.SetReadable (MemoryRegionInfo::eNo); - region_info.SetWritable (MemoryRegionInfo::eNo); - region_info.SetExecutable (MemoryRegionInfo::eNo); - region_info.SetMapped(MemoryRegionInfo::eNo); - } - } - else if (name.compare ("error") == 0) - { - StringExtractorGDBRemote name_extractor; - // Swap "value" over into "name_extractor" - name_extractor.GetStringRef().swap(value); - // Now convert the HEX bytes into a string value - name_extractor.GetHexByteString (value); - error.SetErrorString(value.c_str()); - } - } - - // We got a valid address range back but no permissions -- which means this is an unmapped page - if (region_info.GetRange().IsValid() && saw_permissions == false) - { - region_info.SetReadable (MemoryRegionInfo::eNo); - region_info.SetWritable (MemoryRegionInfo::eNo); - region_info.SetExecutable (MemoryRegionInfo::eNo); - region_info.SetMapped(MemoryRegionInfo::eNo); - } - } - else - { - m_supports_memory_region_info = eLazyBoolNo; - } - } - - if (m_supports_memory_region_info == eLazyBoolNo) - { - error.SetErrorString("qMemoryRegionInfo is not supported"); - } - if (error.Fail()) - region_info.Clear(); - return error; - + return error; } -Error -GDBRemoteCommunicationClient::GetWatchpointSupportInfo (uint32_t &num) -{ - Error error; +Error GDBRemoteCommunicationClient::GetWatchpointSupportInfo(uint32_t &num) { + Error error; - if (m_supports_watchpoint_support_info == eLazyBoolYes) - { - num = m_num_supported_hardware_watchpoints; - return error; - } + if (m_supports_watchpoint_support_info == eLazyBoolYes) { + num = m_num_supported_hardware_watchpoints; + return error; + } - // Set num to 0 first. - num = 0; - if (m_supports_watchpoint_support_info != eLazyBoolNo) - { - char packet[64]; - const int packet_len = ::snprintf(packet, sizeof(packet), "qWatchpointSupportInfo:"); - assert (packet_len < (int)sizeof(packet)); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) - { - m_supports_watchpoint_support_info = eLazyBoolYes; - std::string name; - std::string value; - while (response.GetNameColonValue(name, value)) - { - if (name.compare ("num") == 0) - { - num = StringConvert::ToUInt32(value.c_str(), 0, 0); - m_num_supported_hardware_watchpoints = num; - } - } - } - else - { - m_supports_watchpoint_support_info = eLazyBoolNo; + // Set num to 0 first. + num = 0; + if (m_supports_watchpoint_support_info != eLazyBoolNo) { + char packet[64]; + const int packet_len = + ::snprintf(packet, sizeof(packet), "qWatchpointSupportInfo:"); + assert(packet_len < (int)sizeof(packet)); + UNUSED_IF_ASSERT_DISABLED(packet_len); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, response, false) == + PacketResult::Success) { + m_supports_watchpoint_support_info = eLazyBoolYes; + llvm::StringRef name; + llvm::StringRef value; + while (response.GetNameColonValue(name, value)) { + if (name.equals("num")) { + value.getAsInteger(0, m_num_supported_hardware_watchpoints); + num = m_num_supported_hardware_watchpoints; } + } + } else { + m_supports_watchpoint_support_info = eLazyBoolNo; } + } - if (m_supports_watchpoint_support_info == eLazyBoolNo) - { - error.SetErrorString("qWatchpointSupportInfo is not supported"); - } - return error; - + if (m_supports_watchpoint_support_info == eLazyBoolNo) { + error.SetErrorString("qWatchpointSupportInfo is not supported"); + } + return error; } -lldb_private::Error -GDBRemoteCommunicationClient::GetWatchpointSupportInfo (uint32_t &num, bool& after, const ArchSpec &arch) -{ - Error error(GetWatchpointSupportInfo(num)); - if (error.Success()) - error = GetWatchpointsTriggerAfterInstruction(after, arch); - return error; +lldb_private::Error GDBRemoteCommunicationClient::GetWatchpointSupportInfo( + uint32_t &num, bool &after, const ArchSpec &arch) { + Error error(GetWatchpointSupportInfo(num)); + if (error.Success()) + error = GetWatchpointsTriggerAfterInstruction(after, arch); + return error; } lldb_private::Error -GDBRemoteCommunicationClient::GetWatchpointsTriggerAfterInstruction (bool &after, const ArchSpec &arch) -{ - Error error; - llvm::Triple::ArchType atype = arch.GetMachine(); - - // we assume watchpoints will happen after running the relevant opcode - // and we only want to override this behavior if we have explicitly - // received a qHostInfo telling us otherwise - if (m_qHostInfo_is_valid != eLazyBoolYes) - { - // On targets like MIPS, 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) - after = false; - else - after = true; - } +GDBRemoteCommunicationClient::GetWatchpointsTriggerAfterInstruction( + bool &after, const ArchSpec &arch) { + Error error; + llvm::Triple::ArchType atype = arch.GetMachine(); + + // we assume watchpoints will happen after running the relevant opcode + // and we only want to override this behavior if we have explicitly + // received a qHostInfo telling us otherwise + if (m_qHostInfo_is_valid != eLazyBoolYes) { + // On targets like MIPS, 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) + after = false; else - { - // For MIPS, set m_watchpoints_trigger_after_instruction to eLazyBoolNo - // if it is not calculated before. - if (m_watchpoints_trigger_after_instruction == eLazyBoolCalculate && - (atype == llvm::Triple::mips || atype == llvm::Triple::mipsel - || atype == llvm::Triple::mips64 || atype == llvm::Triple::mips64el)) - m_watchpoints_trigger_after_instruction = eLazyBoolNo; - - after = (m_watchpoints_trigger_after_instruction != eLazyBoolNo); - } - return error; -} - -int -GDBRemoteCommunicationClient::SetSTDIN(const FileSpec &file_spec) -{ - if (file_spec) - { - std::string path{file_spec.GetPath(false)}; - StreamString packet; - packet.PutCString("QSetSTDIN:"); - packet.PutCStringAsRawHex8(path.c_str()); - - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - return 0; - uint8_t error = response.GetError(); - if (error) - return error; - } - } - return -1; -} + after = true; + } else { + // For MIPS, set m_watchpoints_trigger_after_instruction to eLazyBoolNo + // if it is not calculated before. + if (m_watchpoints_trigger_after_instruction == eLazyBoolCalculate && + (atype == llvm::Triple::mips || atype == llvm::Triple::mipsel || + atype == llvm::Triple::mips64 || atype == llvm::Triple::mips64el)) + m_watchpoints_trigger_after_instruction = eLazyBoolNo; + + after = (m_watchpoints_trigger_after_instruction != eLazyBoolNo); + } + return error; +} + +int GDBRemoteCommunicationClient::SetSTDIN(const FileSpec &file_spec) { + if (file_spec) { + std::string path{file_spec.GetPath(false)}; + StreamString packet; + packet.PutCString("QSetSTDIN:"); + packet.PutCStringAsRawHex8(path.c_str()); -int -GDBRemoteCommunicationClient::SetSTDOUT(const FileSpec &file_spec) -{ - if (file_spec) - { - std::string path{file_spec.GetPath(false)}; - StreamString packet; - packet.PutCString("QSetSTDOUT:"); - packet.PutCStringAsRawHex8(path.c_str()); - - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - return 0; - uint8_t error = response.GetError(); - if (error) - return error; - } + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == + PacketResult::Success) { + if (response.IsOKResponse()) + return 0; + uint8_t error = response.GetError(); + if (error) + return error; } - return -1; + } + return -1; } -int -GDBRemoteCommunicationClient::SetSTDERR(const FileSpec &file_spec) -{ - if (file_spec) - { - std::string path{file_spec.GetPath(false)}; - StreamString packet; - packet.PutCString("QSetSTDERR:"); - packet.PutCStringAsRawHex8(path.c_str()); - - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - return 0; - uint8_t error = response.GetError(); - if (error) - return error; - } - } - return -1; -} +int GDBRemoteCommunicationClient::SetSTDOUT(const FileSpec &file_spec) { + if (file_spec) { + std::string path{file_spec.GetPath(false)}; + StreamString packet; + packet.PutCString("QSetSTDOUT:"); + packet.PutCStringAsRawHex8(path.c_str()); -bool -GDBRemoteCommunicationClient::GetWorkingDir(FileSpec &working_dir) -{ StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse ("qGetWorkingDir", response, false) == PacketResult::Success) - { - if (response.IsUnsupportedResponse()) - return false; - if (response.IsErrorResponse()) - return false; - std::string cwd; - response.GetHexByteString(cwd); - working_dir.SetFile(cwd, false, GetHostArchitecture()); - return !cwd.empty(); + if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == + PacketResult::Success) { + if (response.IsOKResponse()) + return 0; + uint8_t error = response.GetError(); + if (error) + return error; } - return false; + } + return -1; } -int -GDBRemoteCommunicationClient::SetWorkingDir(const FileSpec &working_dir) -{ - if (working_dir) - { - std::string path{working_dir.GetPath(false)}; - StreamString packet; - packet.PutCString("QSetWorkingDir:"); - packet.PutCStringAsRawHex8(path.c_str()); - - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - return 0; - uint8_t error = response.GetError(); - if (error) - return error; - } - } - return -1; -} +int GDBRemoteCommunicationClient::SetSTDERR(const FileSpec &file_spec) { + if (file_spec) { + std::string path{file_spec.GetPath(false)}; + StreamString packet; + packet.PutCString("QSetSTDERR:"); + packet.PutCStringAsRawHex8(path.c_str()); -int -GDBRemoteCommunicationClient::SetDisableASLR (bool enable) -{ - char packet[32]; - const int packet_len = ::snprintf (packet, sizeof (packet), "QSetDisableASLR:%i", enable ? 1 : 0); - assert (packet_len < (int)sizeof(packet)); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - return 0; - uint8_t error = response.GetError(); - if (error) - return error; + if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == + PacketResult::Success) { + if (response.IsOKResponse()) + return 0; + uint8_t error = response.GetError(); + if (error) + return error; } - return -1; -} + } + return -1; +} + +bool GDBRemoteCommunicationClient::GetWorkingDir(FileSpec &working_dir) { + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse("qGetWorkingDir", response, false) == + PacketResult::Success) { + if (response.IsUnsupportedResponse()) + return false; + if (response.IsErrorResponse()) + return false; + std::string cwd; + response.GetHexByteString(cwd); + working_dir.SetFile(cwd, false, GetHostArchitecture()); + return !cwd.empty(); + } + return false; +} + +int GDBRemoteCommunicationClient::SetWorkingDir(const FileSpec &working_dir) { + if (working_dir) { + std::string path{working_dir.GetPath(false)}; + StreamString packet; + packet.PutCString("QSetWorkingDir:"); + packet.PutCStringAsRawHex8(path.c_str()); -int -GDBRemoteCommunicationClient::SetDetachOnError (bool enable) -{ - char packet[32]; - const int packet_len = ::snprintf (packet, sizeof (packet), "QSetDetachOnError:%i", enable ? 1 : 0); - assert (packet_len < (int)sizeof(packet)); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - return 0; - uint8_t error = response.GetError(); - if (error) - return error; + if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == + PacketResult::Success) { + if (response.IsOKResponse()) + return 0; + uint8_t error = response.GetError(); + if (error) + return error; } - return -1; -} - + } + return -1; +} + +int GDBRemoteCommunicationClient::SetDisableASLR(bool enable) { + char packet[32]; + const int packet_len = + ::snprintf(packet, sizeof(packet), "QSetDisableASLR:%i", enable ? 1 : 0); + assert(packet_len < (int)sizeof(packet)); + UNUSED_IF_ASSERT_DISABLED(packet_len); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, response, false) == + PacketResult::Success) { + if (response.IsOKResponse()) + return 0; + uint8_t error = response.GetError(); + if (error) + return error; + } + return -1; +} + +int GDBRemoteCommunicationClient::SetDetachOnError(bool enable) { + char packet[32]; + const int packet_len = ::snprintf(packet, sizeof(packet), + "QSetDetachOnError:%i", enable ? 1 : 0); + assert(packet_len < (int)sizeof(packet)); + UNUSED_IF_ASSERT_DISABLED(packet_len); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, response, false) == + PacketResult::Success) { + if (response.IsOKResponse()) + return 0; + uint8_t error = response.GetError(); + if (error) + return error; + } + return -1; +} + +bool GDBRemoteCommunicationClient::DecodeProcessInfoResponse( + StringExtractorGDBRemote &response, ProcessInstanceInfo &process_info) { + if (response.IsNormalResponse()) { + llvm::StringRef name; + llvm::StringRef value; + StringExtractor extractor; -bool -GDBRemoteCommunicationClient::DecodeProcessInfoResponse (StringExtractorGDBRemote &response, ProcessInstanceInfo &process_info) -{ - if (response.IsNormalResponse()) - { + uint32_t cpu = LLDB_INVALID_CPUTYPE; + uint32_t sub = 0; + std::string vendor; + std::string os_type; + + while (response.GetNameColonValue(name, value)) { + if (name.equals("pid")) { + lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; + value.getAsInteger(0, pid); + process_info.SetProcessID(pid); + } else if (name.equals("ppid")) { + lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; + value.getAsInteger(0, pid); + process_info.SetParentProcessID(pid); + } else if (name.equals("uid")) { + uint32_t uid = UINT32_MAX; + value.getAsInteger(0, uid); + process_info.SetUserID(uid); + } else if (name.equals("euid")) { + uint32_t uid = UINT32_MAX; + value.getAsInteger(0, uid); + process_info.SetEffectiveGroupID(uid); + } else if (name.equals("gid")) { + uint32_t gid = UINT32_MAX; + value.getAsInteger(0, gid); + process_info.SetGroupID(gid); + } else if (name.equals("egid")) { + uint32_t gid = UINT32_MAX; + value.getAsInteger(0, gid); + process_info.SetEffectiveGroupID(gid); + } else if (name.equals("triple")) { + StringExtractor extractor(value); + std::string triple; + extractor.GetHexByteString(triple); + process_info.GetArchitecture().SetTriple(triple.c_str()); + } else if (name.equals("name")) { + StringExtractor extractor(value); + // The process name from ASCII hex bytes since we can't + // control the characters in a process name std::string name; - std::string value; - StringExtractor extractor; - - uint32_t cpu = LLDB_INVALID_CPUTYPE; - uint32_t sub = 0; - std::string vendor; - std::string os_type; - - while (response.GetNameColonValue(name, value)) - { - if (name.compare("pid") == 0) - { - process_info.SetProcessID (StringConvert::ToUInt32 (value.c_str(), LLDB_INVALID_PROCESS_ID, 0)); - } - else if (name.compare("ppid") == 0) - { - process_info.SetParentProcessID (StringConvert::ToUInt32 (value.c_str(), LLDB_INVALID_PROCESS_ID, 0)); - } - else if (name.compare("uid") == 0) - { - process_info.SetUserID (StringConvert::ToUInt32 (value.c_str(), UINT32_MAX, 0)); - } - else if (name.compare("euid") == 0) - { - process_info.SetEffectiveUserID (StringConvert::ToUInt32 (value.c_str(), UINT32_MAX, 0)); - } - else if (name.compare("gid") == 0) - { - process_info.SetGroupID (StringConvert::ToUInt32 (value.c_str(), UINT32_MAX, 0)); - } - else if (name.compare("egid") == 0) - { - process_info.SetEffectiveGroupID (StringConvert::ToUInt32 (value.c_str(), UINT32_MAX, 0)); - } - else if (name.compare("triple") == 0) - { - StringExtractor extractor; - extractor.GetStringRef().swap(value); - extractor.SetFilePos(0); - extractor.GetHexByteString (value); - process_info.GetArchitecture ().SetTriple (value.c_str()); - } - else if (name.compare("name") == 0) - { - StringExtractor extractor; - // The process name from ASCII hex bytes since we can't - // control the characters in a process name - extractor.GetStringRef().swap(value); - extractor.SetFilePos(0); - extractor.GetHexByteString (value); - process_info.GetExecutableFile().SetFile (value.c_str(), false); - } - else if (name.compare("cputype") == 0) - { - cpu = StringConvert::ToUInt32 (value.c_str(), LLDB_INVALID_CPUTYPE, 16); - } - else if (name.compare("cpusubtype") == 0) - { - sub = StringConvert::ToUInt32 (value.c_str(), 0, 16); - } - else if (name.compare("vendor") == 0) - { - vendor = value; - } - else if (name.compare("ostype") == 0) - { - os_type = value; - } - } - - if (cpu != LLDB_INVALID_CPUTYPE && !vendor.empty() && !os_type.empty()) - { - if (vendor == "apple") - { - process_info.GetArchitecture().SetArchitecture (eArchTypeMachO, cpu, sub); - process_info.GetArchitecture().GetTriple().setVendorName (llvm::StringRef (vendor)); - process_info.GetArchitecture().GetTriple().setOSName (llvm::StringRef (os_type)); - } - } - - if (process_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) - return true; - } - return false; -} - -bool -GDBRemoteCommunicationClient::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info) -{ - process_info.Clear(); - - if (m_supports_qProcessInfoPID) - { - char packet[32]; - const int packet_len = ::snprintf (packet, sizeof (packet), "qProcessInfoPID:%" PRIu64, pid); - assert (packet_len < (int)sizeof(packet)); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) - { - return DecodeProcessInfoResponse (response, process_info); - } - else - { - m_supports_qProcessInfoPID = false; - return false; - } - } - return false; -} - -bool -GDBRemoteCommunicationClient::GetCurrentProcessInfo (bool allow_lazy) -{ - Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_PROCESS | GDBR_LOG_PACKETS)); - - if (allow_lazy) - { - if (m_qProcessInfo_is_valid == eLazyBoolYes) - return true; - if (m_qProcessInfo_is_valid == eLazyBoolNo) - return false; - } - - GetHostInfo (); - - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse ("qProcessInfo", response, false) == PacketResult::Success) - { - if (response.IsNormalResponse()) - { - std::string name; - std::string value; - uint32_t cpu = LLDB_INVALID_CPUTYPE; - uint32_t sub = 0; - std::string arch_name; - std::string os_name; - std::string vendor_name; - std::string triple; - std::string elf_abi; - uint32_t pointer_byte_size = 0; - StringExtractor extractor; - ByteOrder byte_order = eByteOrderInvalid; - uint32_t num_keys_decoded = 0; - lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; - while (response.GetNameColonValue(name, value)) - { - if (name.compare("cputype") == 0) - { - cpu = StringConvert::ToUInt32 (value.c_str(), LLDB_INVALID_CPUTYPE, 16); - if (cpu != LLDB_INVALID_CPUTYPE) - ++num_keys_decoded; - } - else if (name.compare("cpusubtype") == 0) - { - sub = StringConvert::ToUInt32 (value.c_str(), 0, 16); - if (sub != 0) - ++num_keys_decoded; - } - else if (name.compare("triple") == 0) - { - StringExtractor extractor; - extractor.GetStringRef().swap(value); - extractor.SetFilePos(0); - extractor.GetHexByteString (triple); - ++num_keys_decoded; - } - else if (name.compare("ostype") == 0) - { - os_name.swap (value); - ++num_keys_decoded; - } - else if (name.compare("vendor") == 0) - { - vendor_name.swap(value); - ++num_keys_decoded; - } - else if (name.compare("endian") == 0) - { - ++num_keys_decoded; - if (value.compare("little") == 0) - byte_order = eByteOrderLittle; - else if (value.compare("big") == 0) - byte_order = eByteOrderBig; - else if (value.compare("pdp") == 0) - byte_order = eByteOrderPDP; - else - --num_keys_decoded; - } - else if (name.compare("ptrsize") == 0) - { - pointer_byte_size = StringConvert::ToUInt32 (value.c_str(), 0, 16); - if (pointer_byte_size != 0) - ++num_keys_decoded; - } - else if (name.compare("pid") == 0) - { - pid = StringConvert::ToUInt64(value.c_str(), 0, 16); - if (pid != LLDB_INVALID_PROCESS_ID) - ++num_keys_decoded; - } - else if (name.compare("elf_abi") == 0) - { - elf_abi = value; - ++num_keys_decoded; - } - } - if (num_keys_decoded > 0) - m_qProcessInfo_is_valid = eLazyBoolYes; - if (pid != LLDB_INVALID_PROCESS_ID) - { - m_curr_pid_is_valid = eLazyBoolYes; - m_curr_pid = pid; - } - - // Set the ArchSpec from the triple if we have it. - if (!triple.empty ()) - { - m_process_arch.SetTriple (triple.c_str ()); - m_process_arch.SetFlags(elf_abi); - if (pointer_byte_size) - { - assert (pointer_byte_size == m_process_arch.GetAddressByteSize()); - } - } - else if (cpu != LLDB_INVALID_CPUTYPE && !os_name.empty() && !vendor_name.empty()) - { - llvm::Triple triple(llvm::Twine("-") + vendor_name + "-" + os_name); - - assert(triple.getObjectFormat() != llvm::Triple::UnknownObjectFormat); - switch (triple.getObjectFormat()) { - case llvm::Triple::MachO: - m_process_arch.SetArchitecture (eArchTypeMachO, cpu, sub); - break; - case llvm::Triple::ELF: - m_process_arch.SetArchitecture (eArchTypeELF, cpu, sub); - break; - case llvm::Triple::COFF: - m_process_arch.SetArchitecture (eArchTypeCOFF, cpu, sub); - break; - case llvm::Triple::UnknownObjectFormat: - if (log) - log->Printf("error: failed to determine target architecture"); - return false; - } - - if (pointer_byte_size) - { - assert (pointer_byte_size == m_process_arch.GetAddressByteSize()); - } - if (byte_order != eByteOrderInvalid) - { - assert (byte_order == m_process_arch.GetByteOrder()); - } - m_process_arch.GetTriple().setVendorName (llvm::StringRef (vendor_name)); - m_process_arch.GetTriple().setOSName(llvm::StringRef (os_name)); - m_host_arch.GetTriple().setVendorName (llvm::StringRef (vendor_name)); - m_host_arch.GetTriple().setOSName (llvm::StringRef (os_name)); - } - return true; - } - } - else - { - m_qProcessInfo_is_valid = eLazyBoolNo; - } - - return false; -} - - -uint32_t -GDBRemoteCommunicationClient::FindProcesses (const ProcessInstanceInfoMatch &match_info, - ProcessInstanceInfoList &process_infos) -{ - process_infos.Clear(); - - if (m_supports_qfProcessInfo) - { - StreamString packet; - packet.PutCString ("qfProcessInfo"); - if (!match_info.MatchAllProcesses()) - { - packet.PutChar (':'); - const char *name = match_info.GetProcessInfo().GetName(); - bool has_name_match = false; - if (name && name[0]) - { - has_name_match = true; - NameMatchType name_match_type = match_info.GetNameMatchType(); - switch (name_match_type) - { - case eNameMatchIgnore: - has_name_match = false; - break; - - case eNameMatchEquals: - packet.PutCString ("name_match:equals;"); - break; - - case eNameMatchContains: - packet.PutCString ("name_match:contains;"); - break; - - case eNameMatchStartsWith: - packet.PutCString ("name_match:starts_with;"); - break; - - case eNameMatchEndsWith: - packet.PutCString ("name_match:ends_with;"); - break; - - case eNameMatchRegularExpression: - packet.PutCString ("name_match:regex;"); - break; - } - if (has_name_match) - { - packet.PutCString ("name:"); - packet.PutBytesAsRawHex8(name, ::strlen(name)); - packet.PutChar (';'); - } - } - - if (match_info.GetProcessInfo().ProcessIDIsValid()) - packet.Printf("pid:%" PRIu64 ";",match_info.GetProcessInfo().GetProcessID()); - if (match_info.GetProcessInfo().ParentProcessIDIsValid()) - packet.Printf("parent_pid:%" PRIu64 ";",match_info.GetProcessInfo().GetParentProcessID()); - if (match_info.GetProcessInfo().UserIDIsValid()) - packet.Printf("uid:%u;",match_info.GetProcessInfo().GetUserID()); - if (match_info.GetProcessInfo().GroupIDIsValid()) - packet.Printf("gid:%u;",match_info.GetProcessInfo().GetGroupID()); - if (match_info.GetProcessInfo().EffectiveUserIDIsValid()) - packet.Printf("euid:%u;",match_info.GetProcessInfo().GetEffectiveUserID()); - if (match_info.GetProcessInfo().EffectiveGroupIDIsValid()) - packet.Printf("egid:%u;",match_info.GetProcessInfo().GetEffectiveGroupID()); - if (match_info.GetProcessInfo().EffectiveGroupIDIsValid()) - packet.Printf("all_users:%u;",match_info.GetMatchAllUsers() ? 1 : 0); - if (match_info.GetProcessInfo().GetArchitecture().IsValid()) - { - const ArchSpec &match_arch = match_info.GetProcessInfo().GetArchitecture(); - const llvm::Triple &triple = match_arch.GetTriple(); - packet.PutCString("triple:"); - packet.PutCString(triple.getTriple().c_str()); - packet.PutChar (';'); - } - } - StringExtractorGDBRemote response; - // Increase timeout as the first qfProcessInfo packet takes a long time - // on Android. The value of 1min was arrived at empirically. - GDBRemoteCommunication::ScopedTimeout timeout (*this, 60); - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) - { - do - { - ProcessInstanceInfo process_info; - if (!DecodeProcessInfoResponse (response, process_info)) - break; - process_infos.Append(process_info); - response.GetStringRef().clear(); - response.SetFilePos(0); - } while (SendPacketAndWaitForResponse ("qsProcessInfo", strlen ("qsProcessInfo"), response, false) == PacketResult::Success); - } - else - { - m_supports_qfProcessInfo = false; - return 0; - } - } - return process_infos.GetSize(); - -} - -bool -GDBRemoteCommunicationClient::GetUserName (uint32_t uid, std::string &name) -{ - if (m_supports_qUserName) - { - char packet[32]; - const int packet_len = ::snprintf (packet, sizeof (packet), "qUserName:%i", uid); - assert (packet_len < (int)sizeof(packet)); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) - { - if (response.IsNormalResponse()) - { - // Make sure we parsed the right number of characters. The response is - // the hex encoded user name and should make up the entire packet. - // If there are any non-hex ASCII bytes, the length won't match below.. - if (response.GetHexByteString (name) * 2 == response.GetStringRef().size()) - return true; - } - } - else - { - m_supports_qUserName = false; - return false; - } - } - return false; - -} - -bool -GDBRemoteCommunicationClient::GetGroupName (uint32_t gid, std::string &name) -{ - if (m_supports_qGroupName) - { - char packet[32]; - const int packet_len = ::snprintf (packet, sizeof (packet), "qGroupName:%i", gid); - assert (packet_len < (int)sizeof(packet)); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) - { - if (response.IsNormalResponse()) - { - // Make sure we parsed the right number of characters. The response is - // the hex encoded group name and should make up the entire packet. - // If there are any non-hex ASCII bytes, the length won't match below.. - if (response.GetHexByteString (name) * 2 == response.GetStringRef().size()) - return true; - } - } - else - { - m_supports_qGroupName = false; - return false; - } - } - return false; -} - -bool -GDBRemoteCommunicationClient::SetNonStopMode (const bool enable) -{ - // Form non-stop packet request + extractor.GetHexByteString(name); + process_info.GetExecutableFile().SetFile(name, false); + } else if (name.equals("cputype")) { + value.getAsInteger(0, cpu); + } else if (name.equals("cpusubtype")) { + value.getAsInteger(0, sub); + } else if (name.equals("vendor")) { + vendor = value; + } else if (name.equals("ostype")) { + os_type = value; + } + } + + if (cpu != LLDB_INVALID_CPUTYPE && !vendor.empty() && !os_type.empty()) { + if (vendor == "apple") { + process_info.GetArchitecture().SetArchitecture(eArchTypeMachO, cpu, + sub); + process_info.GetArchitecture().GetTriple().setVendorName( + llvm::StringRef(vendor)); + process_info.GetArchitecture().GetTriple().setOSName( + llvm::StringRef(os_type)); + } + } + + if (process_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) + return true; + } + return false; +} + +bool GDBRemoteCommunicationClient::GetProcessInfo( + lldb::pid_t pid, ProcessInstanceInfo &process_info) { + process_info.Clear(); + + if (m_supports_qProcessInfoPID) { char packet[32]; - const int packet_len = ::snprintf(packet, sizeof(packet), "QNonStop:%1d", (int)enable); + const int packet_len = + ::snprintf(packet, sizeof(packet), "qProcessInfoPID:%" PRIu64, pid); assert(packet_len < (int)sizeof(packet)); - + UNUSED_IF_ASSERT_DISABLED(packet_len); StringExtractorGDBRemote response; - // Send to target - if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) - if (response.IsOKResponse()) - return true; - - // Failed or not supported - return false; - -} - -static void -MakeSpeedTestPacket(StreamString &packet, uint32_t send_size, uint32_t recv_size) -{ - packet.Clear(); - packet.Printf ("qSpeedTest:response_size:%i;data:", recv_size); - uint32_t bytes_left = send_size; - while (bytes_left > 0) - { - if (bytes_left >= 26) - { - packet.PutCString("abcdefghijklmnopqrstuvwxyz"); - bytes_left -= 26; - } - else - { - packet.Printf ("%*.*s;", bytes_left, bytes_left, "abcdefghijklmnopqrstuvwxyz"); - bytes_left = 0; - } - } -} - -template<typename T> -T calculate_standard_deviation(const std::vector<T> &v) -{ - T sum = std::accumulate(std::begin(v), std::end(v), T(0)); - T mean = sum / (T)v.size(); - T accum = T(0); - std::for_each (std::begin(v), std::end(v), [&](const T d) { - T delta = d - mean; - accum += delta * delta; - }); - - T stdev = sqrt(accum / (v.size()-1)); - return stdev; -} - -void -GDBRemoteCommunicationClient::TestPacketSpeed (const uint32_t num_packets, uint32_t max_send, uint32_t max_recv, bool json, Stream &strm) -{ - uint32_t i; - TimeValue start_time, end_time; - uint64_t total_time_nsec; - if (SendSpeedTestPacket (0, 0)) - { - StreamString packet; - if (json) - strm.Printf("{ \"packet_speeds\" : {\n \"num_packets\" : %u,\n \"results\" : [", num_packets); - else - strm.Printf("Testing sending %u packets of various sizes:\n", num_packets); - strm.Flush(); - - uint32_t result_idx = 0; - uint32_t send_size; - std::vector<float> packet_times; - - for (send_size = 0; send_size <= max_send; send_size ? send_size *= 2 : send_size = 4) - { - for (uint32_t recv_size = 0; recv_size <= max_recv; recv_size ? recv_size *= 2 : recv_size = 4) - { - MakeSpeedTestPacket (packet, send_size, recv_size); - - packet_times.clear(); - // Test how long it takes to send 'num_packets' packets - start_time = TimeValue::Now(); - for (i=0; i<num_packets; ++i) - { - TimeValue packet_start_time = TimeValue::Now(); - StringExtractorGDBRemote response; - SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false); - TimeValue packet_end_time = TimeValue::Now(); - uint64_t packet_time_nsec = packet_end_time.GetAsNanoSecondsSinceJan1_1970() - packet_start_time.GetAsNanoSecondsSinceJan1_1970(); - packet_times.push_back((float)packet_time_nsec); - } - end_time = TimeValue::Now(); - total_time_nsec = end_time.GetAsNanoSecondsSinceJan1_1970() - start_time.GetAsNanoSecondsSinceJan1_1970(); - - float packets_per_second = (((float)num_packets)/(float)total_time_nsec) * (float)TimeValue::NanoSecPerSec; - float total_ms = (float)total_time_nsec/(float)TimeValue::NanoSecPerMilliSec; - float average_ms_per_packet = total_ms / num_packets; - const float standard_deviation = calculate_standard_deviation<float>(packet_times); - if (json) - { - strm.Printf ("%s\n {\"send_size\" : %6" PRIu32 ", \"recv_size\" : %6" PRIu32 ", \"total_time_nsec\" : %12" PRIu64 ", \"standard_deviation_nsec\" : %9" PRIu64 " }", result_idx > 0 ? "," : "", send_size, recv_size, total_time_nsec, (uint64_t)standard_deviation); - ++result_idx; - } - else - { - strm.Printf ("qSpeedTest(send=%-7u, recv=%-7u) in %" PRIu64 ".%9.9" PRIu64 " sec for %9.2f packets/sec (%10.6f ms per packet) with standard deviation of %10.6f ms\n", - send_size, - recv_size, - total_time_nsec / TimeValue::NanoSecPerSec, - total_time_nsec % TimeValue::NanoSecPerSec, - packets_per_second, - average_ms_per_packet, - standard_deviation/(float)TimeValue::NanoSecPerMilliSec); - } - strm.Flush(); - } - } - - const uint64_t k_recv_amount = 4*1024*1024; // Receive amount in bytes - - const float k_recv_amount_mb = (float)k_recv_amount/(1024.0f*1024.0f); - if (json) - strm.Printf("\n ]\n },\n \"download_speed\" : {\n \"byte_size\" : %" PRIu64 ",\n \"results\" : [", k_recv_amount); - else - strm.Printf("Testing receiving %2.1fMB of data using varying receive packet sizes:\n", k_recv_amount_mb); - strm.Flush(); - send_size = 0; - result_idx = 0; - for (uint32_t recv_size = 32; recv_size <= max_recv; recv_size *= 2) - { - MakeSpeedTestPacket (packet, send_size, recv_size); - - // If we have a receive size, test how long it takes to receive 4MB of data - if (recv_size > 0) - { - start_time = TimeValue::Now(); - uint32_t bytes_read = 0; - uint32_t packet_count = 0; - while (bytes_read < k_recv_amount) - { - StringExtractorGDBRemote response; - SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false); - bytes_read += recv_size; - ++packet_count; - } - end_time = TimeValue::Now(); - total_time_nsec = end_time.GetAsNanoSecondsSinceJan1_1970() - start_time.GetAsNanoSecondsSinceJan1_1970(); - float mb_second = ((((float)k_recv_amount)/(float)total_time_nsec) * (float)TimeValue::NanoSecPerSec) / (1024.0*1024.0); - float packets_per_second = (((float)packet_count)/(float)total_time_nsec) * (float)TimeValue::NanoSecPerSec; - float total_ms = (float)total_time_nsec/(float)TimeValue::NanoSecPerMilliSec; - float average_ms_per_packet = total_ms / packet_count; - - if (json) - { - strm.Printf ("%s\n {\"send_size\" : %6" PRIu32 ", \"recv_size\" : %6" PRIu32 ", \"total_time_nsec\" : %12" PRIu64 " }", result_idx > 0 ? "," : "", send_size, recv_size, total_time_nsec); - ++result_idx; - } - else - { - strm.Printf ("qSpeedTest(send=%-7u, recv=%-7u) %6u packets needed to receive %2.1fMB in %" PRIu64 ".%9.9" PRIu64 " sec for %f MB/sec for %9.2f packets/sec (%10.6f ms per packet)\n", - send_size, - recv_size, - packet_count, - k_recv_amount_mb, - total_time_nsec / TimeValue::NanoSecPerSec, - total_time_nsec % TimeValue::NanoSecPerSec, - mb_second, - packets_per_second, - average_ms_per_packet); - } - strm.Flush(); - } - } - if (json) - strm.Printf("\n ]\n }\n}\n"); - else - strm.EOL(); - } -} - -bool -GDBRemoteCommunicationClient::SendSpeedTestPacket (uint32_t send_size, uint32_t recv_size) -{ + if (SendPacketAndWaitForResponse(packet, response, false) == + PacketResult::Success) { + return DecodeProcessInfoResponse(response, process_info); + } else { + m_supports_qProcessInfoPID = false; + return false; + } + } + return false; +} + +bool GDBRemoteCommunicationClient::GetCurrentProcessInfo(bool allow_lazy) { + Log *log(ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(GDBR_LOG_PROCESS | + GDBR_LOG_PACKETS)); + + if (allow_lazy) { + if (m_qProcessInfo_is_valid == eLazyBoolYes) + return true; + if (m_qProcessInfo_is_valid == eLazyBoolNo) + return false; + } + + GetHostInfo(); + + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse("qProcessInfo", response, false) == + PacketResult::Success) { + if (response.IsNormalResponse()) { + llvm::StringRef name; + llvm::StringRef value; + uint32_t cpu = LLDB_INVALID_CPUTYPE; + uint32_t sub = 0; + std::string arch_name; + std::string os_name; + std::string vendor_name; + std::string triple; + std::string elf_abi; + uint32_t pointer_byte_size = 0; + StringExtractor extractor; + ByteOrder byte_order = eByteOrderInvalid; + uint32_t num_keys_decoded = 0; + lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; + while (response.GetNameColonValue(name, value)) { + if (name.equals("cputype")) { + if (!value.getAsInteger(16, cpu)) + ++num_keys_decoded; + } else if (name.equals("cpusubtype")) { + if (!value.getAsInteger(16, sub)) + ++num_keys_decoded; + } else if (name.equals("triple")) { + StringExtractor extractor(value); + extractor.GetHexByteString(triple); + ++num_keys_decoded; + } else if (name.equals("ostype")) { + os_name = value; + ++num_keys_decoded; + } else if (name.equals("vendor")) { + vendor_name = value; + ++num_keys_decoded; + } else if (name.equals("endian")) { + byte_order = llvm::StringSwitch<lldb::ByteOrder>(value) + .Case("little", eByteOrderLittle) + .Case("big", eByteOrderBig) + .Case("pdp", eByteOrderPDP) + .Default(eByteOrderInvalid); + if (byte_order != eByteOrderInvalid) + ++num_keys_decoded; + } else if (name.equals("ptrsize")) { + if (!value.getAsInteger(16, pointer_byte_size)) + ++num_keys_decoded; + } else if (name.equals("pid")) { + if (!value.getAsInteger(16, pid)) + ++num_keys_decoded; + } else if (name.equals("elf_abi")) { + elf_abi = value; + ++num_keys_decoded; + } + } + if (num_keys_decoded > 0) + m_qProcessInfo_is_valid = eLazyBoolYes; + if (pid != LLDB_INVALID_PROCESS_ID) { + m_curr_pid_is_valid = eLazyBoolYes; + m_curr_pid = pid; + } + + // Set the ArchSpec from the triple if we have it. + if (!triple.empty()) { + m_process_arch.SetTriple(triple.c_str()); + m_process_arch.SetFlags(elf_abi); + if (pointer_byte_size) { + assert(pointer_byte_size == m_process_arch.GetAddressByteSize()); + } + } else if (cpu != LLDB_INVALID_CPUTYPE && !os_name.empty() && + !vendor_name.empty()) { + llvm::Triple triple(llvm::Twine("-") + vendor_name + "-" + os_name); + + assert(triple.getObjectFormat() != llvm::Triple::UnknownObjectFormat); + switch (triple.getObjectFormat()) { + case llvm::Triple::MachO: + m_process_arch.SetArchitecture(eArchTypeMachO, cpu, sub); + break; + case llvm::Triple::ELF: + m_process_arch.SetArchitecture(eArchTypeELF, cpu, sub); + break; + case llvm::Triple::COFF: + m_process_arch.SetArchitecture(eArchTypeCOFF, cpu, sub); + break; + case llvm::Triple::UnknownObjectFormat: + if (log) + log->Printf("error: failed to determine target architecture"); + return false; + } + + if (pointer_byte_size) { + assert(pointer_byte_size == m_process_arch.GetAddressByteSize()); + } + if (byte_order != eByteOrderInvalid) { + assert(byte_order == m_process_arch.GetByteOrder()); + } + m_process_arch.GetTriple().setVendorName(llvm::StringRef(vendor_name)); + m_process_arch.GetTriple().setOSName(llvm::StringRef(os_name)); + m_host_arch.GetTriple().setVendorName(llvm::StringRef(vendor_name)); + m_host_arch.GetTriple().setOSName(llvm::StringRef(os_name)); + } + return true; + } + } else { + m_qProcessInfo_is_valid = eLazyBoolNo; + } + + return false; +} + +uint32_t GDBRemoteCommunicationClient::FindProcesses( + const ProcessInstanceInfoMatch &match_info, + ProcessInstanceInfoList &process_infos) { + process_infos.Clear(); + + if (m_supports_qfProcessInfo) { StreamString packet; - packet.Printf ("qSpeedTest:response_size:%i;data:", recv_size); - uint32_t bytes_left = send_size; - while (bytes_left > 0) - { - if (bytes_left >= 26) - { - packet.PutCString("abcdefghijklmnopqrstuvwxyz"); - bytes_left -= 26; - } - else - { - packet.Printf ("%*.*s;", bytes_left, bytes_left, "abcdefghijklmnopqrstuvwxyz"); - bytes_left = 0; - } + packet.PutCString("qfProcessInfo"); + if (!match_info.MatchAllProcesses()) { + packet.PutChar(':'); + const char *name = match_info.GetProcessInfo().GetName(); + bool has_name_match = false; + if (name && name[0]) { + has_name_match = true; + NameMatchType name_match_type = match_info.GetNameMatchType(); + switch (name_match_type) { + case eNameMatchIgnore: + has_name_match = false; + break; + + case eNameMatchEquals: + packet.PutCString("name_match:equals;"); + break; + + case eNameMatchContains: + packet.PutCString("name_match:contains;"); + break; + + case eNameMatchStartsWith: + packet.PutCString("name_match:starts_with;"); + break; + + case eNameMatchEndsWith: + packet.PutCString("name_match:ends_with;"); + break; + + case eNameMatchRegularExpression: + packet.PutCString("name_match:regex;"); + break; + } + if (has_name_match) { + packet.PutCString("name:"); + packet.PutBytesAsRawHex8(name, ::strlen(name)); + packet.PutChar(';'); + } + } + + if (match_info.GetProcessInfo().ProcessIDIsValid()) + packet.Printf("pid:%" PRIu64 ";", + match_info.GetProcessInfo().GetProcessID()); + if (match_info.GetProcessInfo().ParentProcessIDIsValid()) + packet.Printf("parent_pid:%" PRIu64 ";", + match_info.GetProcessInfo().GetParentProcessID()); + if (match_info.GetProcessInfo().UserIDIsValid()) + packet.Printf("uid:%u;", match_info.GetProcessInfo().GetUserID()); + if (match_info.GetProcessInfo().GroupIDIsValid()) + packet.Printf("gid:%u;", match_info.GetProcessInfo().GetGroupID()); + if (match_info.GetProcessInfo().EffectiveUserIDIsValid()) + packet.Printf("euid:%u;", + match_info.GetProcessInfo().GetEffectiveUserID()); + if (match_info.GetProcessInfo().EffectiveGroupIDIsValid()) + packet.Printf("egid:%u;", + match_info.GetProcessInfo().GetEffectiveGroupID()); + if (match_info.GetProcessInfo().EffectiveGroupIDIsValid()) + packet.Printf("all_users:%u;", match_info.GetMatchAllUsers() ? 1 : 0); + if (match_info.GetProcessInfo().GetArchitecture().IsValid()) { + const ArchSpec &match_arch = + match_info.GetProcessInfo().GetArchitecture(); + const llvm::Triple &triple = match_arch.GetTriple(); + packet.PutCString("triple:"); + packet.PutCString(triple.getTriple()); + packet.PutChar(';'); + } } - StringExtractorGDBRemote response; - return SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success; -} - -bool -GDBRemoteCommunicationClient::LaunchGDBServer (const char *remote_accept_hostname, - lldb::pid_t &pid, - uint16_t &port, - std::string &socket_name) -{ - pid = LLDB_INVALID_PROCESS_ID; - port = 0; - socket_name.clear(); - + // Increase timeout as the first qfProcessInfo packet takes a long time + // on Android. The value of 1min was arrived at empirically. + ScopedTimeout timeout(*this, minutes(1)); + if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == + PacketResult::Success) { + do { + ProcessInstanceInfo process_info; + if (!DecodeProcessInfoResponse(response, process_info)) + break; + process_infos.Append(process_info); + response.GetStringRef().clear(); + response.SetFilePos(0); + } while (SendPacketAndWaitForResponse("qsProcessInfo", response, false) == + PacketResult::Success); + } else { + m_supports_qfProcessInfo = false; + return 0; + } + } + return process_infos.GetSize(); +} + +bool GDBRemoteCommunicationClient::GetUserName(uint32_t uid, + std::string &name) { + if (m_supports_qUserName) { + char packet[32]; + const int packet_len = + ::snprintf(packet, sizeof(packet), "qUserName:%i", uid); + assert(packet_len < (int)sizeof(packet)); + UNUSED_IF_ASSERT_DISABLED(packet_len); StringExtractorGDBRemote response; - StreamString stream; - stream.PutCString("qLaunchGDBServer;"); - std::string hostname; - if (remote_accept_hostname && remote_accept_hostname[0]) - hostname = remote_accept_hostname; + if (SendPacketAndWaitForResponse(packet, response, false) == + PacketResult::Success) { + if (response.IsNormalResponse()) { + // Make sure we parsed the right number of characters. The response is + // the hex encoded user name and should make up the entire packet. + // If there are any non-hex ASCII bytes, the length won't match below.. + if (response.GetHexByteString(name) * 2 == + response.GetStringRef().size()) + return true; + } + } else { + m_supports_qUserName = false; + return false; + } + } + return false; +} + +bool GDBRemoteCommunicationClient::GetGroupName(uint32_t gid, + std::string &name) { + if (m_supports_qGroupName) { + char packet[32]; + const int packet_len = + ::snprintf(packet, sizeof(packet), "qGroupName:%i", gid); + assert(packet_len < (int)sizeof(packet)); + UNUSED_IF_ASSERT_DISABLED(packet_len); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, response, false) == + PacketResult::Success) { + if (response.IsNormalResponse()) { + // Make sure we parsed the right number of characters. The response is + // the hex encoded group name and should make up the entire packet. + // If there are any non-hex ASCII bytes, the length won't match below.. + if (response.GetHexByteString(name) * 2 == + response.GetStringRef().size()) + return true; + } + } else { + m_supports_qGroupName = false; + return false; + } + } + return false; +} + +bool GDBRemoteCommunicationClient::SetNonStopMode(const bool enable) { + // Form non-stop packet request + char packet[32]; + const int packet_len = + ::snprintf(packet, sizeof(packet), "QNonStop:%1d", (int)enable); + assert(packet_len < (int)sizeof(packet)); + UNUSED_IF_ASSERT_DISABLED(packet_len); + + StringExtractorGDBRemote response; + // Send to target + if (SendPacketAndWaitForResponse(packet, response, false) == + PacketResult::Success) + if (response.IsOKResponse()) + return true; + + // Failed or not supported + return false; +} + +static void MakeSpeedTestPacket(StreamString &packet, uint32_t send_size, + uint32_t recv_size) { + packet.Clear(); + packet.Printf("qSpeedTest:response_size:%i;data:", recv_size); + uint32_t bytes_left = send_size; + while (bytes_left > 0) { + if (bytes_left >= 26) { + packet.PutCString("abcdefghijklmnopqrstuvwxyz"); + bytes_left -= 26; + } else { + packet.Printf("%*.*s;", bytes_left, bytes_left, + "abcdefghijklmnopqrstuvwxyz"); + bytes_left = 0; + } + } +} + +duration<float> +calculate_standard_deviation(const std::vector<duration<float>> &v) { + using Dur = duration<float>; + Dur sum = std::accumulate(std::begin(v), std::end(v), Dur()); + Dur mean = sum / v.size(); + float accum = 0; + for (auto d : v) { + float delta = (d - mean).count(); + accum += delta * delta; + }; + + return Dur(sqrtf(accum / (v.size() - 1))); +} + +void GDBRemoteCommunicationClient::TestPacketSpeed(const uint32_t num_packets, + uint32_t max_send, + uint32_t max_recv, + uint64_t recv_amount, + bool json, Stream &strm) { + uint32_t i; + if (SendSpeedTestPacket(0, 0)) { + StreamString packet; + if (json) + strm.Printf("{ \"packet_speeds\" : {\n \"num_packets\" : %u,\n " + "\"results\" : [", + num_packets); else - { - if (HostInfo::GetHostname(hostname)) - { - // Make the GDB server we launch only accept connections from this host - stream.Printf("host:%s;", hostname.c_str()); - } - else - { - // Make the GDB server we launch accept connections from any host since we can't figure out the hostname - stream.Printf("host:*;"); + strm.Printf("Testing sending %u packets of various sizes:\n", + num_packets); + strm.Flush(); + + uint32_t result_idx = 0; + uint32_t send_size; + std::vector<duration<float>> packet_times; + + for (send_size = 0; send_size <= max_send; + send_size ? send_size *= 2 : send_size = 4) { + for (uint32_t recv_size = 0; recv_size <= max_recv; + recv_size ? recv_size *= 2 : recv_size = 4) { + MakeSpeedTestPacket(packet, send_size, recv_size); + + packet_times.clear(); + // Test how long it takes to send 'num_packets' packets + const auto start_time = steady_clock::now(); + for (i = 0; i < num_packets; ++i) { + const auto packet_start_time = steady_clock::now(); + StringExtractorGDBRemote response; + SendPacketAndWaitForResponse(packet.GetString(), response, false); + const auto packet_end_time = steady_clock::now(); + packet_times.push_back(packet_end_time - packet_start_time); + } + const auto end_time = steady_clock::now(); + const auto total_time = end_time - start_time; + + float packets_per_second = + ((float)num_packets) / duration<float>(total_time).count(); + auto average_per_packet = total_time / num_packets; + const duration<float> standard_deviation = + calculate_standard_deviation(packet_times); + if (json) { + strm.Printf("%s\n {\"send_size\" : %6" PRIu32 + ", \"recv_size\" : %6" PRIu32 + ", \"total_time_nsec\" : %12" PRIu64 + ", \"standard_deviation_nsec\" : %9" PRIu64 " }", + result_idx > 0 ? "," : "", send_size, recv_size, + duration_cast<nanoseconds>(total_time).count(), + duration_cast<nanoseconds>(standard_deviation).count()); + ++result_idx; + } else { + strm.Printf( + "qSpeedTest(send=%-7u, recv=%-7u) in %.9f" + " sec for %9.2f packets/sec (%10.6f ms per packet) with standard " + "deviation of %10.6f ms\n", + send_size, recv_size, duration<float>(total_time).count(), + packets_per_second, + duration<float, std::milli>(average_per_packet).count(), + duration<float, std::milli>(standard_deviation).count()); } + strm.Flush(); + } } - const char *packet = stream.GetData(); - int packet_len = stream.GetSize(); - - // give the process a few seconds to startup - GDBRemoteCommunication::ScopedTimeout timeout (*this, 10); - if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) - { - std::string name; - std::string value; - StringExtractor extractor; - while (response.GetNameColonValue(name, value)) - { - if (name.compare("port") == 0) - port = StringConvert::ToUInt32(value.c_str(), 0, 0); - else if (name.compare("pid") == 0) - pid = StringConvert::ToUInt64(value.c_str(), LLDB_INVALID_PROCESS_ID, 0); - else if (name.compare("socket_name") == 0) - { - extractor.GetStringRef().swap(value); - extractor.SetFilePos(0); - extractor.GetHexByteString(value); - - socket_name = value; - } + const float k_recv_amount_mb = (float)recv_amount / (1024.0f * 1024.0f); + if (json) + strm.Printf("\n ]\n },\n \"download_speed\" : {\n \"byte_size\" " + ": %" PRIu64 ",\n \"results\" : [", + recv_amount); + else + strm.Printf("Testing receiving %2.1fMB of data using varying receive " + "packet sizes:\n", + k_recv_amount_mb); + strm.Flush(); + send_size = 0; + result_idx = 0; + for (uint32_t recv_size = 32; recv_size <= max_recv; recv_size *= 2) { + MakeSpeedTestPacket(packet, send_size, recv_size); + + // If we have a receive size, test how long it takes to receive 4MB of + // data + if (recv_size > 0) { + const auto start_time = steady_clock::now(); + uint32_t bytes_read = 0; + uint32_t packet_count = 0; + while (bytes_read < recv_amount) { + StringExtractorGDBRemote response; + SendPacketAndWaitForResponse(packet.GetString(), response, false); + bytes_read += recv_size; + ++packet_count; + } + const auto end_time = steady_clock::now(); + const auto total_time = end_time - start_time; + float mb_second = ((float)recv_amount) / + duration<float>(total_time).count() / + (1024.0 * 1024.0); + float packets_per_second = + ((float)packet_count) / duration<float>(total_time).count(); + const auto average_per_packet = total_time / packet_count; + + if (json) { + strm.Printf("%s\n {\"send_size\" : %6" PRIu32 + ", \"recv_size\" : %6" PRIu32 + ", \"total_time_nsec\" : %12" PRIu64 " }", + result_idx > 0 ? "," : "", send_size, recv_size, + duration_cast<nanoseconds>(total_time).count()); + ++result_idx; + } else { + strm.Printf("qSpeedTest(send=%-7u, recv=%-7u) %6u packets needed to " + "receive %2.1fMB in %.9f" + " sec for %f MB/sec for %9.2f packets/sec (%10.6f ms per " + "packet)\n", + send_size, recv_size, packet_count, k_recv_amount_mb, + duration<float>(total_time).count(), mb_second, + packets_per_second, + duration<float, std::milli>(average_per_packet).count()); } - return true; + strm.Flush(); + } } - return false; + if (json) + strm.Printf("\n ]\n }\n}\n"); + else + strm.EOL(); + } +} + +bool GDBRemoteCommunicationClient::SendSpeedTestPacket(uint32_t send_size, + uint32_t recv_size) { + StreamString packet; + packet.Printf("qSpeedTest:response_size:%i;data:", recv_size); + uint32_t bytes_left = send_size; + while (bytes_left > 0) { + if (bytes_left >= 26) { + packet.PutCString("abcdefghijklmnopqrstuvwxyz"); + bytes_left -= 26; + } else { + packet.Printf("%*.*s;", bytes_left, bytes_left, + "abcdefghijklmnopqrstuvwxyz"); + bytes_left = 0; + } + } + + StringExtractorGDBRemote response; + return SendPacketAndWaitForResponse(packet.GetString(), response, false) == + PacketResult::Success; +} + +bool GDBRemoteCommunicationClient::LaunchGDBServer( + const char *remote_accept_hostname, lldb::pid_t &pid, uint16_t &port, + std::string &socket_name) { + pid = LLDB_INVALID_PROCESS_ID; + port = 0; + socket_name.clear(); + + StringExtractorGDBRemote response; + StreamString stream; + stream.PutCString("qLaunchGDBServer;"); + std::string hostname; + if (remote_accept_hostname && remote_accept_hostname[0]) + hostname = remote_accept_hostname; + else { + if (HostInfo::GetHostname(hostname)) { + // Make the GDB server we launch only accept connections from this host + stream.Printf("host:%s;", hostname.c_str()); + } else { + // Make the GDB server we launch accept connections from any host since we + // can't figure out the hostname + stream.Printf("host:*;"); + } + } + // give the process a few seconds to startup + ScopedTimeout timeout(*this, seconds(10)); + + if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == + PacketResult::Success) { + llvm::StringRef name; + llvm::StringRef value; + while (response.GetNameColonValue(name, value)) { + if (name.equals("port")) + value.getAsInteger(0, port); + else if (name.equals("pid")) + value.getAsInteger(0, pid); + else if (name.compare("socket_name") == 0) { + StringExtractor extractor(value); + extractor.GetHexByteString(socket_name); + } + } + return true; + } + return false; } -size_t -GDBRemoteCommunicationClient::QueryGDBServer (std::vector<std::pair<uint16_t, std::string>>& connection_urls) -{ - connection_urls.clear(); +size_t GDBRemoteCommunicationClient::QueryGDBServer( + std::vector<std::pair<uint16_t, std::string>> &connection_urls) { + connection_urls.clear(); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("qQueryGDBServer", response, false) != PacketResult::Success) - return 0; + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse("qQueryGDBServer", response, false) != + PacketResult::Success) + return 0; - StructuredData::ObjectSP data = StructuredData::ParseJSON(response.GetStringRef()); - if (!data) - return 0; + StructuredData::ObjectSP data = + StructuredData::ParseJSON(response.GetStringRef()); + if (!data) + return 0; - StructuredData::Array* array = data->GetAsArray(); - if (!array) - return 0; + StructuredData::Array *array = data->GetAsArray(); + if (!array) + return 0; - for (size_t i = 0, count = array->GetSize(); i < count; ++i) - { - StructuredData::Dictionary* element = nullptr; - if (!array->GetItemAtIndexAsDictionary(i, element)) - continue; + for (size_t i = 0, count = array->GetSize(); i < count; ++i) { + StructuredData::Dictionary *element = nullptr; + if (!array->GetItemAtIndexAsDictionary(i, element)) + continue; - uint16_t port = 0; - if (StructuredData::ObjectSP port_osp = element->GetValueForKey(llvm::StringRef("port"))) - port = port_osp->GetIntegerValue(0); + uint16_t port = 0; + if (StructuredData::ObjectSP port_osp = + element->GetValueForKey(llvm::StringRef("port"))) + port = port_osp->GetIntegerValue(0); - std::string socket_name; - if (StructuredData::ObjectSP socket_name_osp = element->GetValueForKey(llvm::StringRef("socket_name"))) - socket_name = socket_name_osp->GetStringValue(); + std::string socket_name; + if (StructuredData::ObjectSP socket_name_osp = + element->GetValueForKey(llvm::StringRef("socket_name"))) + socket_name = socket_name_osp->GetStringValue(); - if (port != 0 || !socket_name.empty()) - connection_urls.emplace_back(port, socket_name); - } - return connection_urls.size(); + if (port != 0 || !socket_name.empty()) + connection_urls.emplace_back(port, socket_name); + } + return connection_urls.size(); } -bool -GDBRemoteCommunicationClient::KillSpawnedProcess (lldb::pid_t pid) -{ - StreamString stream; - stream.Printf ("qKillSpawnedProcess:%" PRId64 , pid); - const char *packet = stream.GetData(); - int packet_len = stream.GetSize(); +bool GDBRemoteCommunicationClient::KillSpawnedProcess(lldb::pid_t pid) { + StreamString stream; + stream.Printf("qKillSpawnedProcess:%" PRId64, pid); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - return true; - } - return false; + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == + PacketResult::Success) { + if (response.IsOKResponse()) + return true; + } + return false; } -bool -GDBRemoteCommunicationClient::SetCurrentThread (uint64_t tid) -{ - if (m_curr_tid == tid) - return true; - - char packet[32]; - int packet_len; - if (tid == UINT64_MAX) - packet_len = ::snprintf (packet, sizeof(packet), "Hg-1"); - else - packet_len = ::snprintf (packet, sizeof(packet), "Hg%" PRIx64, tid); - assert (packet_len + 1 < (int)sizeof(packet)); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - { - m_curr_tid = tid; - return true; - } +bool GDBRemoteCommunicationClient::SetCurrentThread(uint64_t tid) { + if (m_curr_tid == tid) + return true; - /* - * Connected bare-iron target (like YAMON gdb-stub) may not have support for Hg packet. - * The reply from '?' packet could be as simple as 'S05'. There is no packet which can - * give us pid and/or tid. Assume pid=tid=1 in such cases. - */ - if (response.IsUnsupportedResponse() && IsConnected()) - { - m_curr_tid = 1; - return true; - } - } - return false; -} + char packet[32]; + int packet_len; + if (tid == UINT64_MAX) + packet_len = ::snprintf(packet, sizeof(packet), "Hg-1"); + else + packet_len = ::snprintf(packet, sizeof(packet), "Hg%" PRIx64, tid); + assert(packet_len + 1 < (int)sizeof(packet)); + UNUSED_IF_ASSERT_DISABLED(packet_len); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, response, false) == + PacketResult::Success) { + if (response.IsOKResponse()) { + m_curr_tid = tid; + return true; + } + + /* + * Connected bare-iron target (like YAMON gdb-stub) may not have support for + * Hg packet. + * The reply from '?' packet could be as simple as 'S05'. There is no packet + * which can + * give us pid and/or tid. Assume pid=tid=1 in such cases. + */ + if (response.IsUnsupportedResponse() && IsConnected()) { + m_curr_tid = 1; + return true; + } + } + return false; +} + +bool GDBRemoteCommunicationClient::SetCurrentThreadForRun(uint64_t tid) { + if (m_curr_tid_run == tid) + return true; -bool -GDBRemoteCommunicationClient::SetCurrentThreadForRun (uint64_t tid) -{ - if (m_curr_tid_run == tid) + char packet[32]; + int packet_len; + if (tid == UINT64_MAX) + packet_len = ::snprintf(packet, sizeof(packet), "Hc-1"); + else + packet_len = ::snprintf(packet, sizeof(packet), "Hc%" PRIx64, tid); + + assert(packet_len + 1 < (int)sizeof(packet)); + UNUSED_IF_ASSERT_DISABLED(packet_len); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, response, false) == + PacketResult::Success) { + if (response.IsOKResponse()) { + m_curr_tid_run = tid; + return true; + } + + /* + * Connected bare-iron target (like YAMON gdb-stub) may not have support for + * Hc packet. + * The reply from '?' packet could be as simple as 'S05'. There is no packet + * which can + * give us pid and/or tid. Assume pid=tid=1 in such cases. + */ + if (response.IsUnsupportedResponse() && IsConnected()) { + m_curr_tid_run = 1; + return true; + } + } + return false; +} + +bool GDBRemoteCommunicationClient::GetStopReply( + StringExtractorGDBRemote &response) { + if (SendPacketAndWaitForResponse("?", response, false) == + PacketResult::Success) + return response.IsNormalResponse(); + return false; +} + +bool GDBRemoteCommunicationClient::GetThreadStopInfo( + lldb::tid_t tid, StringExtractorGDBRemote &response) { + if (m_supports_qThreadStopInfo) { + char packet[256]; + int packet_len = + ::snprintf(packet, sizeof(packet), "qThreadStopInfo%" PRIx64, tid); + assert(packet_len < (int)sizeof(packet)); + UNUSED_IF_ASSERT_DISABLED(packet_len); + if (SendPacketAndWaitForResponse(packet, response, false) == + PacketResult::Success) { + if (response.IsUnsupportedResponse()) + m_supports_qThreadStopInfo = false; + else if (response.IsNormalResponse()) return true; - - char packet[32]; - int packet_len; - if (tid == UINT64_MAX) - packet_len = ::snprintf (packet, sizeof(packet), "Hc-1"); - else - packet_len = ::snprintf (packet, sizeof(packet), "Hc%" PRIx64, tid); - - assert (packet_len + 1 < (int)sizeof(packet)); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - { - m_curr_tid_run = tid; - return true; - } - - /* - * Connected bare-iron target (like YAMON gdb-stub) may not have support for Hc packet. - * The reply from '?' packet could be as simple as 'S05'. There is no packet which can - * give us pid and/or tid. Assume pid=tid=1 in such cases. - */ - if (response.IsUnsupportedResponse() && IsConnected()) - { - m_curr_tid_run = 1; - return true; - } + else + return false; + } else { + m_supports_qThreadStopInfo = false; } - return false; + } + return false; } -bool -GDBRemoteCommunicationClient::GetStopReply (StringExtractorGDBRemote &response) -{ - if (SendPacketAndWaitForResponse("?", 1, response, false) == PacketResult::Success) - return response.IsNormalResponse(); - return false; -} +uint8_t GDBRemoteCommunicationClient::SendGDBStoppointTypePacket( + GDBStoppointType type, bool insert, addr_t addr, uint32_t length) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + if (log) + log->Printf("GDBRemoteCommunicationClient::%s() %s at addr = 0x%" PRIx64, + __FUNCTION__, insert ? "add" : "remove", addr); -bool -GDBRemoteCommunicationClient::GetThreadStopInfo (lldb::tid_t tid, StringExtractorGDBRemote &response) -{ - if (m_supports_qThreadStopInfo) - { - char packet[256]; - int packet_len = ::snprintf(packet, sizeof(packet), "qThreadStopInfo%" PRIx64, tid); - assert (packet_len < (int)sizeof(packet)); - if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) - { - if (response.IsUnsupportedResponse()) - m_supports_qThreadStopInfo = false; - else if (response.IsNormalResponse()) - return true; - else - return false; - } - else - { - m_supports_qThreadStopInfo = false; - } + // Check if the stub is known not to support this breakpoint type + if (!SupportsGDBStoppointPacket(type)) + return UINT8_MAX; + // Construct the breakpoint packet + char packet[64]; + const int packet_len = + ::snprintf(packet, sizeof(packet), "%c%i,%" PRIx64 ",%x", + insert ? 'Z' : 'z', type, addr, length); + // Check we haven't overwritten the end of the packet buffer + assert(packet_len + 1 < (int)sizeof(packet)); + UNUSED_IF_ASSERT_DISABLED(packet_len); + StringExtractorGDBRemote response; + // Make sure the response is either "OK", "EXX" where XX are two hex digits, + // or "" (unsupported) + response.SetResponseValidatorToOKErrorNotSupported(); + // Try to send the breakpoint packet, and check that it was correctly sent + if (SendPacketAndWaitForResponse(packet, response, true) == + PacketResult::Success) { + // Receive and OK packet when the breakpoint successfully placed + if (response.IsOKResponse()) + return 0; + + // Error while setting breakpoint, send back specific error + if (response.IsErrorResponse()) + return response.GetError(); + + // Empty packet informs us that breakpoint is not supported + if (response.IsUnsupportedResponse()) { + // Disable this breakpoint type since it is unsupported + switch (type) { + case eBreakpointSoftware: + m_supports_z0 = false; + break; + case eBreakpointHardware: + m_supports_z1 = false; + break; + case eWatchpointWrite: + m_supports_z2 = false; + break; + case eWatchpointRead: + m_supports_z3 = false; + break; + case eWatchpointReadWrite: + m_supports_z4 = false; + break; + case eStoppointInvalid: + return UINT8_MAX; + } } - return false; + } + // Signal generic failure + return UINT8_MAX; } +size_t GDBRemoteCommunicationClient::GetCurrentThreadIDs( + std::vector<lldb::tid_t> &thread_ids, bool &sequence_mutex_unavailable) { + thread_ids.clear(); -uint8_t -GDBRemoteCommunicationClient::SendGDBStoppointTypePacket (GDBStoppointType type, bool insert, addr_t addr, uint32_t length) -{ - Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); - if (log) - log->Printf ("GDBRemoteCommunicationClient::%s() %s at addr = 0x%" PRIx64, - __FUNCTION__, insert ? "add" : "remove", addr); - - // Check if the stub is known not to support this breakpoint type - if (!SupportsGDBStoppointPacket(type)) - return UINT8_MAX; - // Construct the breakpoint packet - char packet[64]; - const int packet_len = ::snprintf (packet, - sizeof(packet), - "%c%i,%" PRIx64 ",%x", - insert ? 'Z' : 'z', - type, - addr, - length); - // Check we haven't overwritten the end of the packet buffer - assert (packet_len + 1 < (int)sizeof(packet)); + Lock lock(*this, false); + if (lock) { + sequence_mutex_unavailable = false; StringExtractorGDBRemote response; - // Make sure the response is either "OK", "EXX" where XX are two hex digits, or "" (unsupported) - response.SetResponseValidatorToOKErrorNotSupported(); - // Try to send the breakpoint packet, and check that it was correctly sent - if (SendPacketAndWaitForResponse(packet, packet_len, response, true) == PacketResult::Success) - { - // Receive and OK packet when the breakpoint successfully placed - if (response.IsOKResponse()) - return 0; - - // Error while setting breakpoint, send back specific error - if (response.IsErrorResponse()) - return response.GetError(); - - // Empty packet informs us that breakpoint is not supported - if (response.IsUnsupportedResponse()) - { - // Disable this breakpoint type since it is unsupported - switch (type) - { - case eBreakpointSoftware: m_supports_z0 = false; break; - case eBreakpointHardware: m_supports_z1 = false; break; - case eWatchpointWrite: m_supports_z2 = false; break; - case eWatchpointRead: m_supports_z3 = false; break; - case eWatchpointReadWrite: m_supports_z4 = false; break; - case eStoppointInvalid: return UINT8_MAX; - } - } - } - // Signal generic failure - return UINT8_MAX; -} - -size_t -GDBRemoteCommunicationClient::GetCurrentThreadIDs (std::vector<lldb::tid_t> &thread_ids, - bool &sequence_mutex_unavailable) -{ - Mutex::Locker locker; - thread_ids.clear(); - - if (GetSequenceMutex (locker, "ProcessGDBRemote::UpdateThreadList() failed due to not getting the sequence mutex")) - { - sequence_mutex_unavailable = false; - StringExtractorGDBRemote response; - - PacketResult packet_result; - for (packet_result = SendPacketAndWaitForResponseNoLock ("qfThreadInfo", strlen("qfThreadInfo"), response); - packet_result == PacketResult::Success && response.IsNormalResponse(); - packet_result = SendPacketAndWaitForResponseNoLock ("qsThreadInfo", strlen("qsThreadInfo"), response)) - { - char ch = response.GetChar(); - if (ch == 'l') - break; - if (ch == 'm') - { - do - { - tid_t tid = response.GetHexMaxU64(false, LLDB_INVALID_THREAD_ID); - - if (tid != LLDB_INVALID_THREAD_ID) - { - thread_ids.push_back (tid); - } - ch = response.GetChar(); // Skip the command separator - } while (ch == ','); // Make sure we got a comma separator - } - } - /* - * Connected bare-iron target (like YAMON gdb-stub) may not have support for - * qProcessInfo, qC and qfThreadInfo packets. The reply from '?' packet could - * be as simple as 'S05'. There is no packet which can give us pid and/or tid. - * Assume pid=tid=1 in such cases. - */ - if (response.IsUnsupportedResponse() && thread_ids.size() == 0 && IsConnected()) - { - thread_ids.push_back (1); - } - } - else - { -#if defined (LLDB_CONFIGURATION_DEBUG) - // assert(!"ProcessGDBRemote::UpdateThreadList() failed due to not getting the sequence mutex"); -#else - Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_PROCESS | GDBR_LOG_PACKETS)); - if (log) - log->Printf("error: failed to get packet sequence mutex, not sending packet 'qfThreadInfo'"); + PacketResult packet_result; + for (packet_result = + SendPacketAndWaitForResponseNoLock("qfThreadInfo", response); + packet_result == PacketResult::Success && response.IsNormalResponse(); + packet_result = + SendPacketAndWaitForResponseNoLock("qsThreadInfo", response)) { + char ch = response.GetChar(); + if (ch == 'l') + break; + if (ch == 'm') { + do { + tid_t tid = response.GetHexMaxU64(false, LLDB_INVALID_THREAD_ID); + + if (tid != LLDB_INVALID_THREAD_ID) { + thread_ids.push_back(tid); + } + ch = response.GetChar(); // Skip the command separator + } while (ch == ','); // Make sure we got a comma separator + } + } + + /* + * Connected bare-iron target (like YAMON gdb-stub) may not have support for + * qProcessInfo, qC and qfThreadInfo packets. The reply from '?' packet + * could + * be as simple as 'S05'. There is no packet which can give us pid and/or + * tid. + * Assume pid=tid=1 in such cases. + */ + if (response.IsUnsupportedResponse() && thread_ids.size() == 0 && + IsConnected()) { + thread_ids.push_back(1); + } + } else { +#if !defined(LLDB_CONFIGURATION_DEBUG) + Log *log(ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(GDBR_LOG_PROCESS | + GDBR_LOG_PACKETS)); + if (log) + log->Printf("error: failed to get packet sequence mutex, not sending " + "packet 'qfThreadInfo'"); #endif - sequence_mutex_unavailable = true; - } - return thread_ids.size(); + sequence_mutex_unavailable = true; + } + return thread_ids.size(); } -lldb::addr_t -GDBRemoteCommunicationClient::GetShlibInfoAddr() -{ - if (!IsRunning()) - { - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("qShlibInfoAddr", ::strlen ("qShlibInfoAddr"), response, false) == PacketResult::Success) - { - if (response.IsNormalResponse()) - return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS); - } - } +lldb::addr_t GDBRemoteCommunicationClient::GetShlibInfoAddr() { + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse("qShlibInfoAddr", response, false) != + PacketResult::Success || + !response.IsNormalResponse()) return LLDB_INVALID_ADDRESS; -} - -lldb_private::Error -GDBRemoteCommunicationClient::RunShellCommand(const char *command, // Shouldn't be NULL - const FileSpec &working_dir, // Pass empty FileSpec to use the current working directory - int *status_ptr, // Pass NULL if you don't want the process exit status - int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit - std::string *command_output, // Pass NULL if you don't want the command output - uint32_t timeout_sec) // Timeout in seconds to wait for shell program to finish -{ - lldb_private::StreamString stream; - stream.PutCString("qPlatform_shell:"); - stream.PutBytesAsRawHex8(command, strlen(command)); - stream.PutChar(','); - stream.PutHex32(timeout_sec); - if (working_dir) - { - std::string path{working_dir.GetPath(false)}; - stream.PutChar(','); - stream.PutCStringAsRawHex8(path.c_str()); - } - const char *packet = stream.GetData(); - int packet_len = stream.GetSize(); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) - { - if (response.GetChar() != 'F') - return Error("malformed reply"); - if (response.GetChar() != ',') - return Error("malformed reply"); - uint32_t exitcode = response.GetHexMaxU32(false, UINT32_MAX); - if (exitcode == UINT32_MAX) - return Error("unable to run remote process"); - else if (status_ptr) - *status_ptr = exitcode; - if (response.GetChar() != ',') - return Error("malformed reply"); - uint32_t signo = response.GetHexMaxU32(false, UINT32_MAX); - if (signo_ptr) - *signo_ptr = signo; - if (response.GetChar() != ',') - return Error("malformed reply"); - std::string output; - response.GetEscapedBinaryData(output); - if (command_output) - command_output->assign(output); - return Error(); - } - return Error("unable to send packet"); -} - -Error -GDBRemoteCommunicationClient::MakeDirectory(const FileSpec &file_spec, - uint32_t file_permissions) -{ - std::string path{file_spec.GetPath(false)}; - lldb_private::StreamString stream; - stream.PutCString("qPlatform_mkdir:"); - stream.PutHex32(file_permissions); + return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS); +} + +lldb_private::Error GDBRemoteCommunicationClient::RunShellCommand( + const char *command, // Shouldn't be NULL + const FileSpec & + working_dir, // Pass empty FileSpec to use the current working directory + int *status_ptr, // Pass NULL if you don't want the process exit status + int *signo_ptr, // Pass NULL if you don't want the signal that caused the + // process to exit + std::string + *command_output, // Pass NULL if you don't want the command output + uint32_t + timeout_sec) // Timeout in seconds to wait for shell program to finish +{ + lldb_private::StreamString stream; + stream.PutCString("qPlatform_shell:"); + stream.PutBytesAsRawHex8(command, strlen(command)); + stream.PutChar(','); + stream.PutHex32(timeout_sec); + if (working_dir) { + std::string path{working_dir.GetPath(false)}; stream.PutChar(','); stream.PutCStringAsRawHex8(path.c_str()); - const char *packet = stream.GetData(); - int packet_len = stream.GetSize(); - StringExtractorGDBRemote response; - - if (SendPacketAndWaitForResponse(packet, packet_len, response, false) != PacketResult::Success) - return Error("failed to send '%s' packet", packet); - + } + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == + PacketResult::Success) { if (response.GetChar() != 'F') - return Error("invalid response to '%s' packet", packet); - - return Error(response.GetU32(UINT32_MAX), eErrorTypePOSIX); -} - -Error -GDBRemoteCommunicationClient::SetFilePermissions(const FileSpec &file_spec, - uint32_t file_permissions) -{ - std::string path{file_spec.GetPath(false)}; - lldb_private::StreamString stream; - stream.PutCString("qPlatform_chmod:"); - stream.PutHex32(file_permissions); - stream.PutChar(','); - stream.PutCStringAsRawHex8(path.c_str()); - const char *packet = stream.GetData(); - int packet_len = stream.GetSize(); - StringExtractorGDBRemote response; - - if (SendPacketAndWaitForResponse(packet, packet_len, response, false) != PacketResult::Success) - return Error("failed to send '%s' packet", packet); - - if (response.GetChar() != 'F') - return Error("invalid response to '%s' packet", packet); - - return Error(response.GetU32(UINT32_MAX), eErrorTypePOSIX); -} - -static uint64_t -ParseHostIOPacketResponse (StringExtractorGDBRemote &response, - uint64_t fail_result, - Error &error) -{ - response.SetFilePos(0); - if (response.GetChar() != 'F') - return fail_result; - int32_t result = response.GetS32 (-2); - if (result == -2) - return fail_result; - if (response.GetChar() == ',') - { - int result_errno = response.GetS32 (-2); - if (result_errno != -2) - error.SetError(result_errno, eErrorTypePOSIX); - else - error.SetError(-1, eErrorTypeGeneric); - } + return Error("malformed reply"); + if (response.GetChar() != ',') + return Error("malformed reply"); + uint32_t exitcode = response.GetHexMaxU32(false, UINT32_MAX); + if (exitcode == UINT32_MAX) + return Error("unable to run remote process"); + else if (status_ptr) + *status_ptr = exitcode; + if (response.GetChar() != ',') + return Error("malformed reply"); + uint32_t signo = response.GetHexMaxU32(false, UINT32_MAX); + if (signo_ptr) + *signo_ptr = signo; + if (response.GetChar() != ',') + return Error("malformed reply"); + std::string output; + response.GetEscapedBinaryData(output); + if (command_output) + command_output->assign(output); + return Error(); + } + return Error("unable to send packet"); +} + +Error GDBRemoteCommunicationClient::MakeDirectory(const FileSpec &file_spec, + uint32_t file_permissions) { + std::string path{file_spec.GetPath(false)}; + lldb_private::StreamString stream; + stream.PutCString("qPlatform_mkdir:"); + stream.PutHex32(file_permissions); + stream.PutChar(','); + stream.PutCStringAsRawHex8(path.c_str()); + llvm::StringRef packet = stream.GetString(); + StringExtractorGDBRemote response; + + if (SendPacketAndWaitForResponse(packet, response, false) != + PacketResult::Success) + return Error("failed to send '%s' packet", packet.str().c_str()); + + if (response.GetChar() != 'F') + return Error("invalid response to '%s' packet", packet.str().c_str()); + + return Error(response.GetU32(UINT32_MAX), eErrorTypePOSIX); +} + +Error GDBRemoteCommunicationClient::SetFilePermissions( + const FileSpec &file_spec, uint32_t file_permissions) { + std::string path{file_spec.GetPath(false)}; + lldb_private::StreamString stream; + stream.PutCString("qPlatform_chmod:"); + stream.PutHex32(file_permissions); + stream.PutChar(','); + stream.PutCStringAsRawHex8(path.c_str()); + llvm::StringRef packet = stream.GetString(); + StringExtractorGDBRemote response; + + if (SendPacketAndWaitForResponse(packet, response, false) != + PacketResult::Success) + return Error("failed to send '%s' packet", stream.GetData()); + + if (response.GetChar() != 'F') + return Error("invalid response to '%s' packet", stream.GetData()); + + return Error(response.GetU32(UINT32_MAX), eErrorTypePOSIX); +} + +static uint64_t ParseHostIOPacketResponse(StringExtractorGDBRemote &response, + uint64_t fail_result, Error &error) { + response.SetFilePos(0); + if (response.GetChar() != 'F') + return fail_result; + int32_t result = response.GetS32(-2); + if (result == -2) + return fail_result; + if (response.GetChar() == ',') { + int result_errno = response.GetS32(-2); + if (result_errno != -2) + error.SetError(result_errno, eErrorTypePOSIX); else - error.Clear(); - return result; + error.SetError(-1, eErrorTypeGeneric); + } else + error.Clear(); + return result; } lldb::user_id_t -GDBRemoteCommunicationClient::OpenFile (const lldb_private::FileSpec& file_spec, - uint32_t flags, - mode_t mode, - Error &error) -{ - std::string path(file_spec.GetPath(false)); - lldb_private::StreamString stream; - stream.PutCString("vFile:open:"); - if (path.empty()) - return UINT64_MAX; - stream.PutCStringAsRawHex8(path.c_str()); - stream.PutChar(','); - stream.PutHex32(flags); - stream.PutChar(','); - stream.PutHex32(mode); - const char* packet = stream.GetData(); - int packet_len = stream.GetSize(); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) - { - return ParseHostIOPacketResponse (response, UINT64_MAX, error); - } +GDBRemoteCommunicationClient::OpenFile(const lldb_private::FileSpec &file_spec, + uint32_t flags, mode_t mode, + Error &error) { + std::string path(file_spec.GetPath(false)); + lldb_private::StreamString stream; + stream.PutCString("vFile:open:"); + if (path.empty()) return UINT64_MAX; -} - -bool -GDBRemoteCommunicationClient::CloseFile (lldb::user_id_t fd, - Error &error) -{ - lldb_private::StreamString stream; - stream.Printf("vFile:close:%i", (int)fd); - const char* packet = stream.GetData(); - int packet_len = stream.GetSize(); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) - { - return ParseHostIOPacketResponse (response, -1, error) == 0; - } - return false; + stream.PutCStringAsRawHex8(path.c_str()); + stream.PutChar(','); + stream.PutHex32(flags); + stream.PutChar(','); + stream.PutHex32(mode); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == + PacketResult::Success) { + return ParseHostIOPacketResponse(response, UINT64_MAX, error); + } + return UINT64_MAX; +} + +bool GDBRemoteCommunicationClient::CloseFile(lldb::user_id_t fd, Error &error) { + lldb_private::StreamString stream; + stream.Printf("vFile:close:%i", (int)fd); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == + PacketResult::Success) { + return ParseHostIOPacketResponse(response, -1, error) == 0; + } + return false; } // Extension of host I/O packets to get the file size. -lldb::user_id_t -GDBRemoteCommunicationClient::GetFileSize (const lldb_private::FileSpec& file_spec) -{ - std::string path(file_spec.GetPath(false)); - lldb_private::StreamString stream; - stream.PutCString("vFile:size:"); - stream.PutCStringAsRawHex8(path.c_str()); - const char* packet = stream.GetData(); - int packet_len = stream.GetSize(); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) - { - if (response.GetChar() != 'F') - return UINT64_MAX; - uint32_t retcode = response.GetHexMaxU64(false, UINT64_MAX); - return retcode; - } - return UINT64_MAX; +lldb::user_id_t GDBRemoteCommunicationClient::GetFileSize( + const lldb_private::FileSpec &file_spec) { + std::string path(file_spec.GetPath(false)); + lldb_private::StreamString stream; + stream.PutCString("vFile:size:"); + stream.PutCStringAsRawHex8(path.c_str()); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == + PacketResult::Success) { + if (response.GetChar() != 'F') + return UINT64_MAX; + uint32_t retcode = response.GetHexMaxU64(false, UINT64_MAX); + return retcode; + } + return UINT64_MAX; +} + +Error GDBRemoteCommunicationClient::GetFilePermissions( + const FileSpec &file_spec, uint32_t &file_permissions) { + std::string path{file_spec.GetPath(false)}; + Error error; + lldb_private::StreamString stream; + stream.PutCString("vFile:mode:"); + stream.PutCStringAsRawHex8(path.c_str()); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == + PacketResult::Success) { + if (response.GetChar() != 'F') { + error.SetErrorStringWithFormat("invalid response to '%s' packet", + stream.GetData()); + } else { + const uint32_t mode = response.GetS32(-1); + if (static_cast<int32_t>(mode) == -1) { + if (response.GetChar() == ',') { + int response_errno = response.GetS32(-1); + if (response_errno > 0) + error.SetError(response_errno, lldb::eErrorTypePOSIX); + else + error.SetErrorToGenericError(); + } else + error.SetErrorToGenericError(); + } else { + file_permissions = mode & (S_IRWXU | S_IRWXG | S_IRWXO); + } + } + } else { + error.SetErrorStringWithFormat("failed to send '%s' packet", + stream.GetData()); + } + return error; +} + +uint64_t GDBRemoteCommunicationClient::ReadFile(lldb::user_id_t fd, + uint64_t offset, void *dst, + uint64_t dst_len, + Error &error) { + lldb_private::StreamString stream; + stream.Printf("vFile:pread:%i,%" PRId64 ",%" PRId64, (int)fd, dst_len, + offset); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == + PacketResult::Success) { + if (response.GetChar() != 'F') + return 0; + uint32_t retcode = response.GetHexMaxU32(false, UINT32_MAX); + if (retcode == UINT32_MAX) + return retcode; + const char next = (response.Peek() ? *response.Peek() : 0); + if (next == ',') + return 0; + if (next == ';') { + response.GetChar(); // skip the semicolon + std::string buffer; + if (response.GetEscapedBinaryData(buffer)) { + const uint64_t data_to_write = + std::min<uint64_t>(dst_len, buffer.size()); + if (data_to_write > 0) + memcpy(dst, &buffer[0], data_to_write); + return data_to_write; + } + } + } + return 0; +} + +uint64_t GDBRemoteCommunicationClient::WriteFile(lldb::user_id_t fd, + uint64_t offset, + const void *src, + uint64_t src_len, + Error &error) { + lldb_private::StreamGDBRemote stream; + stream.Printf("vFile:pwrite:%i,%" PRId64 ",", (int)fd, offset); + stream.PutEscapedBytes(src, src_len); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == + PacketResult::Success) { + if (response.GetChar() != 'F') { + error.SetErrorStringWithFormat("write file failed"); + return 0; + } + uint64_t bytes_written = response.GetU64(UINT64_MAX); + if (bytes_written == UINT64_MAX) { + error.SetErrorToGenericError(); + if (response.GetChar() == ',') { + int response_errno = response.GetS32(-1); + if (response_errno > 0) + error.SetError(response_errno, lldb::eErrorTypePOSIX); + } + return 0; + } + return bytes_written; + } else { + error.SetErrorString("failed to send vFile:pwrite packet"); + } + return 0; +} + +Error GDBRemoteCommunicationClient::CreateSymlink(const FileSpec &src, + const FileSpec &dst) { + std::string src_path{src.GetPath(false)}, dst_path{dst.GetPath(false)}; + Error error; + lldb_private::StreamGDBRemote stream; + stream.PutCString("vFile:symlink:"); + // the unix symlink() command reverses its parameters where the dst if first, + // so we follow suit here + stream.PutCStringAsRawHex8(dst_path.c_str()); + stream.PutChar(','); + stream.PutCStringAsRawHex8(src_path.c_str()); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == + PacketResult::Success) { + if (response.GetChar() == 'F') { + uint32_t result = response.GetU32(UINT32_MAX); + if (result != 0) { + error.SetErrorToGenericError(); + if (response.GetChar() == ',') { + int response_errno = response.GetS32(-1); + if (response_errno > 0) + error.SetError(response_errno, lldb::eErrorTypePOSIX); + } + } + } else { + // Should have returned with 'F<result>[,<errno>]' + error.SetErrorStringWithFormat("symlink failed"); + } + } else { + error.SetErrorString("failed to send vFile:symlink packet"); + } + return error; +} + +Error GDBRemoteCommunicationClient::Unlink(const FileSpec &file_spec) { + std::string path{file_spec.GetPath(false)}; + Error error; + lldb_private::StreamGDBRemote stream; + stream.PutCString("vFile:unlink:"); + // the unix symlink() command reverses its parameters where the dst if first, + // so we follow suit here + stream.PutCStringAsRawHex8(path.c_str()); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == + PacketResult::Success) { + if (response.GetChar() == 'F') { + uint32_t result = response.GetU32(UINT32_MAX); + if (result != 0) { + error.SetErrorToGenericError(); + if (response.GetChar() == ',') { + int response_errno = response.GetS32(-1); + if (response_errno > 0) + error.SetError(response_errno, lldb::eErrorTypePOSIX); + } + } + } else { + // Should have returned with 'F<result>[,<errno>]' + error.SetErrorStringWithFormat("unlink failed"); + } + } else { + error.SetErrorString("failed to send vFile:unlink packet"); + } + return error; } -Error -GDBRemoteCommunicationClient::GetFilePermissions(const FileSpec &file_spec, - uint32_t &file_permissions) -{ - std::string path{file_spec.GetPath(false)}; - Error error; - lldb_private::StreamString stream; - stream.PutCString("vFile:mode:"); - stream.PutCStringAsRawHex8(path.c_str()); - const char* packet = stream.GetData(); - int packet_len = stream.GetSize(); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) - { - if (response.GetChar() != 'F') - { - error.SetErrorStringWithFormat ("invalid response to '%s' packet", packet); - } - else - { - const uint32_t mode = response.GetS32(-1); - if (static_cast<int32_t>(mode) == -1) - { - if (response.GetChar() == ',') - { - int response_errno = response.GetS32(-1); - if (response_errno > 0) - error.SetError(response_errno, lldb::eErrorTypePOSIX); - else - error.SetErrorToGenericError(); - } - else - error.SetErrorToGenericError(); - } - else - { - file_permissions = mode & (S_IRWXU|S_IRWXG|S_IRWXO); - } - } - } - else - { - error.SetErrorStringWithFormat ("failed to send '%s' packet", packet); - } - return error; -} +// Extension of host I/O packets to get whether a file exists. +bool GDBRemoteCommunicationClient::GetFileExists( + const lldb_private::FileSpec &file_spec) { + std::string path(file_spec.GetPath(false)); + lldb_private::StreamString stream; + stream.PutCString("vFile:exists:"); + stream.PutCStringAsRawHex8(path.c_str()); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == + PacketResult::Success) { + if (response.GetChar() != 'F') + return false; + if (response.GetChar() != ',') + return false; + bool retcode = (response.GetChar() != '0'); + return retcode; + } + return false; +} + +bool GDBRemoteCommunicationClient::CalculateMD5( + const lldb_private::FileSpec &file_spec, uint64_t &high, uint64_t &low) { + std::string path(file_spec.GetPath(false)); + lldb_private::StreamString stream; + stream.PutCString("vFile:MD5:"); + stream.PutCStringAsRawHex8(path.c_str()); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == + PacketResult::Success) { + if (response.GetChar() != 'F') + return false; + if (response.GetChar() != ',') + return false; + if (response.Peek() && *response.Peek() == 'x') + return false; + low = response.GetHexMaxU64(false, UINT64_MAX); + high = response.GetHexMaxU64(false, UINT64_MAX); + return true; + } + return false; +} + +bool GDBRemoteCommunicationClient::AvoidGPackets(ProcessGDBRemote *process) { + // Some targets have issues with g/G packets and we need to avoid using them + if (m_avoid_g_packets == eLazyBoolCalculate) { + if (process) { + m_avoid_g_packets = eLazyBoolNo; + const ArchSpec &arch = process->GetTarget().GetArchitecture(); + if (arch.IsValid() && + arch.GetTriple().getVendor() == llvm::Triple::Apple && + arch.GetTriple().getOS() == llvm::Triple::IOS && + arch.GetTriple().getArch() == llvm::Triple::aarch64) { + m_avoid_g_packets = eLazyBoolYes; + uint32_t gdb_server_version = GetGDBServerProgramVersion(); + if (gdb_server_version != 0) { + const char *gdb_server_name = GetGDBServerProgramName(); + if (gdb_server_name && strcmp(gdb_server_name, "debugserver") == 0) { + if (gdb_server_version >= 310) + m_avoid_g_packets = eLazyBoolNo; + } + } + } + } + } + return m_avoid_g_packets == eLazyBoolYes; +} + +DataBufferSP GDBRemoteCommunicationClient::ReadRegister(lldb::tid_t tid, + uint32_t reg) { + StreamString payload; + payload.Printf("p%x", reg); + StringExtractorGDBRemote response; + if (SendThreadSpecificPacketAndWaitForResponse( + tid, std::move(payload), response, false) != PacketResult::Success || + !response.IsNormalResponse()) + return nullptr; + + DataBufferSP buffer_sp( + new DataBufferHeap(response.GetStringRef().size() / 2, 0)); + response.GetHexBytes(buffer_sp->GetData(), '\xcc'); + return buffer_sp; +} + +DataBufferSP GDBRemoteCommunicationClient::ReadAllRegisters(lldb::tid_t tid) { + StreamString payload; + payload.PutChar('g'); + StringExtractorGDBRemote response; + if (SendThreadSpecificPacketAndWaitForResponse( + tid, std::move(payload), response, false) != PacketResult::Success || + !response.IsNormalResponse()) + return nullptr; + + DataBufferSP buffer_sp( + new DataBufferHeap(response.GetStringRef().size() / 2, 0)); + response.GetHexBytes(buffer_sp->GetData(), '\xcc'); + return buffer_sp; +} + +bool GDBRemoteCommunicationClient::WriteRegister(lldb::tid_t tid, + uint32_t reg_num, + llvm::ArrayRef<uint8_t> data) { + StreamString payload; + payload.Printf("P%x=", reg_num); + payload.PutBytesAsRawHex8(data.data(), data.size(), + endian::InlHostByteOrder(), + endian::InlHostByteOrder()); + StringExtractorGDBRemote response; + return SendThreadSpecificPacketAndWaitForResponse(tid, std::move(payload), + response, false) == + PacketResult::Success && + response.IsOKResponse(); +} + +bool GDBRemoteCommunicationClient::WriteAllRegisters( + lldb::tid_t tid, llvm::ArrayRef<uint8_t> data) { + StreamString payload; + payload.PutChar('G'); + payload.PutBytesAsRawHex8(data.data(), data.size(), + endian::InlHostByteOrder(), + endian::InlHostByteOrder()); + StringExtractorGDBRemote response; + return SendThreadSpecificPacketAndWaitForResponse(tid, std::move(payload), + response, false) == + PacketResult::Success && + response.IsOKResponse(); +} + +bool GDBRemoteCommunicationClient::SaveRegisterState(lldb::tid_t tid, + uint32_t &save_id) { + save_id = 0; // Set to invalid save ID + if (m_supports_QSaveRegisterState == eLazyBoolNo) + return false; -uint64_t -GDBRemoteCommunicationClient::ReadFile (lldb::user_id_t fd, - uint64_t offset, - void *dst, - uint64_t dst_len, - Error &error) -{ - lldb_private::StreamString stream; - stream.Printf("vFile:pread:%i,%" PRId64 ",%" PRId64, (int)fd, dst_len, offset); - const char* packet = stream.GetData(); - int packet_len = stream.GetSize(); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) - { - if (response.GetChar() != 'F') - return 0; - uint32_t retcode = response.GetHexMaxU32(false, UINT32_MAX); - if (retcode == UINT32_MAX) - return retcode; - const char next = (response.Peek() ? *response.Peek() : 0); - if (next == ',') - return 0; - if (next == ';') - { - response.GetChar(); // skip the semicolon - std::string buffer; - if (response.GetEscapedBinaryData(buffer)) - { - const uint64_t data_to_write = std::min<uint64_t>(dst_len, buffer.size()); - if (data_to_write > 0) - memcpy(dst, &buffer[0], data_to_write); - return data_to_write; - } - } - } - return 0; -} + m_supports_QSaveRegisterState = eLazyBoolYes; + StreamString payload; + payload.PutCString("QSaveRegisterState"); + StringExtractorGDBRemote response; + if (SendThreadSpecificPacketAndWaitForResponse( + tid, std::move(payload), response, false) != PacketResult::Success) + return false; -uint64_t -GDBRemoteCommunicationClient::WriteFile (lldb::user_id_t fd, - uint64_t offset, - const void* src, - uint64_t src_len, - Error &error) -{ - lldb_private::StreamGDBRemote stream; - stream.Printf("vFile:pwrite:%i,%" PRId64 ",", (int)fd, offset); - stream.PutEscapedBytes(src, src_len); - const char* packet = stream.GetData(); - int packet_len = stream.GetSize(); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) - { - if (response.GetChar() != 'F') - { - error.SetErrorStringWithFormat("write file failed"); - return 0; - } - uint64_t bytes_written = response.GetU64(UINT64_MAX); - if (bytes_written == UINT64_MAX) - { - error.SetErrorToGenericError(); - if (response.GetChar() == ',') - { - int response_errno = response.GetS32(-1); - if (response_errno > 0) - error.SetError(response_errno, lldb::eErrorTypePOSIX); - } - return 0; - } - return bytes_written; - } - else - { - error.SetErrorString ("failed to send vFile:pwrite packet"); - } - return 0; -} + if (response.IsUnsupportedResponse()) + m_supports_QSaveRegisterState = eLazyBoolNo; -Error -GDBRemoteCommunicationClient::CreateSymlink(const FileSpec &src, const FileSpec &dst) -{ - std::string src_path{src.GetPath(false)}, - dst_path{dst.GetPath(false)}; - Error error; - lldb_private::StreamGDBRemote stream; - stream.PutCString("vFile:symlink:"); - // the unix symlink() command reverses its parameters where the dst if first, - // so we follow suit here - stream.PutCStringAsRawHex8(dst_path.c_str()); - stream.PutChar(','); - stream.PutCStringAsRawHex8(src_path.c_str()); - const char* packet = stream.GetData(); - int packet_len = stream.GetSize(); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) - { - if (response.GetChar() == 'F') - { - uint32_t result = response.GetU32(UINT32_MAX); - if (result != 0) - { - error.SetErrorToGenericError(); - if (response.GetChar() == ',') - { - int response_errno = response.GetS32(-1); - if (response_errno > 0) - error.SetError(response_errno, lldb::eErrorTypePOSIX); - } - } - } - else - { - // Should have returned with 'F<result>[,<errno>]' - error.SetErrorStringWithFormat("symlink failed"); - } - } - else - { - error.SetErrorString ("failed to send vFile:symlink packet"); - } - return error; -} + const uint32_t response_save_id = response.GetU32(0); + if (response_save_id == 0) + return false; -Error -GDBRemoteCommunicationClient::Unlink(const FileSpec &file_spec) -{ - std::string path{file_spec.GetPath(false)}; - Error error; - lldb_private::StreamGDBRemote stream; - stream.PutCString("vFile:unlink:"); - // the unix symlink() command reverses its parameters where the dst if first, - // so we follow suit here - stream.PutCStringAsRawHex8(path.c_str()); - const char* packet = stream.GetData(); - int packet_len = stream.GetSize(); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) - { - if (response.GetChar() == 'F') - { - uint32_t result = response.GetU32(UINT32_MAX); - if (result != 0) - { - error.SetErrorToGenericError(); - if (response.GetChar() == ',') - { - int response_errno = response.GetS32(-1); - if (response_errno > 0) - error.SetError(response_errno, lldb::eErrorTypePOSIX); - } - } - } - else - { - // Should have returned with 'F<result>[,<errno>]' - error.SetErrorStringWithFormat("unlink failed"); - } - } - else - { - error.SetErrorString ("failed to send vFile:unlink packet"); - } - return error; + save_id = response_save_id; + return true; } -// Extension of host I/O packets to get whether a file exists. -bool -GDBRemoteCommunicationClient::GetFileExists (const lldb_private::FileSpec& file_spec) -{ - std::string path(file_spec.GetPath(false)); - lldb_private::StreamString stream; - stream.PutCString("vFile:exists:"); - stream.PutCStringAsRawHex8(path.c_str()); - const char* packet = stream.GetData(); - int packet_len = stream.GetSize(); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) - { - if (response.GetChar() != 'F') - return false; - if (response.GetChar() != ',') - return false; - bool retcode = (response.GetChar() != '0'); - return retcode; - } +bool GDBRemoteCommunicationClient::RestoreRegisterState(lldb::tid_t tid, + uint32_t save_id) { + // We use the "m_supports_QSaveRegisterState" variable here because the + // QSaveRegisterState and QRestoreRegisterState packets must both be supported + // in + // order to be useful + if (m_supports_QSaveRegisterState == eLazyBoolNo) return false; -} -bool -GDBRemoteCommunicationClient::CalculateMD5 (const lldb_private::FileSpec& file_spec, - uint64_t &high, - uint64_t &low) -{ - std::string path(file_spec.GetPath(false)); - lldb_private::StreamString stream; - stream.PutCString("vFile:MD5:"); - stream.PutCStringAsRawHex8(path.c_str()); - const char* packet = stream.GetData(); - int packet_len = stream.GetSize(); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) - { - if (response.GetChar() != 'F') - return false; - if (response.GetChar() != ',') - return false; - if (response.Peek() && *response.Peek() == 'x') - return false; - low = response.GetHexMaxU64(false, UINT64_MAX); - high = response.GetHexMaxU64(false, UINT64_MAX); - return true; - } + StreamString payload; + payload.Printf("QRestoreRegisterState:%u", save_id); + StringExtractorGDBRemote response; + if (SendThreadSpecificPacketAndWaitForResponse( + tid, std::move(payload), response, false) != PacketResult::Success) return false; -} -bool -GDBRemoteCommunicationClient::AvoidGPackets (ProcessGDBRemote *process) -{ - // Some targets have issues with g/G packets and we need to avoid using them - if (m_avoid_g_packets == eLazyBoolCalculate) - { - if (process) - { - m_avoid_g_packets = eLazyBoolNo; - const ArchSpec &arch = process->GetTarget().GetArchitecture(); - if (arch.IsValid() - && arch.GetTriple().getVendor() == llvm::Triple::Apple - && arch.GetTriple().getOS() == llvm::Triple::IOS - && arch.GetTriple().getArch() == llvm::Triple::aarch64) - { - m_avoid_g_packets = eLazyBoolYes; - uint32_t gdb_server_version = GetGDBServerProgramVersion(); - if (gdb_server_version != 0) - { - const char *gdb_server_name = GetGDBServerProgramName(); - if (gdb_server_name && strcmp(gdb_server_name, "debugserver") == 0) - { - if (gdb_server_version >= 310) - m_avoid_g_packets = eLazyBoolNo; - } - } - } - } - } - return m_avoid_g_packets == eLazyBoolYes; + if (response.IsOKResponse()) + return true; + + if (response.IsUnsupportedResponse()) + m_supports_QSaveRegisterState = eLazyBoolNo; + return false; } -bool -GDBRemoteCommunicationClient::ReadRegister(lldb::tid_t tid, uint32_t reg, StringExtractorGDBRemote &response) -{ - Mutex::Locker locker; - if (GetSequenceMutex (locker, "Didn't get sequence mutex for p packet.")) - { - const bool thread_suffix_supported = GetThreadSuffixSupported(); - - if (thread_suffix_supported || SetCurrentThread(tid)) - { - char packet[64]; - int packet_len = 0; - if (thread_suffix_supported) - packet_len = ::snprintf (packet, sizeof(packet), "p%x;thread:%4.4" PRIx64 ";", reg, tid); - else - packet_len = ::snprintf (packet, sizeof(packet), "p%x", reg); - assert (packet_len < ((int)sizeof(packet) - 1)); - return SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success; - } - } +bool GDBRemoteCommunicationClient::SyncThreadState(lldb::tid_t tid) { + if (!GetSyncThreadStateSupported()) return false; + StreamString packet; + StringExtractorGDBRemote response; + packet.Printf("QSyncThreadState:%4.4" PRIx64 ";", tid); + return SendPacketAndWaitForResponse(packet.GetString(), response, false) == + GDBRemoteCommunication::PacketResult::Success && + response.IsOKResponse(); } +bool GDBRemoteCommunicationClient::GetModuleInfo( + const FileSpec &module_file_spec, const lldb_private::ArchSpec &arch_spec, + ModuleSpec &module_spec) { + if (!m_supports_qModuleInfo) + return false; -bool -GDBRemoteCommunicationClient::ReadAllRegisters (lldb::tid_t tid, StringExtractorGDBRemote &response) -{ - Mutex::Locker locker; - if (GetSequenceMutex (locker, "Didn't get sequence mutex for g packet.")) - { - const bool thread_suffix_supported = GetThreadSuffixSupported(); - - if (thread_suffix_supported || SetCurrentThread(tid)) - { - char packet[64]; - int packet_len = 0; - // Get all registers in one packet - if (thread_suffix_supported) - packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4" PRIx64 ";", tid); - else - packet_len = ::snprintf (packet, sizeof(packet), "g"); - assert (packet_len < ((int)sizeof(packet) - 1)); - return SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success; - } - } + std::string module_path = module_file_spec.GetPath(false); + if (module_path.empty()) return false; -} -bool -GDBRemoteCommunicationClient::SaveRegisterState (lldb::tid_t tid, uint32_t &save_id) -{ - save_id = 0; // Set to invalid save ID - if (m_supports_QSaveRegisterState == eLazyBoolNo) - return false; - - m_supports_QSaveRegisterState = eLazyBoolYes; - Mutex::Locker locker; - if (GetSequenceMutex (locker, "Didn't get sequence mutex for QSaveRegisterState.")) - { - const bool thread_suffix_supported = GetThreadSuffixSupported(); - if (thread_suffix_supported || SetCurrentThread(tid)) - { - char packet[256]; - if (thread_suffix_supported) - ::snprintf (packet, sizeof(packet), "QSaveRegisterState;thread:%4.4" PRIx64 ";", tid); - else - ::snprintf(packet, sizeof(packet), "QSaveRegisterState"); - - StringExtractorGDBRemote response; - - if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success) - { - if (response.IsUnsupportedResponse()) - { - // This packet isn't supported, don't try calling it again - m_supports_QSaveRegisterState = eLazyBoolNo; - } - - const uint32_t response_save_id = response.GetU32(0); - if (response_save_id != 0) - { - save_id = response_save_id; - return true; - } - } - } - } + + StreamString packet; + packet.PutCString("qModuleInfo:"); + packet.PutCStringAsRawHex8(module_path.c_str()); + packet.PutCString(";"); + const auto &triple = arch_spec.GetTriple().getTriple(); + packet.PutCStringAsRawHex8(triple.c_str()); + + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet.GetString(), response, false) != + PacketResult::Success) return false; -} -bool -GDBRemoteCommunicationClient::RestoreRegisterState (lldb::tid_t tid, uint32_t save_id) -{ - // We use the "m_supports_QSaveRegisterState" variable here because the - // QSaveRegisterState and QRestoreRegisterState packets must both be supported in - // order to be useful - if (m_supports_QSaveRegisterState == eLazyBoolNo) - return false; - - Mutex::Locker locker; - if (GetSequenceMutex (locker, "Didn't get sequence mutex for QRestoreRegisterState.")) - { - const bool thread_suffix_supported = GetThreadSuffixSupported(); - if (thread_suffix_supported || SetCurrentThread(tid)) - { - char packet[256]; - if (thread_suffix_supported) - ::snprintf (packet, sizeof(packet), "QRestoreRegisterState:%u;thread:%4.4" PRIx64 ";", save_id, tid); - else - ::snprintf (packet, sizeof(packet), "QRestoreRegisterState:%u" PRIx64 ";", save_id); - - StringExtractorGDBRemote response; - - if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - { - return true; - } - else if (response.IsUnsupportedResponse()) - { - // This packet isn't supported, don't try calling this packet or - // QSaveRegisterState again... - m_supports_QSaveRegisterState = eLazyBoolNo; - } - } - } - } + if (response.IsErrorResponse()) return false; -} -bool -GDBRemoteCommunicationClient::GetModuleInfo (const FileSpec& module_file_spec, - const lldb_private::ArchSpec& arch_spec, - ModuleSpec &module_spec) -{ - if (!m_supports_qModuleInfo) - return false; + if (response.IsUnsupportedResponse()) { + m_supports_qModuleInfo = false; + return false; + } + + llvm::StringRef name; + llvm::StringRef value; + + module_spec.Clear(); + module_spec.GetFileSpec() = module_file_spec; + + while (response.GetNameColonValue(name, value)) { + if (name == "uuid" || name == "md5") { + StringExtractor extractor(value); + std::string uuid; + extractor.GetHexByteString(uuid); + module_spec.GetUUID().SetFromCString(uuid.c_str(), uuid.size() / 2); + } else if (name == "triple") { + StringExtractor extractor(value); + std::string triple; + extractor.GetHexByteString(triple); + module_spec.GetArchitecture().SetTriple(triple.c_str()); + } else if (name == "file_offset") { + uint64_t ival = 0; + if (!value.getAsInteger(16, ival)) + module_spec.SetObjectOffset(ival); + } else if (name == "file_size") { + uint64_t ival = 0; + if (!value.getAsInteger(16, ival)) + module_spec.SetObjectSize(ival); + } else if (name == "file_path") { + StringExtractor extractor(value); + std::string path; + extractor.GetHexByteString(path); + module_spec.GetFileSpec() = FileSpec(path, false, arch_spec); + } + } + + return true; +} + +static llvm::Optional<ModuleSpec> +ParseModuleSpec(StructuredData::Dictionary *dict) { + ModuleSpec result; + if (!dict) + return llvm::None; + + std::string string; + uint64_t integer; + + if (!dict->GetValueForKeyAsString("uuid", string)) + return llvm::None; + result.GetUUID().SetFromCString(string.c_str(), string.size()); + + if (!dict->GetValueForKeyAsInteger("file_offset", integer)) + return llvm::None; + result.SetObjectOffset(integer); + + if (!dict->GetValueForKeyAsInteger("file_size", integer)) + return llvm::None; + result.SetObjectSize(integer); + + if (!dict->GetValueForKeyAsString("triple", string)) + return llvm::None; + result.GetArchitecture().SetTriple(string.c_str()); + + if (!dict->GetValueForKeyAsString("file_path", string)) + return llvm::None; + result.GetFileSpec() = FileSpec(string, false, result.GetArchitecture()); + + return result; +} + +llvm::Optional<std::vector<ModuleSpec>> +GDBRemoteCommunicationClient::GetModulesInfo( + llvm::ArrayRef<FileSpec> module_file_specs, const llvm::Triple &triple) { + if (!m_supports_jModulesInfo) + return llvm::None; + + JSONArray::SP module_array_sp = std::make_shared<JSONArray>(); + for (const FileSpec &module_file_spec : module_file_specs) { + JSONObject::SP module_sp = std::make_shared<JSONObject>(); + module_array_sp->AppendObject(module_sp); + module_sp->SetObject( + "file", std::make_shared<JSONString>(module_file_spec.GetPath(false))); + module_sp->SetObject("triple", + std::make_shared<JSONString>(triple.getTriple())); + } + StreamString unescaped_payload; + unescaped_payload.PutCString("jModulesInfo:"); + module_array_sp->Write(unescaped_payload); + StreamGDBRemote payload; + payload.PutEscapedBytes(unescaped_payload.GetString().data(), + unescaped_payload.GetSize()); + + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(payload.GetString(), response, false) != + PacketResult::Success || + response.IsErrorResponse()) + return llvm::None; + + if (response.IsUnsupportedResponse()) { + m_supports_jModulesInfo = false; + return llvm::None; + } + + StructuredData::ObjectSP response_object_sp = + StructuredData::ParseJSON(response.GetStringRef()); + if (!response_object_sp) + return llvm::None; + + StructuredData::Array *response_array = response_object_sp->GetAsArray(); + if (!response_array) + return llvm::None; + + std::vector<ModuleSpec> result; + for (size_t i = 0; i < response_array->GetSize(); ++i) { + if (llvm::Optional<ModuleSpec> module_spec = ParseModuleSpec( + response_array->GetItemAtIndex(i)->GetAsDictionary())) + result.push_back(*module_spec); + } + + return result; +} - std::string module_path = module_file_spec.GetPath (false); - if (module_path.empty ()) - return false; +// query the target remote for extended information using the qXfer packet +// +// example: object='features', annex='target.xml', out=<xml output> +// return: 'true' on success +// 'false' on failure (err set) +bool GDBRemoteCommunicationClient::ReadExtFeature( + const lldb_private::ConstString object, + const lldb_private::ConstString annex, std::string &out, + lldb_private::Error &err) { - StreamString packet; - packet.PutCString("qModuleInfo:"); - packet.PutCStringAsRawHex8(module_path.c_str()); - packet.PutCString(";"); - const auto& triple = arch_spec.GetTriple().getTriple(); - packet.PutCStringAsRawHex8(triple.c_str()); + std::stringstream output; + StringExtractorGDBRemote chunk; - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) != PacketResult::Success) - return false; + uint64_t size = GetRemoteMaxPacketSize(); + if (size == 0) + size = 0x1000; + size = size - 1; // Leave space for the 'm' or 'l' character in the response + int offset = 0; + bool active = true; - if (response.IsErrorResponse ()) - return false; + // loop until all data has been read + while (active) { - if (response.IsUnsupportedResponse ()) - { - m_supports_qModuleInfo = false; - return false; - } + // send query extended feature packet + std::stringstream packet; + packet << "qXfer:" << object.AsCString("") + << ":read:" << annex.AsCString("") << ":" << std::hex << offset + << "," << std::hex << size; - std::string name; - std::string value; - bool success; - StringExtractor extractor; + GDBRemoteCommunication::PacketResult res = + SendPacketAndWaitForResponse(packet.str(), chunk, false); - module_spec.Clear (); - module_spec.GetFileSpec () = module_file_spec; - - while (response.GetNameColonValue (name, value)) - { - if (name == "uuid" || name == "md5") - { - extractor.GetStringRef ().swap (value); - extractor.SetFilePos (0); - extractor.GetHexByteString (value); - module_spec.GetUUID().SetFromCString (value.c_str(), value.size() / 2); - } - else if (name == "triple") - { - extractor.GetStringRef ().swap (value); - extractor.SetFilePos (0); - extractor.GetHexByteString (value); - module_spec.GetArchitecture().SetTriple (value.c_str ()); - } - else if (name == "file_offset") - { - const auto ival = StringConvert::ToUInt64 (value.c_str (), 0, 16, &success); - if (success) - module_spec.SetObjectOffset (ival); - } - else if (name == "file_size") - { - const auto ival = StringConvert::ToUInt64 (value.c_str (), 0, 16, &success); - if (success) - module_spec.SetObjectSize (ival); - } - else if (name == "file_path") - { - extractor.GetStringRef ().swap (value); - extractor.SetFilePos (0); - extractor.GetHexByteString (value); - module_spec.GetFileSpec() = FileSpec(value.c_str(), false, arch_spec); - } + if (res != GDBRemoteCommunication::PacketResult::Success) { + err.SetErrorString("Error sending $qXfer packet"); + return false; } - return true; -} + const std::string &str = chunk.GetStringRef(); + if (str.length() == 0) { + // should have some data in chunk + err.SetErrorString("Empty response from $qXfer packet"); + return false; + } -// query the target remote for extended information using the qXfer packet -// -// example: object='features', annex='target.xml', out=<xml output> -// return: 'true' on success -// 'false' on failure (err set) -bool -GDBRemoteCommunicationClient::ReadExtFeature (const lldb_private::ConstString object, - const lldb_private::ConstString annex, - std::string & out, - lldb_private::Error & err) { - - std::stringstream output; - StringExtractorGDBRemote chunk; - - uint64_t size = GetRemoteMaxPacketSize(); - if (size == 0) - size = 0x1000; - size = size - 1; // Leave space for the 'm' or 'l' character in the response - int offset = 0; - bool active = true; - - // loop until all data has been read - while ( active ) { - - // send query extended feature packet - std::stringstream packet; - packet << "qXfer:" - << object.AsCString("") << ":read:" - << annex.AsCString("") << ":" - << std::hex << offset << "," - << std::hex << size; - - GDBRemoteCommunication::PacketResult res = - SendPacketAndWaitForResponse( packet.str().c_str(), - chunk, - false ); - - if ( res != GDBRemoteCommunication::PacketResult::Success ) { - err.SetErrorString( "Error sending $qXfer packet" ); - return false; - } + // check packet code + switch (str[0]) { + // last chunk + case ('l'): + active = false; + LLVM_FALLTHROUGH; - const std::string & str = chunk.GetStringRef( ); - if ( str.length() == 0 ) { - // should have some data in chunk - err.SetErrorString( "Empty response from $qXfer packet" ); - return false; - } + // more chunks + case ('m'): + if (str.length() > 1) + output << &str[1]; + offset += size; + break; - // check packet code - switch ( str[0] ) { - // last chunk - case ( 'l' ): - active = false; - LLVM_FALLTHROUGH; - - // more chunks - case ( 'm' ) : - if ( str.length() > 1 ) - output << &str[1]; - offset += size; - break; - - // unknown chunk - default: - err.SetErrorString( "Invalid continuation code from $qXfer packet" ); - return false; - } + // unknown chunk + default: + err.SetErrorString("Invalid continuation code from $qXfer packet"); + return false; } + } - out = output.str( ); - err.Success( ); - return true; + out = output.str(); + err.Success(); + return true; } // Notify the target that gdb is prepared to serve symbol lookup requests. // packet: "qSymbol::" // reply: // OK The target does not need to look up any (more) symbols. -// qSymbol:<sym_name> The target requests the value of symbol sym_name (hex encoded). -// LLDB may provide the value by sending another qSymbol packet +// qSymbol:<sym_name> The target requests the value of symbol sym_name (hex +// encoded). +// LLDB may provide the value by sending another qSymbol +// packet // in the form of"qSymbol:<sym_value>:<sym_name>". // // Three examples: // // lldb sends: qSymbol:: // lldb receives: OK -// Remote gdb stub does not need to know the addresses of any symbols, lldb does not +// Remote gdb stub does not need to know the addresses of any symbols, lldb +// does not // need to ask again in this session. // // lldb sends: qSymbol:: // lldb receives: qSymbol:64697370617463685f71756575655f6f666673657473 // lldb sends: qSymbol::64697370617463685f71756575655f6f666673657473 // lldb receives: OK -// Remote gdb stub asks for address of 'dispatch_queue_offsets'. lldb does not know -// the address at this time. lldb needs to send qSymbol:: again when it has more +// Remote gdb stub asks for address of 'dispatch_queue_offsets'. lldb does +// not know +// the address at this time. lldb needs to send qSymbol:: again when it has +// more // solibs loaded. // // lldb sends: qSymbol:: // lldb receives: qSymbol:64697370617463685f71756575655f6f666673657473 // lldb sends: qSymbol:2bc97554:64697370617463685f71756575655f6f666673657473 // lldb receives: OK -// Remote gdb stub asks for address of 'dispatch_queue_offsets'. lldb says that it -// is at address 0x2bc97554. Remote gdb stub sends 'OK' indicating that it does not +// Remote gdb stub asks for address of 'dispatch_queue_offsets'. lldb says +// that it +// is at address 0x2bc97554. Remote gdb stub sends 'OK' indicating that it +// does not // need any more symbols. lldb does not need to ask again in this session. -void -GDBRemoteCommunicationClient::ServeSymbolLookups(lldb_private::Process *process) -{ - // Set to true once we've resolved a symbol to an address for the remote stub. - // If we get an 'OK' response after this, the remote stub doesn't need any more - // symbols and we can stop asking. - bool symbol_response_provided = false; - - // Is this the inital qSymbol:: packet? - bool first_qsymbol_query = true; - - if (m_supports_qSymbol && m_qSymbol_requests_done == false) - { - Mutex::Locker locker; - if (GetSequenceMutex(locker, "GDBRemoteCommunicationClient::ServeSymbolLookups() failed due to not getting the sequence mutex")) - { - StreamString packet; - packet.PutCString ("qSymbol::"); - StringExtractorGDBRemote response; - while (SendPacketAndWaitForResponseNoLock(packet.GetData(), packet.GetSize(), response) == PacketResult::Success) - { - if (response.IsOKResponse()) - { - if (symbol_response_provided || first_qsymbol_query) - { - m_qSymbol_requests_done = true; - } - - // We are done serving symbols requests - return; - } - first_qsymbol_query = false; +void GDBRemoteCommunicationClient::ServeSymbolLookups( + lldb_private::Process *process) { + // Set to true once we've resolved a symbol to an address for the remote stub. + // If we get an 'OK' response after this, the remote stub doesn't need any + // more + // symbols and we can stop asking. + bool symbol_response_provided = false; + + // Is this the initial qSymbol:: packet? + bool first_qsymbol_query = true; + + if (m_supports_qSymbol && m_qSymbol_requests_done == false) { + Lock lock(*this, false); + if (lock) { + StreamString packet; + packet.PutCString("qSymbol::"); + StringExtractorGDBRemote response; + while (SendPacketAndWaitForResponseNoLock(packet.GetString(), response) == + PacketResult::Success) { + if (response.IsOKResponse()) { + if (symbol_response_provided || first_qsymbol_query) { + m_qSymbol_requests_done = true; + } + + // We are done serving symbols requests + return; + } + first_qsymbol_query = false; + + if (response.IsUnsupportedResponse()) { + // qSymbol is not supported by the current GDB server we are connected + // to + m_supports_qSymbol = false; + return; + } else { + llvm::StringRef response_str(response.GetStringRef()); + if (response_str.startswith("qSymbol:")) { + response.SetFilePos(strlen("qSymbol:")); + std::string symbol_name; + if (response.GetHexByteString(symbol_name)) { + if (symbol_name.empty()) + return; + + addr_t symbol_load_addr = LLDB_INVALID_ADDRESS; + lldb_private::SymbolContextList sc_list; + if (process->GetTarget().GetImages().FindSymbolsWithNameAndType( + ConstString(symbol_name), eSymbolTypeAny, sc_list)) { + const size_t num_scs = sc_list.GetSize(); + for (size_t sc_idx = 0; + sc_idx < num_scs && + symbol_load_addr == LLDB_INVALID_ADDRESS; + ++sc_idx) { + SymbolContext sc; + if (sc_list.GetContextAtIndex(sc_idx, sc)) { + if (sc.symbol) { + switch (sc.symbol->GetType()) { + case eSymbolTypeInvalid: + case eSymbolTypeAbsolute: + case eSymbolTypeUndefined: + case eSymbolTypeSourceFile: + case eSymbolTypeHeaderFile: + case eSymbolTypeObjectFile: + case eSymbolTypeCommonBlock: + case eSymbolTypeBlock: + case eSymbolTypeLocal: + case eSymbolTypeParam: + case eSymbolTypeVariable: + case eSymbolTypeVariableType: + case eSymbolTypeLineEntry: + case eSymbolTypeLineHeader: + case eSymbolTypeScopeBegin: + case eSymbolTypeScopeEnd: + case eSymbolTypeAdditional: + case eSymbolTypeCompiler: + case eSymbolTypeInstrumentation: + case eSymbolTypeTrampoline: + break; - if (response.IsUnsupportedResponse()) - { - // qSymbol is not supported by the current GDB server we are connected to - m_supports_qSymbol = false; - return; - } - else - { - llvm::StringRef response_str(response.GetStringRef()); - if (response_str.startswith("qSymbol:")) - { - response.SetFilePos(strlen("qSymbol:")); - std::string symbol_name; - if (response.GetHexByteString(symbol_name)) - { - if (symbol_name.empty()) - return; - - addr_t symbol_load_addr = LLDB_INVALID_ADDRESS; - lldb_private::SymbolContextList sc_list; - if (process->GetTarget().GetImages().FindSymbolsWithNameAndType(ConstString(symbol_name), eSymbolTypeAny, sc_list)) - { - const size_t num_scs = sc_list.GetSize(); - for (size_t sc_idx=0; sc_idx<num_scs && symbol_load_addr == LLDB_INVALID_ADDRESS; ++sc_idx) - { - SymbolContext sc; - if (sc_list.GetContextAtIndex(sc_idx, sc)) - { - if (sc.symbol) - { - switch (sc.symbol->GetType()) - { - case eSymbolTypeInvalid: - case eSymbolTypeAbsolute: - case eSymbolTypeUndefined: - case eSymbolTypeSourceFile: - case eSymbolTypeHeaderFile: - case eSymbolTypeObjectFile: - case eSymbolTypeCommonBlock: - case eSymbolTypeBlock: - case eSymbolTypeLocal: - case eSymbolTypeParam: - case eSymbolTypeVariable: - case eSymbolTypeVariableType: - case eSymbolTypeLineEntry: - case eSymbolTypeLineHeader: - case eSymbolTypeScopeBegin: - case eSymbolTypeScopeEnd: - case eSymbolTypeAdditional: - case eSymbolTypeCompiler: - case eSymbolTypeInstrumentation: - case eSymbolTypeTrampoline: - break; - - case eSymbolTypeCode: - case eSymbolTypeResolver: - case eSymbolTypeData: - case eSymbolTypeRuntime: - case eSymbolTypeException: - case eSymbolTypeObjCClass: - case eSymbolTypeObjCMetaClass: - case eSymbolTypeObjCIVar: - case eSymbolTypeReExported: - symbol_load_addr = sc.symbol->GetLoadAddress(&process->GetTarget()); - break; - } - } - } - } - } - // This is the normal path where our symbol lookup was successful and we want - // to send a packet with the new symbol value and see if another lookup needs to be - // done. - - // Change "packet" to contain the requested symbol value and name - packet.Clear(); - packet.PutCString("qSymbol:"); - if (symbol_load_addr != LLDB_INVALID_ADDRESS) - { - packet.Printf("%" PRIx64, symbol_load_addr); - symbol_response_provided = true; - } - else - { - symbol_response_provided = false; - } - packet.PutCString(":"); - packet.PutBytesAsRawHex8(symbol_name.data(), symbol_name.size()); - continue; // go back to the while loop and send "packet" and wait for another response - } + case eSymbolTypeCode: + case eSymbolTypeResolver: + case eSymbolTypeData: + case eSymbolTypeRuntime: + case eSymbolTypeException: + case eSymbolTypeObjCClass: + case eSymbolTypeObjCMetaClass: + case eSymbolTypeObjCIVar: + case eSymbolTypeReExported: + symbol_load_addr = + sc.symbol->GetLoadAddress(&process->GetTarget()); + break; + } } + } } - } - // If we make it here, the symbol request packet response wasn't valid or - // our symbol lookup failed so we must abort - return; + } + // This is the normal path where our symbol lookup was successful + // and we want + // to send a packet with the new symbol value and see if another + // lookup needs to be + // done. + + // Change "packet" to contain the requested symbol value and name + packet.Clear(); + packet.PutCString("qSymbol:"); + if (symbol_load_addr != LLDB_INVALID_ADDRESS) { + packet.Printf("%" PRIx64, symbol_load_addr); + symbol_response_provided = true; + } else { + symbol_response_provided = false; + } + packet.PutCString(":"); + packet.PutBytesAsRawHex8(symbol_name.data(), symbol_name.size()); + continue; // go back to the while loop and send "packet" and wait + // for another response + } + } + } + } + // If we make it here, the symbol request packet response wasn't valid or + // our symbol lookup failed so we must abort + return; + + } else if (Log *log = ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet( + GDBR_LOG_PROCESS | GDBR_LOG_PACKETS)) { + log->Printf( + "GDBRemoteCommunicationClient::%s: Didn't get sequence mutex.", + __FUNCTION__); + } + } +} + +StructuredData::Array * +GDBRemoteCommunicationClient::GetSupportedStructuredDataPlugins() { + if (!m_supported_async_json_packets_is_valid) { + // Query the server for the array of supported asynchronous JSON + // packets. + m_supported_async_json_packets_is_valid = true; - } - } -} + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + // Poll it now. + StringExtractorGDBRemote response; + const bool send_async = false; + if (SendPacketAndWaitForResponse("qStructuredDataPlugins", response, + send_async) == PacketResult::Success) { + m_supported_async_json_packets_sp = + StructuredData::ParseJSON(response.GetStringRef()); + if (m_supported_async_json_packets_sp && + !m_supported_async_json_packets_sp->GetAsArray()) { + // We were returned something other than a JSON array. This + // is invalid. Clear it out. + if (log) + log->Printf("GDBRemoteCommunicationClient::%s(): " + "QSupportedAsyncJSONPackets returned invalid " + "result: %s", + __FUNCTION__, response.GetStringRef().c_str()); + m_supported_async_json_packets_sp.reset(); + } + } else { + if (log) + log->Printf("GDBRemoteCommunicationClient::%s(): " + "QSupportedAsyncJSONPackets unsupported", + __FUNCTION__); + } + + if (log && m_supported_async_json_packets_sp) { + StreamString stream; + m_supported_async_json_packets_sp->Dump(stream); + log->Printf("GDBRemoteCommunicationClient::%s(): supported async " + "JSON packets: %s", + __FUNCTION__, stream.GetData()); + } + } + + return m_supported_async_json_packets_sp + ? m_supported_async_json_packets_sp->GetAsArray() + : nullptr; +} + +Error GDBRemoteCommunicationClient::ConfigureRemoteStructuredData( + const ConstString &type_name, const StructuredData::ObjectSP &config_sp) { + Error error; + + if (type_name.GetLength() == 0) { + error.SetErrorString("invalid type_name argument"); + return error; + } + + // Build command: Configure{type_name}: serialized config + // data. + StreamGDBRemote stream; + stream.PutCString("QConfigure"); + stream.PutCString(type_name.AsCString()); + stream.PutChar(':'); + if (config_sp) { + // Gather the plain-text version of the configuration data. + StreamString unescaped_stream; + config_sp->Dump(unescaped_stream); + unescaped_stream.Flush(); + + // Add it to the stream in escaped fashion. + stream.PutEscapedBytes(unescaped_stream.GetString().data(), + unescaped_stream.GetSize()); + } + stream.Flush(); + + // Send the packet. + const bool send_async = false; + StringExtractorGDBRemote response; + auto result = + SendPacketAndWaitForResponse(stream.GetString(), response, send_async); + if (result == PacketResult::Success) { + // We failed if the config result comes back other than OK. + if (strcmp(response.GetStringRef().c_str(), "OK") == 0) { + // Okay! + error.Clear(); + } else { + error.SetErrorStringWithFormat("configuring StructuredData feature " + "%s failed with error %s", + type_name.AsCString(), + response.GetStringRef().c_str()); + } + } else { + // Can we get more data here on the failure? + error.SetErrorStringWithFormat("configuring StructuredData feature %s " + "failed when sending packet: " + "PacketResult=%d", + type_name.AsCString(), (int)result); + } + return error; +} + +void GDBRemoteCommunicationClient::OnRunPacketSent(bool first) { + GDBRemoteClientBase::OnRunPacketSent(first); + m_curr_tid = LLDB_INVALID_THREAD_ID; +} diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index 096c4cf..83162a6 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -10,8 +10,11 @@ #ifndef liblldb_GDBRemoteCommunicationClient_h_ #define liblldb_GDBRemoteCommunicationClient_h_ +#include "GDBRemoteClientBase.h" + // C Includes // C++ Includes +#include <chrono> #include <map> #include <mutex> #include <string> @@ -23,660 +26,563 @@ #include "lldb/Core/StructuredData.h" #include "lldb/Target/Process.h" -#include "GDBRemoteCommunication.h" +#include "llvm/ADT/Optional.h" namespace lldb_private { namespace process_gdb_remote { -class GDBRemoteCommunicationClient : public GDBRemoteCommunication -{ +class GDBRemoteCommunicationClient : public GDBRemoteClientBase { public: - GDBRemoteCommunicationClient(); - - ~GDBRemoteCommunicationClient() override; - - //------------------------------------------------------------------ - // After connecting, send the handshake to the server to make sure - // we are communicating with it. - //------------------------------------------------------------------ - bool - HandshakeWithServer (Error *error_ptr); - - PacketResult - SendPacketAndWaitForResponse (const char *send_payload, - StringExtractorGDBRemote &response, - bool send_async); - - PacketResult - SendPacketAndWaitForResponse (const char *send_payload, - size_t send_length, - StringExtractorGDBRemote &response, - bool send_async); - - // For packets which specify a range of output to be returned, - // return all of the output via a series of request packets of the form - // <prefix>0,<size> - // <prefix><size>,<size> - // <prefix><size>*2,<size> - // <prefix><size>*3,<size> - // ... - // until a "$l..." packet is received, indicating the end. - // (size is in hex; this format is used by a standard gdbserver to - // return the given portion of the output specified by <prefix>; - // for example, "qXfer:libraries-svr4:read::fff,1000" means - // "return a chunk of the xml description file for shared - // library load addresses, where the chunk starts at offset 0xfff - // and continues for 0x1000 bytes"). - // Concatenate the resulting server response packets together and - // return in response_string. If any packet fails, the return value - // indicates that failure and the returned string value is undefined. - PacketResult - SendPacketsAndConcatenateResponses (const char *send_payload_prefix, - std::string &response_string); - - lldb::StateType - SendContinuePacketAndWaitForResponse (ProcessGDBRemote *process, - const char *packet_payload, - size_t packet_length, - StringExtractorGDBRemote &response); - - bool - SendvContPacket (ProcessGDBRemote *process, - const char *payload, - size_t packet_length, - StringExtractorGDBRemote &response); - - bool - GetThreadSuffixSupported () override; - - // This packet is usually sent first and the boolean return value - // indicates if the packet was send and any response was received - // even in the response is UNIMPLEMENTED. If the packet failed to - // get a response, then false is returned. This quickly tells us - // if we were able to connect and communicate with the remote GDB - // server - bool - QueryNoAckModeSupported (); - - void - GetListThreadsInStopReplySupported (); - - bool - SendAsyncSignal (int signo); - - bool - SendInterrupt (Mutex::Locker &locker, - uint32_t seconds_to_wait_for_stop, - bool &timed_out); - - lldb::pid_t - GetCurrentProcessID (bool allow_lazy = true); - - bool - GetLaunchSuccess (std::string &error_str); - - bool - LaunchGDBServer (const char *remote_accept_hostname, - lldb::pid_t &pid, - uint16_t &port, - std::string &socket_name); - - size_t - QueryGDBServer (std::vector<std::pair<uint16_t, std::string>>& connection_urls); - - bool - KillSpawnedProcess (lldb::pid_t pid); - - //------------------------------------------------------------------ - /// Sends a GDB remote protocol 'A' packet that delivers program - /// arguments to the remote server. - /// - /// @param[in] argv - /// A NULL terminated array of const C strings to use as the - /// arguments. - /// - /// @return - /// Zero if the response was "OK", a positive value if the - /// the response was "Exx" where xx are two hex digits, or - /// -1 if the call is unsupported or any other unexpected - /// response was received. - //------------------------------------------------------------------ - int - SendArgumentsPacket (const ProcessLaunchInfo &launch_info); - - //------------------------------------------------------------------ - /// Sends a "QEnvironment:NAME=VALUE" packet that will build up the - /// environment that will get used when launching an application - /// in conjunction with the 'A' packet. This function can be called - /// multiple times in a row in order to pass on the desired - /// environment that the inferior should be launched with. - /// - /// @param[in] name_equal_value - /// A NULL terminated C string that contains a single environment - /// in the format "NAME=VALUE". - /// - /// @return - /// Zero if the response was "OK", a positive value if the - /// the response was "Exx" where xx are two hex digits, or - /// -1 if the call is unsupported or any other unexpected - /// response was received. - //------------------------------------------------------------------ - int - SendEnvironmentPacket (char const *name_equal_value); - - int - SendLaunchArchPacket (const char *arch); - - int - SendLaunchEventDataPacket(const char *data, bool *was_supported = nullptr); - - //------------------------------------------------------------------ - /// Sends a "vAttach:PID" where PID is in hex. - /// - /// @param[in] pid - /// A process ID for the remote gdb server to attach to. - /// - /// @param[out] response - /// The response received from the gdb server. If the return - /// value is zero, \a response will contain a stop reply - /// packet. - /// - /// @return - /// Zero if the attach was successful, or an error indicating - /// an error code. - //------------------------------------------------------------------ - int - SendAttach (lldb::pid_t pid, - StringExtractorGDBRemote& response); - - //------------------------------------------------------------------ - /// Sends a GDB remote protocol 'I' packet that delivers stdin - /// data to the remote process. - /// - /// @param[in] data - /// A pointer to stdin data. - /// - /// @param[in] data_len - /// The number of bytes available at \a data. - /// - /// @return - /// Zero if the attach was successful, or an error indicating - /// an error code. - //------------------------------------------------------------------ - int - SendStdinNotification(const char* data, size_t data_len); - - //------------------------------------------------------------------ - /// Sets the path to use for stdin/out/err for a process - /// that will be launched with the 'A' packet. - /// - /// @param[in] path - /// The path to use for stdin/out/err - /// - /// @return - /// Zero if the for success, or an error code for failure. - //------------------------------------------------------------------ - int - SetSTDIN(const FileSpec &file_spec); - int - SetSTDOUT(const FileSpec &file_spec); - int - SetSTDERR(const FileSpec &file_spec); - - //------------------------------------------------------------------ - /// Sets the disable ASLR flag to \a enable for a process that will - /// be launched with the 'A' packet. - /// - /// @param[in] enable - /// A boolean value indicating whether to disable ASLR or not. - /// - /// @return - /// Zero if the for success, or an error code for failure. - //------------------------------------------------------------------ - int - SetDisableASLR (bool enable); - - //------------------------------------------------------------------ - /// Sets the DetachOnError flag to \a enable for the process controlled by the stub. - /// - /// @param[in] enable - /// A boolean value indicating whether to detach on error or not. - /// - /// @return - /// Zero if the for success, or an error code for failure. - //------------------------------------------------------------------ - int - SetDetachOnError (bool enable); - - //------------------------------------------------------------------ - /// Sets the working directory to \a path for a process that will - /// be launched with the 'A' packet for non platform based - /// connections. If this packet is sent to a GDB server that - /// implements the platform, it will change the current working - /// directory for the platform process. - /// - /// @param[in] working_dir - /// The path to a directory to use when launching our process - /// - /// @return - /// Zero if the for success, or an error code for failure. - //------------------------------------------------------------------ - int - SetWorkingDir(const FileSpec &working_dir); - - //------------------------------------------------------------------ - /// Gets the current working directory of a remote platform GDB - /// server. - /// - /// @param[out] working_dir - /// The current working directory on the remote platform. - /// - /// @return - /// Boolean for success - //------------------------------------------------------------------ - bool - GetWorkingDir(FileSpec &working_dir); - - lldb::addr_t - AllocateMemory (size_t size, uint32_t permissions); - - bool - DeallocateMemory (lldb::addr_t addr); - - Error - Detach (bool keep_stopped); - - Error - GetMemoryRegionInfo (lldb::addr_t addr, MemoryRegionInfo &range_info); - - Error - GetWatchpointSupportInfo (uint32_t &num); - - Error - GetWatchpointSupportInfo (uint32_t &num, bool& after, const ArchSpec &arch); - - Error - GetWatchpointsTriggerAfterInstruction (bool &after, const ArchSpec &arch); - - const ArchSpec & - GetHostArchitecture (); - - uint32_t - GetHostDefaultPacketTimeout(); - - const ArchSpec & - GetProcessArchitecture (); - - void - GetRemoteQSupported(); - - bool - GetVContSupported (char flavor); - - bool - GetpPacketSupported (lldb::tid_t tid); - - bool - GetxPacketSupported (); - - bool - GetVAttachOrWaitSupported (); - - bool - GetSyncThreadStateSupported(); - - void - ResetDiscoverableSettings (bool did_exec); - - bool - GetHostInfo (bool force = false); - - bool - GetDefaultThreadId (lldb::tid_t &tid); - - bool - GetOSVersion (uint32_t &major, - uint32_t &minor, - uint32_t &update); - - bool - GetOSBuildString (std::string &s); - - bool - GetOSKernelDescription (std::string &s); - - ArchSpec - GetSystemArchitecture (); - - bool - GetHostname (std::string &s); - - lldb::addr_t - GetShlibInfoAddr(); - - bool - GetSupportsThreadSuffix (); - - bool - GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info); - - uint32_t - FindProcesses (const ProcessInstanceInfoMatch &process_match_info, - ProcessInstanceInfoList &process_infos); - - bool - GetUserName (uint32_t uid, std::string &name); - - bool - GetGroupName (uint32_t gid, std::string &name); - - bool - HasFullVContSupport () - { - return GetVContSupported ('A'); - } + GDBRemoteCommunicationClient(); + + ~GDBRemoteCommunicationClient() override; + + //------------------------------------------------------------------ + // After connecting, send the handshake to the server to make sure + // we are communicating with it. + //------------------------------------------------------------------ + bool HandshakeWithServer(Error *error_ptr); + + // For packets which specify a range of output to be returned, + // return all of the output via a series of request packets of the form + // <prefix>0,<size> + // <prefix><size>,<size> + // <prefix><size>*2,<size> + // <prefix><size>*3,<size> + // ... + // until a "$l..." packet is received, indicating the end. + // (size is in hex; this format is used by a standard gdbserver to + // return the given portion of the output specified by <prefix>; + // for example, "qXfer:libraries-svr4:read::fff,1000" means + // "return a chunk of the xml description file for shared + // library load addresses, where the chunk starts at offset 0xfff + // and continues for 0x1000 bytes"). + // Concatenate the resulting server response packets together and + // return in response_string. If any packet fails, the return value + // indicates that failure and the returned string value is undefined. + PacketResult + SendPacketsAndConcatenateResponses(const char *send_payload_prefix, + std::string &response_string); + + bool GetThreadSuffixSupported(); + + // This packet is usually sent first and the boolean return value + // indicates if the packet was send and any response was received + // even in the response is UNIMPLEMENTED. If the packet failed to + // get a response, then false is returned. This quickly tells us + // if we were able to connect and communicate with the remote GDB + // server + bool QueryNoAckModeSupported(); + + void GetListThreadsInStopReplySupported(); + + lldb::pid_t GetCurrentProcessID(bool allow_lazy = true); + + bool GetLaunchSuccess(std::string &error_str); + + bool LaunchGDBServer(const char *remote_accept_hostname, lldb::pid_t &pid, + uint16_t &port, std::string &socket_name); + + size_t QueryGDBServer( + std::vector<std::pair<uint16_t, std::string>> &connection_urls); + + bool KillSpawnedProcess(lldb::pid_t pid); + + //------------------------------------------------------------------ + /// Sends a GDB remote protocol 'A' packet that delivers program + /// arguments to the remote server. + /// + /// @param[in] argv + /// A NULL terminated array of const C strings to use as the + /// arguments. + /// + /// @return + /// Zero if the response was "OK", a positive value if the + /// the response was "Exx" where xx are two hex digits, or + /// -1 if the call is unsupported or any other unexpected + /// response was received. + //------------------------------------------------------------------ + int SendArgumentsPacket(const ProcessLaunchInfo &launch_info); + + //------------------------------------------------------------------ + /// Sends a "QEnvironment:NAME=VALUE" packet that will build up the + /// environment that will get used when launching an application + /// in conjunction with the 'A' packet. This function can be called + /// multiple times in a row in order to pass on the desired + /// environment that the inferior should be launched with. + /// + /// @param[in] name_equal_value + /// A NULL terminated C string that contains a single environment + /// in the format "NAME=VALUE". + /// + /// @return + /// Zero if the response was "OK", a positive value if the + /// the response was "Exx" where xx are two hex digits, or + /// -1 if the call is unsupported or any other unexpected + /// response was received. + //------------------------------------------------------------------ + int SendEnvironmentPacket(char const *name_equal_value); + + int SendLaunchArchPacket(const char *arch); + + int SendLaunchEventDataPacket(const char *data, + bool *was_supported = nullptr); + + //------------------------------------------------------------------ + /// Sends a "vAttach:PID" where PID is in hex. + /// + /// @param[in] pid + /// A process ID for the remote gdb server to attach to. + /// + /// @param[out] response + /// The response received from the gdb server. If the return + /// value is zero, \a response will contain a stop reply + /// packet. + /// + /// @return + /// Zero if the attach was successful, or an error indicating + /// an error code. + //------------------------------------------------------------------ + int SendAttach(lldb::pid_t pid, StringExtractorGDBRemote &response); + + //------------------------------------------------------------------ + /// Sends a GDB remote protocol 'I' packet that delivers stdin + /// data to the remote process. + /// + /// @param[in] data + /// A pointer to stdin data. + /// + /// @param[in] data_len + /// The number of bytes available at \a data. + /// + /// @return + /// Zero if the attach was successful, or an error indicating + /// an error code. + //------------------------------------------------------------------ + int SendStdinNotification(const char *data, size_t data_len); + + //------------------------------------------------------------------ + /// Sets the path to use for stdin/out/err for a process + /// that will be launched with the 'A' packet. + /// + /// @param[in] path + /// The path to use for stdin/out/err + /// + /// @return + /// Zero if the for success, or an error code for failure. + //------------------------------------------------------------------ + int SetSTDIN(const FileSpec &file_spec); + int SetSTDOUT(const FileSpec &file_spec); + int SetSTDERR(const FileSpec &file_spec); + + //------------------------------------------------------------------ + /// Sets the disable ASLR flag to \a enable for a process that will + /// be launched with the 'A' packet. + /// + /// @param[in] enable + /// A boolean value indicating whether to disable ASLR or not. + /// + /// @return + /// Zero if the for success, or an error code for failure. + //------------------------------------------------------------------ + int SetDisableASLR(bool enable); + + //------------------------------------------------------------------ + /// Sets the DetachOnError flag to \a enable for the process controlled by the + /// stub. + /// + /// @param[in] enable + /// A boolean value indicating whether to detach on error or not. + /// + /// @return + /// Zero if the for success, or an error code for failure. + //------------------------------------------------------------------ + int SetDetachOnError(bool enable); + + //------------------------------------------------------------------ + /// Sets the working directory to \a path for a process that will + /// be launched with the 'A' packet for non platform based + /// connections. If this packet is sent to a GDB server that + /// implements the platform, it will change the current working + /// directory for the platform process. + /// + /// @param[in] working_dir + /// The path to a directory to use when launching our process + /// + /// @return + /// Zero if the for success, or an error code for failure. + //------------------------------------------------------------------ + int SetWorkingDir(const FileSpec &working_dir); + + //------------------------------------------------------------------ + /// Gets the current working directory of a remote platform GDB + /// server. + /// + /// @param[out] working_dir + /// The current working directory on the remote platform. + /// + /// @return + /// Boolean for success + //------------------------------------------------------------------ + bool GetWorkingDir(FileSpec &working_dir); + + lldb::addr_t AllocateMemory(size_t size, uint32_t permissions); + + bool DeallocateMemory(lldb::addr_t addr); + + Error Detach(bool keep_stopped); + + Error GetMemoryRegionInfo(lldb::addr_t addr, MemoryRegionInfo &range_info); + + Error GetWatchpointSupportInfo(uint32_t &num); + + Error GetWatchpointSupportInfo(uint32_t &num, bool &after, + const ArchSpec &arch); + + Error GetWatchpointsTriggerAfterInstruction(bool &after, + const ArchSpec &arch); + + const ArchSpec &GetHostArchitecture(); + + std::chrono::seconds GetHostDefaultPacketTimeout(); + + const ArchSpec &GetProcessArchitecture(); + + void GetRemoteQSupported(); - bool - HasAnyVContSupport () - { - return GetVContSupported ('a'); - } - - bool - GetStopReply (StringExtractorGDBRemote &response); - - bool - GetThreadStopInfo (lldb::tid_t tid, - StringExtractorGDBRemote &response); - - bool - SupportsGDBStoppointPacket (GDBStoppointType type) - { - switch (type) - { - case eBreakpointSoftware: return m_supports_z0; - case eBreakpointHardware: return m_supports_z1; - case eWatchpointWrite: return m_supports_z2; - case eWatchpointRead: return m_supports_z3; - case eWatchpointReadWrite: return m_supports_z4; - default: return false; - } - } + bool GetVContSupported(char flavor); - uint8_t - SendGDBStoppointTypePacket (GDBStoppointType type, // Type of breakpoint or watchpoint - bool insert, // Insert or remove? - lldb::addr_t addr, // Address of breakpoint or watchpoint - uint32_t length); // Byte Size of breakpoint or watchpoint - - bool - SetNonStopMode (const bool enable); - - void - TestPacketSpeed (const uint32_t num_packets, uint32_t max_send, uint32_t max_recv, bool json, Stream &strm); - - // This packet is for testing the speed of the interface only. Both - // the client and server need to support it, but this allows us to - // measure the packet speed without any other work being done on the - // other end and avoids any of that work affecting the packet send - // and response times. - bool - SendSpeedTestPacket (uint32_t send_size, - uint32_t recv_size); - - bool - SetCurrentThread (uint64_t tid); - - bool - SetCurrentThreadForRun (uint64_t tid); - - bool - GetQXferAuxvReadSupported (); - - bool - GetQXferLibrariesReadSupported (); - - bool - GetQXferLibrariesSVR4ReadSupported (); - - uint64_t - GetRemoteMaxPacketSize(); - - bool - GetEchoSupported (); - - bool - GetAugmentedLibrariesSVR4ReadSupported (); - - bool - GetQXferFeaturesReadSupported (); - - LazyBool - SupportsAllocDeallocMemory () // const - { - // Uncomment this to have lldb pretend the debug server doesn't respond to alloc/dealloc memory packets. - // m_supports_alloc_dealloc_memory = lldb_private::eLazyBoolNo; - return m_supports_alloc_dealloc_memory; - } + bool GetpPacketSupported(lldb::tid_t tid); + + bool GetxPacketSupported(); + + bool GetVAttachOrWaitSupported(); + + bool GetSyncThreadStateSupported(); + + void ResetDiscoverableSettings(bool did_exec); + + bool GetHostInfo(bool force = false); + + bool GetDefaultThreadId(lldb::tid_t &tid); + + bool GetOSVersion(uint32_t &major, uint32_t &minor, uint32_t &update); + + bool GetOSBuildString(std::string &s); + + bool GetOSKernelDescription(std::string &s); + + ArchSpec GetSystemArchitecture(); + + bool GetHostname(std::string &s); + + lldb::addr_t GetShlibInfoAddr(); + + bool GetSupportsThreadSuffix(); + + bool GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info); - size_t - GetCurrentThreadIDs (std::vector<lldb::tid_t> &thread_ids, - bool &sequence_mutex_unavailable); - - bool - GetInterruptWasSent () const - { - return m_interrupt_sent; + uint32_t FindProcesses(const ProcessInstanceInfoMatch &process_match_info, + ProcessInstanceInfoList &process_infos); + + bool GetUserName(uint32_t uid, std::string &name); + + bool GetGroupName(uint32_t gid, std::string &name); + + bool HasFullVContSupport() { return GetVContSupported('A'); } + + bool HasAnyVContSupport() { return GetVContSupported('a'); } + + bool GetStopReply(StringExtractorGDBRemote &response); + + bool GetThreadStopInfo(lldb::tid_t tid, StringExtractorGDBRemote &response); + + bool SupportsGDBStoppointPacket(GDBStoppointType type) { + switch (type) { + case eBreakpointSoftware: + return m_supports_z0; + case eBreakpointHardware: + return m_supports_z1; + case eWatchpointWrite: + return m_supports_z2; + case eWatchpointRead: + return m_supports_z3; + case eWatchpointReadWrite: + return m_supports_z4; + default: + return false; } - - lldb::user_id_t - OpenFile (const FileSpec& file_spec, uint32_t flags, mode_t mode, Error &error); - - bool - CloseFile (lldb::user_id_t fd, Error &error); - - lldb::user_id_t - GetFileSize (const FileSpec& file_spec); - - Error - GetFilePermissions(const FileSpec &file_spec, uint32_t &file_permissions); - - Error - SetFilePermissions(const FileSpec &file_spec, uint32_t file_permissions); - - uint64_t - ReadFile (lldb::user_id_t fd, - uint64_t offset, - void *dst, - uint64_t dst_len, - Error &error); - - uint64_t - WriteFile (lldb::user_id_t fd, - uint64_t offset, - const void* src, - uint64_t src_len, - Error &error); - - Error - CreateSymlink(const FileSpec &src, - const FileSpec &dst); - - Error - Unlink(const FileSpec &file_spec); - - Error - MakeDirectory(const FileSpec &file_spec, uint32_t mode); - - bool - GetFileExists (const FileSpec& file_spec); - - Error - RunShellCommand(const char *command, // Shouldn't be nullptr - const FileSpec &working_dir, // Pass empty FileSpec to use the current working directory - int *status_ptr, // Pass nullptr if you don't want the process exit status - int *signo_ptr, // Pass nullptr if you don't want the signal that caused the process to exit - std::string *command_output, // Pass nullptr if you don't want the command output - uint32_t timeout_sec); // Timeout in seconds to wait for shell program to finish - - bool - CalculateMD5 (const FileSpec& file_spec, uint64_t &high, uint64_t &low); - - std::string - HarmonizeThreadIdsForProfileData (ProcessGDBRemote *process, - StringExtractorGDBRemote &inputStringExtractor); - - bool - ReadRegister(lldb::tid_t tid, - uint32_t reg_num, // Must be the eRegisterKindProcessPlugin register number, to be sent to the remote - StringExtractorGDBRemote &response); - - bool - ReadAllRegisters (lldb::tid_t tid, - StringExtractorGDBRemote &response); - - bool - SaveRegisterState (lldb::tid_t tid, uint32_t &save_id); - - bool - RestoreRegisterState (lldb::tid_t tid, uint32_t save_id); - - const char * - GetGDBServerProgramName(); - - uint32_t - GetGDBServerProgramVersion(); - - bool - AvoidGPackets(ProcessGDBRemote *process); - - StructuredData::ObjectSP - GetThreadsInfo(); - - bool - GetThreadExtendedInfoSupported(); - - bool - GetLoadedDynamicLibrariesInfosSupported(); - - bool - GetModuleInfo (const FileSpec& module_file_spec, - const ArchSpec& arch_spec, - ModuleSpec &module_spec); - - bool - ReadExtFeature (const lldb_private::ConstString object, - const lldb_private::ConstString annex, - std::string & out, - lldb_private::Error & err); - - void - ServeSymbolLookups(lldb_private::Process *process); + } + + uint8_t SendGDBStoppointTypePacket( + GDBStoppointType type, // Type of breakpoint or watchpoint + bool insert, // Insert or remove? + lldb::addr_t addr, // Address of breakpoint or watchpoint + uint32_t length); // Byte Size of breakpoint or watchpoint + + bool SetNonStopMode(const bool enable); + + void TestPacketSpeed(const uint32_t num_packets, uint32_t max_send, + uint32_t max_recv, uint64_t recv_amount, bool json, + Stream &strm); + + // This packet is for testing the speed of the interface only. Both + // the client and server need to support it, but this allows us to + // measure the packet speed without any other work being done on the + // other end and avoids any of that work affecting the packet send + // and response times. + bool SendSpeedTestPacket(uint32_t send_size, uint32_t recv_size); + + bool SetCurrentThread(uint64_t tid); + + bool SetCurrentThreadForRun(uint64_t tid); + + bool GetQXferAuxvReadSupported(); + + bool GetQXferLibrariesReadSupported(); + + bool GetQXferLibrariesSVR4ReadSupported(); + + uint64_t GetRemoteMaxPacketSize(); + + bool GetEchoSupported(); + + bool GetAugmentedLibrariesSVR4ReadSupported(); + + bool GetQXferFeaturesReadSupported(); + + LazyBool SupportsAllocDeallocMemory() // const + { + // Uncomment this to have lldb pretend the debug server doesn't respond to + // alloc/dealloc memory packets. + // m_supports_alloc_dealloc_memory = lldb_private::eLazyBoolNo; + return m_supports_alloc_dealloc_memory; + } + + size_t GetCurrentThreadIDs(std::vector<lldb::tid_t> &thread_ids, + bool &sequence_mutex_unavailable); + + lldb::user_id_t OpenFile(const FileSpec &file_spec, uint32_t flags, + mode_t mode, Error &error); + + bool CloseFile(lldb::user_id_t fd, Error &error); + + lldb::user_id_t GetFileSize(const FileSpec &file_spec); + + Error GetFilePermissions(const FileSpec &file_spec, + uint32_t &file_permissions); + + Error SetFilePermissions(const FileSpec &file_spec, + uint32_t file_permissions); + + uint64_t ReadFile(lldb::user_id_t fd, uint64_t offset, void *dst, + uint64_t dst_len, Error &error); + + uint64_t WriteFile(lldb::user_id_t fd, uint64_t offset, const void *src, + uint64_t src_len, Error &error); + + Error CreateSymlink(const FileSpec &src, const FileSpec &dst); + + Error Unlink(const FileSpec &file_spec); + + Error MakeDirectory(const FileSpec &file_spec, uint32_t mode); + + bool GetFileExists(const FileSpec &file_spec); + + Error RunShellCommand( + const char *command, // Shouldn't be nullptr + const FileSpec &working_dir, // Pass empty FileSpec to use the current + // working directory + int *status_ptr, // Pass nullptr if you don't want the process exit status + int *signo_ptr, // Pass nullptr if you don't want the signal that caused + // the process to exit + std::string + *command_output, // Pass nullptr if you don't want the command output + uint32_t timeout_sec); // Timeout in seconds to wait for shell program to + // finish + + bool CalculateMD5(const FileSpec &file_spec, uint64_t &high, uint64_t &low); + + lldb::DataBufferSP ReadRegister( + lldb::tid_t tid, + uint32_t + reg_num); // Must be the eRegisterKindProcessPlugin register number + + lldb::DataBufferSP ReadAllRegisters(lldb::tid_t tid); + + bool + WriteRegister(lldb::tid_t tid, + uint32_t reg_num, // eRegisterKindProcessPlugin register number + llvm::ArrayRef<uint8_t> data); + + bool WriteAllRegisters(lldb::tid_t tid, llvm::ArrayRef<uint8_t> data); + + bool SaveRegisterState(lldb::tid_t tid, uint32_t &save_id); + + bool RestoreRegisterState(lldb::tid_t tid, uint32_t save_id); + + bool SyncThreadState(lldb::tid_t tid); + + const char *GetGDBServerProgramName(); + + uint32_t GetGDBServerProgramVersion(); + + bool AvoidGPackets(ProcessGDBRemote *process); + + StructuredData::ObjectSP GetThreadsInfo(); + + bool GetThreadExtendedInfoSupported(); + + bool GetLoadedDynamicLibrariesInfosSupported(); + + bool GetSharedCacheInfoSupported(); + + bool GetModuleInfo(const FileSpec &module_file_spec, + const ArchSpec &arch_spec, ModuleSpec &module_spec); + + llvm::Optional<std::vector<ModuleSpec>> + GetModulesInfo(llvm::ArrayRef<FileSpec> module_file_specs, + const llvm::Triple &triple); + + bool ReadExtFeature(const lldb_private::ConstString object, + const lldb_private::ConstString annex, std::string &out, + lldb_private::Error &err); + + void ServeSymbolLookups(lldb_private::Process *process); + + //------------------------------------------------------------------ + /// Return the feature set supported by the gdb-remote server. + /// + /// This method returns the remote side's response to the qSupported + /// packet. The response is the complete string payload returned + /// to the client. + /// + /// @return + /// The string returned by the server to the qSupported query. + //------------------------------------------------------------------ + const std::string &GetServerSupportedFeatures() const { + return m_qSupported_response; + } + + //------------------------------------------------------------------ + /// Return the array of async JSON packet types supported by the remote. + /// + /// This method returns the remote side's array of supported JSON + /// packet types as a list of type names. Each of the results are + /// expected to have an Enable{type_name} command to enable and configure + /// the related feature. Each type_name for an enabled feature will + /// possibly send async-style packets that contain a payload of a + /// binhex-encoded JSON dictionary. The dictionary will have a + /// string field named 'type', that contains the type_name of the + /// supported packet type. + /// + /// There is a Plugin category called structured-data plugins. + /// A plugin indicates whether it knows how to handle a type_name. + /// If so, it can be used to process the async JSON packet. + /// + /// @return + /// The string returned by the server to the qSupported query. + //------------------------------------------------------------------ + lldb_private::StructuredData::Array *GetSupportedStructuredDataPlugins(); + + //------------------------------------------------------------------ + /// Configure a StructuredData feature on the remote end. + /// + /// @see \b Process::ConfigureStructuredData(...) for details. + //------------------------------------------------------------------ + Error + ConfigureRemoteStructuredData(const ConstString &type_name, + const StructuredData::ObjectSP &config_sp); protected: - LazyBool m_supports_not_sending_acks; - LazyBool m_supports_thread_suffix; - LazyBool m_supports_threads_in_stop_reply; - LazyBool m_supports_vCont_all; - LazyBool m_supports_vCont_any; - LazyBool m_supports_vCont_c; - LazyBool m_supports_vCont_C; - LazyBool m_supports_vCont_s; - LazyBool m_supports_vCont_S; - LazyBool m_qHostInfo_is_valid; - LazyBool m_curr_pid_is_valid; - LazyBool m_qProcessInfo_is_valid; - LazyBool m_qGDBServerVersion_is_valid; - LazyBool m_supports_alloc_dealloc_memory; - LazyBool m_supports_memory_region_info; - LazyBool m_supports_watchpoint_support_info; - LazyBool m_supports_detach_stay_stopped; - LazyBool m_watchpoints_trigger_after_instruction; - LazyBool m_attach_or_wait_reply; - LazyBool m_prepare_for_reg_writing_reply; - LazyBool m_supports_p; - LazyBool m_supports_x; - LazyBool m_avoid_g_packets; - LazyBool m_supports_QSaveRegisterState; - LazyBool m_supports_qXfer_auxv_read; - LazyBool m_supports_qXfer_libraries_read; - LazyBool m_supports_qXfer_libraries_svr4_read; - LazyBool m_supports_qXfer_features_read; - LazyBool m_supports_augmented_libraries_svr4_read; - LazyBool m_supports_jThreadExtendedInfo; - LazyBool m_supports_jLoadedDynamicLibrariesInfos; - - bool - m_supports_qProcessInfoPID:1, - m_supports_qfProcessInfo:1, - m_supports_qUserName:1, - m_supports_qGroupName:1, - m_supports_qThreadStopInfo:1, - m_supports_z0:1, - m_supports_z1:1, - m_supports_z2:1, - m_supports_z3:1, - m_supports_z4:1, - m_supports_QEnvironment:1, - m_supports_QEnvironmentHexEncoded:1, - m_supports_qSymbol:1, - m_qSymbol_requests_done:1, - m_supports_qModuleInfo:1, - m_supports_jThreadsInfo:1; - - lldb::pid_t m_curr_pid; - lldb::tid_t m_curr_tid; // Current gdb remote protocol thread index for all other operations - lldb::tid_t m_curr_tid_run; // Current gdb remote protocol thread index for continue, step, etc - - uint32_t m_num_supported_hardware_watchpoints; - - // If we need to send a packet while the target is running, the m_async_XXX - // member variables take care of making this happen. - std::recursive_mutex m_async_mutex; - Predicate<bool> m_async_packet_predicate; - std::string m_async_packet; - PacketResult m_async_result; - StringExtractorGDBRemote m_async_response; - int m_async_signal; // We were asked to deliver a signal to the inferior process. - bool m_interrupt_sent; - std::string m_partial_profile_data; - std::map<uint64_t, uint32_t> m_thread_id_to_used_usec_map; - - ArchSpec m_host_arch; - ArchSpec m_process_arch; - uint32_t m_os_version_major; - uint32_t m_os_version_minor; - uint32_t m_os_version_update; - std::string m_os_build; - std::string m_os_kernel; - std::string m_hostname; - std::string m_gdb_server_name; // from reply to qGDBServerVersion, empty if qGDBServerVersion is not supported - uint32_t m_gdb_server_version; // from reply to qGDBServerVersion, zero if qGDBServerVersion is not supported - uint32_t m_default_packet_timeout; - uint64_t m_max_packet_size; // as returned by qSupported - - PacketResult - SendPacketAndWaitForResponseNoLock (const char *payload, - size_t payload_length, - StringExtractorGDBRemote &response); - - bool - GetCurrentProcessInfo (bool allow_lazy_pid = true); - - bool - GetGDBServerVersion(); - - // Given the list of compression types that the remote debug stub can support, - // possibly enable compression if we find an encoding we can handle. - void - MaybeEnableCompression (std::vector<std::string> supported_compressions); - - bool - DecodeProcessInfoResponse (StringExtractorGDBRemote &response, - ProcessInstanceInfo &process_info); + LazyBool m_supports_not_sending_acks; + LazyBool m_supports_thread_suffix; + LazyBool m_supports_threads_in_stop_reply; + LazyBool m_supports_vCont_all; + LazyBool m_supports_vCont_any; + LazyBool m_supports_vCont_c; + LazyBool m_supports_vCont_C; + LazyBool m_supports_vCont_s; + LazyBool m_supports_vCont_S; + LazyBool m_qHostInfo_is_valid; + LazyBool m_curr_pid_is_valid; + LazyBool m_qProcessInfo_is_valid; + LazyBool m_qGDBServerVersion_is_valid; + LazyBool m_supports_alloc_dealloc_memory; + LazyBool m_supports_memory_region_info; + LazyBool m_supports_watchpoint_support_info; + LazyBool m_supports_detach_stay_stopped; + LazyBool m_watchpoints_trigger_after_instruction; + LazyBool m_attach_or_wait_reply; + LazyBool m_prepare_for_reg_writing_reply; + LazyBool m_supports_p; + LazyBool m_supports_x; + LazyBool m_avoid_g_packets; + LazyBool m_supports_QSaveRegisterState; + LazyBool m_supports_qXfer_auxv_read; + LazyBool m_supports_qXfer_libraries_read; + LazyBool m_supports_qXfer_libraries_svr4_read; + LazyBool m_supports_qXfer_features_read; + LazyBool m_supports_augmented_libraries_svr4_read; + LazyBool m_supports_jThreadExtendedInfo; + LazyBool m_supports_jLoadedDynamicLibrariesInfos; + LazyBool m_supports_jGetSharedCacheInfo; + + bool m_supports_qProcessInfoPID : 1, m_supports_qfProcessInfo : 1, + m_supports_qUserName : 1, m_supports_qGroupName : 1, + m_supports_qThreadStopInfo : 1, m_supports_z0 : 1, m_supports_z1 : 1, + m_supports_z2 : 1, m_supports_z3 : 1, m_supports_z4 : 1, + m_supports_QEnvironment : 1, m_supports_QEnvironmentHexEncoded : 1, + m_supports_qSymbol : 1, m_qSymbol_requests_done : 1, + m_supports_qModuleInfo : 1, m_supports_jThreadsInfo : 1, + m_supports_jModulesInfo : 1; + + lldb::pid_t m_curr_pid; + lldb::tid_t m_curr_tid; // Current gdb remote protocol thread index for all + // other operations + lldb::tid_t m_curr_tid_run; // Current gdb remote protocol thread index for + // continue, step, etc + + uint32_t m_num_supported_hardware_watchpoints; + + ArchSpec m_host_arch; + ArchSpec m_process_arch; + uint32_t m_os_version_major; + uint32_t m_os_version_minor; + uint32_t m_os_version_update; + std::string m_os_build; + std::string m_os_kernel; + std::string m_hostname; + std::string m_gdb_server_name; // from reply to qGDBServerVersion, empty if + // qGDBServerVersion is not supported + uint32_t m_gdb_server_version; // from reply to qGDBServerVersion, zero if + // qGDBServerVersion is not supported + std::chrono::seconds m_default_packet_timeout; + uint64_t m_max_packet_size; // as returned by qSupported + std::string m_qSupported_response; // the complete response to qSupported + + bool m_supported_async_json_packets_is_valid; + lldb_private::StructuredData::ObjectSP m_supported_async_json_packets_sp; + + bool GetCurrentProcessInfo(bool allow_lazy_pid = true); + + bool GetGDBServerVersion(); + + // Given the list of compression types that the remote debug stub can support, + // possibly enable compression if we find an encoding we can handle. + void MaybeEnableCompression(std::vector<std::string> supported_compressions); + + bool DecodeProcessInfoResponse(StringExtractorGDBRemote &response, + ProcessInstanceInfo &process_info); + + void OnRunPacketSent(bool first) override; + + PacketResult SendThreadSpecificPacketAndWaitForResponse( + lldb::tid_t tid, StreamString &&payload, + StringExtractorGDBRemote &response, bool send_async); private: - DISALLOW_COPY_AND_ASSIGN (GDBRemoteCommunicationClient); + DISALLOW_COPY_AND_ASSIGN(GDBRemoteCommunicationClient); }; } // namespace process_gdb_remote diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp index 4ee66b8..934824e 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp @@ -25,114 +25,96 @@ using namespace lldb; using namespace lldb_private; using namespace lldb_private::process_gdb_remote; -GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(const char *comm_name, - const char *listener_name) : - GDBRemoteCommunication (comm_name, listener_name), - m_exit_now (false) -{ -} +GDBRemoteCommunicationServer::GDBRemoteCommunicationServer( + const char *comm_name, const char *listener_name) + : GDBRemoteCommunication(comm_name, listener_name), m_exit_now(false) {} -GDBRemoteCommunicationServer::~GDBRemoteCommunicationServer() -{ -} +GDBRemoteCommunicationServer::~GDBRemoteCommunicationServer() {} void GDBRemoteCommunicationServer::RegisterPacketHandler( - StringExtractorGDBRemote::ServerPacketType packet_type, - PacketHandler handler) -{ - m_packet_handlers[packet_type] = std::move(handler); + StringExtractorGDBRemote::ServerPacketType packet_type, + PacketHandler handler) { + m_packet_handlers[packet_type] = std::move(handler); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec, - Error &error, - bool &interrupt, - bool &quit) -{ - StringExtractorGDBRemote packet; - - PacketResult packet_result = WaitForPacketWithTimeoutMicroSecondsNoLock (packet, timeout_usec, false); - if (packet_result == PacketResult::Success) - { - const StringExtractorGDBRemote::ServerPacketType packet_type = packet.GetServerPacketType (); - switch (packet_type) - { - case StringExtractorGDBRemote::eServerPacketType_nack: - case StringExtractorGDBRemote::eServerPacketType_ack: - break; - - case StringExtractorGDBRemote::eServerPacketType_invalid: - error.SetErrorString("invalid packet"); - quit = true; - break; - - case StringExtractorGDBRemote::eServerPacketType_unimplemented: - packet_result = SendUnimplementedResponse (packet.GetStringRef().c_str()); - break; - - default: - auto handler_it = m_packet_handlers.find(packet_type); - if (handler_it == m_packet_handlers.end()) - packet_result = SendUnimplementedResponse (packet.GetStringRef().c_str()); - else - packet_result = handler_it->second (packet, error, interrupt, quit); - break; - } +GDBRemoteCommunicationServer::GetPacketAndSendResponse( + Timeout<std::micro> timeout, Error &error, bool &interrupt, bool &quit) { + StringExtractorGDBRemote packet; + + PacketResult packet_result = WaitForPacketNoLock(packet, timeout, false); + if (packet_result == PacketResult::Success) { + const StringExtractorGDBRemote::ServerPacketType packet_type = + packet.GetServerPacketType(); + switch (packet_type) { + case StringExtractorGDBRemote::eServerPacketType_nack: + case StringExtractorGDBRemote::eServerPacketType_ack: + break; + + case StringExtractorGDBRemote::eServerPacketType_invalid: + error.SetErrorString("invalid packet"); + quit = true; + break; + + case StringExtractorGDBRemote::eServerPacketType_unimplemented: + packet_result = SendUnimplementedResponse(packet.GetStringRef().c_str()); + break; + + default: + auto handler_it = m_packet_handlers.find(packet_type); + if (handler_it == m_packet_handlers.end()) + packet_result = + SendUnimplementedResponse(packet.GetStringRef().c_str()); + else + packet_result = handler_it->second(packet, error, interrupt, quit); + break; } - else - { - if (!IsConnected()) - { - error.SetErrorString("lost connection"); - quit = true; - } - else - { - error.SetErrorString("timeout"); - } + } else { + if (!IsConnected()) { + error.SetErrorString("lost connection"); + quit = true; + } else { + error.SetErrorString("timeout"); } + } - // Check if anything occurred that would force us to want to exit. - if (m_exit_now) - quit = true; + // Check if anything occurred that would force us to want to exit. + if (m_exit_now) + quit = true; - return packet_result; + return packet_result; } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::SendUnimplementedResponse (const char *) -{ - // TODO: Log the packet we aren't handling... - return SendPacketNoLock ("", 0); +GDBRemoteCommunicationServer::SendUnimplementedResponse(const char *) { + // TODO: Log the packet we aren't handling... + return SendPacketNoLock(""); } - GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::SendErrorResponse (uint8_t err) -{ - char packet[16]; - int packet_len = ::snprintf (packet, sizeof(packet), "E%2.2x", err); - assert (packet_len < (int)sizeof(packet)); - return SendPacketNoLock (packet, packet_len); +GDBRemoteCommunicationServer::SendErrorResponse(uint8_t err) { + char packet[16]; + int packet_len = ::snprintf(packet, sizeof(packet), "E%2.2x", err); + assert(packet_len < (int)sizeof(packet)); + return SendPacketNoLock(llvm::StringRef(packet, packet_len)); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::SendIllFormedResponse (const StringExtractorGDBRemote &failed_packet, const char *message) -{ - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS)); - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s: ILLFORMED: '%s' (%s)", __FUNCTION__, failed_packet.GetStringRef ().c_str (), message ? message : ""); - return SendErrorResponse (0x03); +GDBRemoteCommunicationServer::SendIllFormedResponse( + const StringExtractorGDBRemote &failed_packet, const char *message) { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS)); + if (log) + log->Printf("GDBRemoteCommunicationServer::%s: ILLFORMED: '%s' (%s)", + __FUNCTION__, failed_packet.GetStringRef().c_str(), + message ? message : ""); + return SendErrorResponse(0x03); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::SendOKResponse () -{ - return SendPacketNoLock ("OK", 2); +GDBRemoteCommunicationServer::SendOKResponse() { + return SendPacketNoLock("OK"); } -bool -GDBRemoteCommunicationServer::HandshakeWithClient() -{ - return GetAck() == PacketResult::Success; +bool GDBRemoteCommunicationServer::HandshakeWithClient() { + return GetAck() == PacketResult::Success; } diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h index 1d512bf..0c583e6 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h @@ -17,8 +17,8 @@ // Other libraries and framework includes // Project includes -#include "lldb/lldb-private-forward.h" #include "GDBRemoteCommunication.h" +#include "lldb/lldb-private-forward.h" class StringExtractorGDBRemote; @@ -27,52 +27,47 @@ namespace process_gdb_remote { class ProcessGDBRemote; -class GDBRemoteCommunicationServer : public GDBRemoteCommunication -{ +class GDBRemoteCommunicationServer : public GDBRemoteCommunication { public: - using PortMap = std::map<uint16_t, lldb::pid_t>; - using PacketHandler = std::function<PacketResult(StringExtractorGDBRemote &packet, - Error &error, - bool &interrupt, - bool &quit)>; + using PortMap = std::map<uint16_t, lldb::pid_t>; + using PacketHandler = + std::function<PacketResult(StringExtractorGDBRemote &packet, Error &error, + bool &interrupt, bool &quit)>; - GDBRemoteCommunicationServer(const char *comm_name, - const char *listener_name); + GDBRemoteCommunicationServer(const char *comm_name, + const char *listener_name); - ~GDBRemoteCommunicationServer() override; + ~GDBRemoteCommunicationServer() override; - void RegisterPacketHandler(StringExtractorGDBRemote::ServerPacketType packet_type, - PacketHandler handler); + void + RegisterPacketHandler(StringExtractorGDBRemote::ServerPacketType packet_type, + PacketHandler handler); - PacketResult - GetPacketAndSendResponse (uint32_t timeout_usec, - Error &error, - bool &interrupt, - bool &quit); + PacketResult GetPacketAndSendResponse(Timeout<std::micro> timeout, + Error &error, bool &interrupt, + bool &quit); - // After connecting, do a little handshake with the client to make sure - // we are at least communicating - bool - HandshakeWithClient (); + // After connecting, do a little handshake with the client to make sure + // we are at least communicating + bool HandshakeWithClient(); protected: - std::map<StringExtractorGDBRemote::ServerPacketType, PacketHandler> m_packet_handlers; - bool m_exit_now; // use in asynchronous handling to indicate process should exit. + std::map<StringExtractorGDBRemote::ServerPacketType, PacketHandler> + m_packet_handlers; + bool m_exit_now; // use in asynchronous handling to indicate process should + // exit. - PacketResult - SendUnimplementedResponse (const char *packet); + PacketResult SendUnimplementedResponse(const char *packet); - PacketResult - SendErrorResponse (uint8_t error); + PacketResult SendErrorResponse(uint8_t error); - PacketResult - SendIllFormedResponse (const StringExtractorGDBRemote &packet, const char *error_message); + PacketResult SendIllFormedResponse(const StringExtractorGDBRemote &packet, + const char *error_message); - PacketResult - SendOKResponse (); + PacketResult SendOKResponse(); private: - DISALLOW_COPY_AND_ASSIGN (GDBRemoteCommunicationServer); + DISALLOW_COPY_AND_ASSIGN(GDBRemoteCommunicationServer); }; } // namespace process_gdb_remote diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp index 26a2e69..e4e6810 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp @@ -12,12 +12,16 @@ #include <errno.h> // C Includes + +#ifdef __APPLE__ +#include <TargetConditionals.h> +#endif + // C++ Includes -#include <cstring> #include <chrono> +#include <cstring> // Other libraries and framework includes -#include "llvm/ADT/Triple.h" #include "lldb/Core/Log.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/StreamGDBRemote.h" @@ -34,6 +38,8 @@ #include "lldb/Target/FileAction.h" #include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" +#include "lldb/Utility/JSON.h" +#include "llvm/ADT/Triple.h" // Project includes #include "ProcessGDBRemoteLog.h" @@ -43,1214 +49,1252 @@ #include "lldb/Host/android/HostInfoAndroid.h" #endif +#include "llvm/ADT/StringSwitch.h" + using namespace lldb; using namespace lldb_private; using namespace lldb_private::process_gdb_remote; #ifdef __ANDROID__ - const static uint32_t g_default_packet_timeout_sec = 20; // seconds +const static uint32_t g_default_packet_timeout_sec = 20; // seconds #else - const static uint32_t g_default_packet_timeout_sec = 0; // not specified +const static uint32_t g_default_packet_timeout_sec = 0; // not specified #endif //---------------------------------------------------------------------- // GDBRemoteCommunicationServerCommon constructor //---------------------------------------------------------------------- -GDBRemoteCommunicationServerCommon::GDBRemoteCommunicationServerCommon(const char *comm_name, const char *listener_name) : - GDBRemoteCommunicationServer (comm_name, listener_name), - m_process_launch_info (), - m_process_launch_error (), - m_proc_infos (), - m_proc_infos_index (0), - m_thread_suffix_supported (false), - m_list_threads_in_stop_reply (false) -{ - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_A, - &GDBRemoteCommunicationServerCommon::Handle_A); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QEnvironment, - &GDBRemoteCommunicationServerCommon::Handle_QEnvironment); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QEnvironmentHexEncoded, - &GDBRemoteCommunicationServerCommon::Handle_QEnvironmentHexEncoded); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qfProcessInfo, - &GDBRemoteCommunicationServerCommon::Handle_qfProcessInfo); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qGroupName, - &GDBRemoteCommunicationServerCommon::Handle_qGroupName); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qHostInfo, - &GDBRemoteCommunicationServerCommon::Handle_qHostInfo); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QLaunchArch, - &GDBRemoteCommunicationServerCommon::Handle_QLaunchArch); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qLaunchSuccess, - &GDBRemoteCommunicationServerCommon::Handle_qLaunchSuccess); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QListThreadsInStopReply, - &GDBRemoteCommunicationServerCommon::Handle_QListThreadsInStopReply); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qEcho, - &GDBRemoteCommunicationServerCommon::Handle_qEcho); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qModuleInfo, - &GDBRemoteCommunicationServerCommon::Handle_qModuleInfo); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qPlatform_chmod, - &GDBRemoteCommunicationServerCommon::Handle_qPlatform_chmod); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qPlatform_mkdir, - &GDBRemoteCommunicationServerCommon::Handle_qPlatform_mkdir); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qPlatform_shell, - &GDBRemoteCommunicationServerCommon::Handle_qPlatform_shell); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qProcessInfoPID, - &GDBRemoteCommunicationServerCommon::Handle_qProcessInfoPID); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetDetachOnError, - &GDBRemoteCommunicationServerCommon::Handle_QSetDetachOnError); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetSTDERR, - &GDBRemoteCommunicationServerCommon::Handle_QSetSTDERR); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetSTDIN, - &GDBRemoteCommunicationServerCommon::Handle_QSetSTDIN); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetSTDOUT, - &GDBRemoteCommunicationServerCommon::Handle_QSetSTDOUT); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qSpeedTest, - &GDBRemoteCommunicationServerCommon::Handle_qSpeedTest); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qsProcessInfo, - &GDBRemoteCommunicationServerCommon::Handle_qsProcessInfo); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QStartNoAckMode, - &GDBRemoteCommunicationServerCommon::Handle_QStartNoAckMode); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qSupported, - &GDBRemoteCommunicationServerCommon::Handle_qSupported); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QThreadSuffixSupported, - &GDBRemoteCommunicationServerCommon::Handle_QThreadSuffixSupported); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qUserName, - &GDBRemoteCommunicationServerCommon::Handle_qUserName); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_close, - &GDBRemoteCommunicationServerCommon::Handle_vFile_Close); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_exists, - &GDBRemoteCommunicationServerCommon::Handle_vFile_Exists); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_md5, - &GDBRemoteCommunicationServerCommon::Handle_vFile_MD5); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_mode, - &GDBRemoteCommunicationServerCommon::Handle_vFile_Mode); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_open, - &GDBRemoteCommunicationServerCommon::Handle_vFile_Open); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_pread, - &GDBRemoteCommunicationServerCommon::Handle_vFile_pRead); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_pwrite, - &GDBRemoteCommunicationServerCommon::Handle_vFile_pWrite); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_size, - &GDBRemoteCommunicationServerCommon::Handle_vFile_Size); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_stat, - &GDBRemoteCommunicationServerCommon::Handle_vFile_Stat); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_symlink, - &GDBRemoteCommunicationServerCommon::Handle_vFile_symlink); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_unlink, - &GDBRemoteCommunicationServerCommon::Handle_vFile_unlink); +GDBRemoteCommunicationServerCommon::GDBRemoteCommunicationServerCommon( + const char *comm_name, const char *listener_name) + : GDBRemoteCommunicationServer(comm_name, listener_name), + m_process_launch_info(), m_process_launch_error(), m_proc_infos(), + m_proc_infos_index(0), m_thread_suffix_supported(false), + m_list_threads_in_stop_reply(false) { + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_A, + &GDBRemoteCommunicationServerCommon::Handle_A); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_QEnvironment, + &GDBRemoteCommunicationServerCommon::Handle_QEnvironment); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_QEnvironmentHexEncoded, + &GDBRemoteCommunicationServerCommon::Handle_QEnvironmentHexEncoded); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qfProcessInfo, + &GDBRemoteCommunicationServerCommon::Handle_qfProcessInfo); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qGroupName, + &GDBRemoteCommunicationServerCommon::Handle_qGroupName); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qHostInfo, + &GDBRemoteCommunicationServerCommon::Handle_qHostInfo); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_QLaunchArch, + &GDBRemoteCommunicationServerCommon::Handle_QLaunchArch); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qLaunchSuccess, + &GDBRemoteCommunicationServerCommon::Handle_qLaunchSuccess); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_QListThreadsInStopReply, + &GDBRemoteCommunicationServerCommon::Handle_QListThreadsInStopReply); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qEcho, + &GDBRemoteCommunicationServerCommon::Handle_qEcho); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qModuleInfo, + &GDBRemoteCommunicationServerCommon::Handle_qModuleInfo); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_jModulesInfo, + &GDBRemoteCommunicationServerCommon::Handle_jModulesInfo); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qPlatform_chmod, + &GDBRemoteCommunicationServerCommon::Handle_qPlatform_chmod); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qPlatform_mkdir, + &GDBRemoteCommunicationServerCommon::Handle_qPlatform_mkdir); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qPlatform_shell, + &GDBRemoteCommunicationServerCommon::Handle_qPlatform_shell); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qProcessInfoPID, + &GDBRemoteCommunicationServerCommon::Handle_qProcessInfoPID); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_QSetDetachOnError, + &GDBRemoteCommunicationServerCommon::Handle_QSetDetachOnError); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_QSetSTDERR, + &GDBRemoteCommunicationServerCommon::Handle_QSetSTDERR); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_QSetSTDIN, + &GDBRemoteCommunicationServerCommon::Handle_QSetSTDIN); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_QSetSTDOUT, + &GDBRemoteCommunicationServerCommon::Handle_QSetSTDOUT); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qSpeedTest, + &GDBRemoteCommunicationServerCommon::Handle_qSpeedTest); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qsProcessInfo, + &GDBRemoteCommunicationServerCommon::Handle_qsProcessInfo); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_QStartNoAckMode, + &GDBRemoteCommunicationServerCommon::Handle_QStartNoAckMode); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qSupported, + &GDBRemoteCommunicationServerCommon::Handle_qSupported); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_QThreadSuffixSupported, + &GDBRemoteCommunicationServerCommon::Handle_QThreadSuffixSupported); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qUserName, + &GDBRemoteCommunicationServerCommon::Handle_qUserName); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_vFile_close, + &GDBRemoteCommunicationServerCommon::Handle_vFile_Close); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_vFile_exists, + &GDBRemoteCommunicationServerCommon::Handle_vFile_Exists); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_vFile_md5, + &GDBRemoteCommunicationServerCommon::Handle_vFile_MD5); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_vFile_mode, + &GDBRemoteCommunicationServerCommon::Handle_vFile_Mode); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_vFile_open, + &GDBRemoteCommunicationServerCommon::Handle_vFile_Open); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_vFile_pread, + &GDBRemoteCommunicationServerCommon::Handle_vFile_pRead); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_vFile_pwrite, + &GDBRemoteCommunicationServerCommon::Handle_vFile_pWrite); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_vFile_size, + &GDBRemoteCommunicationServerCommon::Handle_vFile_Size); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_vFile_stat, + &GDBRemoteCommunicationServerCommon::Handle_vFile_Stat); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_vFile_symlink, + &GDBRemoteCommunicationServerCommon::Handle_vFile_symlink); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_vFile_unlink, + &GDBRemoteCommunicationServerCommon::Handle_vFile_unlink); } //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- -GDBRemoteCommunicationServerCommon::~GDBRemoteCommunicationServerCommon() -{ -} +GDBRemoteCommunicationServerCommon::~GDBRemoteCommunicationServerCommon() {} GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_qHostInfo (StringExtractorGDBRemote &packet) -{ - StreamString response; +GDBRemoteCommunicationServerCommon::Handle_qHostInfo( + StringExtractorGDBRemote &packet) { + StreamString response; - // $cputype:16777223;cpusubtype:3;ostype:Darwin;vendor:apple;endian:little;ptrsize:8;#00 + // $cputype:16777223;cpusubtype:3;ostype:Darwin;vendor:apple;endian:little;ptrsize:8;#00 - ArchSpec host_arch(HostInfo::GetArchitecture()); - const llvm::Triple &host_triple = host_arch.GetTriple(); - response.PutCString("triple:"); - response.PutCStringAsRawHex8(host_triple.getTriple().c_str()); - response.Printf (";ptrsize:%u;",host_arch.GetAddressByteSize()); - - const char* distribution_id = host_arch.GetDistributionId ().AsCString (); - if (distribution_id) - { - response.PutCString("distribution_id:"); - response.PutCStringAsRawHex8(distribution_id); - response.PutCString(";"); - } + ArchSpec host_arch(HostInfo::GetArchitecture()); + const llvm::Triple &host_triple = host_arch.GetTriple(); + response.PutCString("triple:"); + response.PutCStringAsRawHex8(host_triple.getTriple().c_str()); + response.Printf(";ptrsize:%u;", host_arch.GetAddressByteSize()); + + const char *distribution_id = host_arch.GetDistributionId().AsCString(); + if (distribution_id) { + response.PutCString("distribution_id:"); + response.PutCStringAsRawHex8(distribution_id); + response.PutCString(";"); + } - // Only send out MachO info when lldb-platform/llgs is running on a MachO host. #if defined(__APPLE__) - uint32_t cpu = host_arch.GetMachOCPUType(); - uint32_t sub = host_arch.GetMachOCPUSubType(); - if (cpu != LLDB_INVALID_CPUTYPE) - response.Printf ("cputype:%u;", cpu); - if (sub != LLDB_INVALID_CPUTYPE) - response.Printf ("cpusubtype:%u;", sub); - - if (cpu == ArchSpec::kCore_arm_any) - response.Printf("watchpoint_exceptions_received:before;"); // On armv7 we use "synchronous" watchpoints which means the exception is delivered before the instruction executes. - else - response.Printf("watchpoint_exceptions_received:after;"); + // For parity with debugserver, we'll include the vendor key. + response.PutCString("vendor:apple;"); + + // Send out MachO info. + uint32_t cpu = host_arch.GetMachOCPUType(); + uint32_t sub = host_arch.GetMachOCPUSubType(); + if (cpu != LLDB_INVALID_CPUTYPE) + response.Printf("cputype:%u;", cpu); + if (sub != LLDB_INVALID_CPUTYPE) + response.Printf("cpusubtype:%u;", sub); + + if (cpu == ArchSpec::kCore_arm_any) { +// Indicate the OS type. +#if defined(TARGET_OS_TV) && TARGET_OS_TV == 1 + response.PutCString("ostype:tvos;"); +#elif defined(TARGET_OS_WATCH) && TARGET_OS_WATCH == 1 + response.PutCString("ostype:watchos;"); #else - if (host_arch.GetMachine() == llvm::Triple::aarch64 || - host_arch.GetMachine() == llvm::Triple::aarch64_be || - host_arch.GetMachine() == llvm::Triple::arm || - host_arch.GetMachine() == llvm::Triple::armeb || - host_arch.GetMachine() == llvm::Triple::mips64 || - host_arch.GetMachine() == llvm::Triple::mips64el || - host_arch.GetMachine() == llvm::Triple::mips || - host_arch.GetMachine() == llvm::Triple::mipsel) - response.Printf("watchpoint_exceptions_received:before;"); - else - response.Printf("watchpoint_exceptions_received:after;"); + response.PutCString("ostype:ios;"); #endif - switch (endian::InlHostByteOrder()) - { - case eByteOrderBig: response.PutCString ("endian:big;"); break; - case eByteOrderLittle: response.PutCString ("endian:little;"); break; - case eByteOrderPDP: response.PutCString ("endian:pdp;"); break; - default: response.PutCString ("endian:unknown;"); break; - } + // On arm, we use "synchronous" watchpoints which means the exception is + // delivered before the instruction executes. + response.PutCString("watchpoint_exceptions_received:before;"); + } else { + response.PutCString("ostype:macosx;"); + response.Printf("watchpoint_exceptions_received:after;"); + } - uint32_t major = UINT32_MAX; - uint32_t minor = UINT32_MAX; - uint32_t update = UINT32_MAX; - if (HostInfo::GetOSVersion(major, minor, update)) - { - if (major != UINT32_MAX) - { - response.Printf("os_version:%u", major); - if (minor != UINT32_MAX) - { - response.Printf(".%u", minor); - if (update != UINT32_MAX) - response.Printf(".%u", update); - } - response.PutChar(';'); - } - } +#else + if (host_arch.GetMachine() == llvm::Triple::aarch64 || + host_arch.GetMachine() == llvm::Triple::aarch64_be || + host_arch.GetMachine() == llvm::Triple::arm || + host_arch.GetMachine() == llvm::Triple::armeb || + host_arch.GetMachine() == llvm::Triple::mips64 || + host_arch.GetMachine() == llvm::Triple::mips64el || + host_arch.GetMachine() == llvm::Triple::mips || + host_arch.GetMachine() == llvm::Triple::mipsel) + response.Printf("watchpoint_exceptions_received:before;"); + else + response.Printf("watchpoint_exceptions_received:after;"); +#endif - std::string s; - if (HostInfo::GetOSBuildString(s)) - { - response.PutCString ("os_build:"); - response.PutCStringAsRawHex8(s.c_str()); - response.PutChar(';'); - } - if (HostInfo::GetOSKernelDescription(s)) - { - response.PutCString ("os_kernel:"); - response.PutCStringAsRawHex8(s.c_str()); - response.PutChar(';'); + switch (endian::InlHostByteOrder()) { + case eByteOrderBig: + response.PutCString("endian:big;"); + break; + case eByteOrderLittle: + response.PutCString("endian:little;"); + break; + case eByteOrderPDP: + response.PutCString("endian:pdp;"); + break; + default: + response.PutCString("endian:unknown;"); + break; + } + + uint32_t major = UINT32_MAX; + uint32_t minor = UINT32_MAX; + uint32_t update = UINT32_MAX; + if (HostInfo::GetOSVersion(major, minor, update)) { + if (major != UINT32_MAX) { + response.Printf("os_version:%u", major); + if (minor != UINT32_MAX) { + response.Printf(".%u", minor); + if (update != UINT32_MAX) + response.Printf(".%u", update); + } + response.PutChar(';'); } + } + + std::string s; + if (HostInfo::GetOSBuildString(s)) { + response.PutCString("os_build:"); + response.PutCStringAsRawHex8(s.c_str()); + response.PutChar(';'); + } + if (HostInfo::GetOSKernelDescription(s)) { + response.PutCString("os_kernel:"); + response.PutCStringAsRawHex8(s.c_str()); + response.PutChar(';'); + } #if defined(__APPLE__) #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) - // For iOS devices, we are connected through a USB Mux so we never pretend - // to actually have a hostname as far as the remote lldb that is connecting - // to this lldb-platform is concerned - response.PutCString ("hostname:"); - response.PutCStringAsRawHex8("127.0.0.1"); + // For iOS devices, we are connected through a USB Mux so we never pretend + // to actually have a hostname as far as the remote lldb that is connecting + // to this lldb-platform is concerned + response.PutCString("hostname:"); + response.PutCStringAsRawHex8("127.0.0.1"); + response.PutChar(';'); +#else // #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) + if (HostInfo::GetHostname(s)) { + response.PutCString("hostname:"); + response.PutCStringAsRawHex8(s.c_str()); response.PutChar(';'); -#else // #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) - if (HostInfo::GetHostname(s)) - { - response.PutCString ("hostname:"); - response.PutCStringAsRawHex8(s.c_str()); - response.PutChar(';'); - } -#endif // #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) + } +#endif // #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) -#else // #if defined(__APPLE__) - if (HostInfo::GetHostname(s)) - { - response.PutCString ("hostname:"); - response.PutCStringAsRawHex8(s.c_str()); - response.PutChar(';'); - } -#endif // #if defined(__APPLE__) +#else // #if defined(__APPLE__) + if (HostInfo::GetHostname(s)) { + response.PutCString("hostname:"); + response.PutCStringAsRawHex8(s.c_str()); + response.PutChar(';'); + } +#endif // #if defined(__APPLE__) - if (g_default_packet_timeout_sec > 0) - response.Printf ("default_packet_timeout:%u;", g_default_packet_timeout_sec); + if (g_default_packet_timeout_sec > 0) + response.Printf("default_packet_timeout:%u;", g_default_packet_timeout_sec); - return SendPacketNoLock (response.GetData(), response.GetSize()); + return SendPacketNoLock(response.GetString()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_qProcessInfoPID (StringExtractorGDBRemote &packet) -{ - // Packet format: "qProcessInfoPID:%i" where %i is the pid - packet.SetFilePos (::strlen ("qProcessInfoPID:")); - lldb::pid_t pid = packet.GetU32 (LLDB_INVALID_PROCESS_ID); - if (pid != LLDB_INVALID_PROCESS_ID) - { - ProcessInstanceInfo proc_info; - if (Host::GetProcessInfo (pid, proc_info)) - { - StreamString response; - CreateProcessInfoResponse (proc_info, response); - return SendPacketNoLock (response.GetData(), response.GetSize()); - } +GDBRemoteCommunicationServerCommon::Handle_qProcessInfoPID( + StringExtractorGDBRemote &packet) { + // Packet format: "qProcessInfoPID:%i" where %i is the pid + packet.SetFilePos(::strlen("qProcessInfoPID:")); + lldb::pid_t pid = packet.GetU32(LLDB_INVALID_PROCESS_ID); + if (pid != LLDB_INVALID_PROCESS_ID) { + ProcessInstanceInfo proc_info; + if (Host::GetProcessInfo(pid, proc_info)) { + StreamString response; + CreateProcessInfoResponse(proc_info, response); + return SendPacketNoLock(response.GetString()); } - return SendErrorResponse (1); + } + return SendErrorResponse(1); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_qfProcessInfo (StringExtractorGDBRemote &packet) -{ - m_proc_infos_index = 0; - m_proc_infos.Clear(); - - ProcessInstanceInfoMatch match_info; - packet.SetFilePos(::strlen ("qfProcessInfo")); - if (packet.GetChar() == ':') - { - - std::string key; - std::string value; - while (packet.GetNameColonValue(key, value)) - { - bool success = true; - if (key.compare("name") == 0) - { - StringExtractor extractor; - extractor.GetStringRef().swap(value); - extractor.GetHexByteString (value); - match_info.GetProcessInfo().GetExecutableFile().SetFile(value.c_str(), false); - } - else if (key.compare("name_match") == 0) - { - if (value.compare("equals") == 0) - { - match_info.SetNameMatchType (eNameMatchEquals); - } - else if (value.compare("starts_with") == 0) - { - match_info.SetNameMatchType (eNameMatchStartsWith); - } - else if (value.compare("ends_with") == 0) - { - match_info.SetNameMatchType (eNameMatchEndsWith); - } - else if (value.compare("contains") == 0) - { - match_info.SetNameMatchType (eNameMatchContains); - } - else if (value.compare("regex") == 0) - { - match_info.SetNameMatchType (eNameMatchRegularExpression); - } - else - { - success = false; - } - } - else if (key.compare("pid") == 0) - { - match_info.GetProcessInfo().SetProcessID (StringConvert::ToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0, &success)); - } - else if (key.compare("parent_pid") == 0) - { - match_info.GetProcessInfo().SetParentProcessID (StringConvert::ToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0, &success)); - } - else if (key.compare("uid") == 0) - { - match_info.GetProcessInfo().SetUserID (StringConvert::ToUInt32(value.c_str(), UINT32_MAX, 0, &success)); - } - else if (key.compare("gid") == 0) - { - match_info.GetProcessInfo().SetGroupID (StringConvert::ToUInt32(value.c_str(), UINT32_MAX, 0, &success)); - } - else if (key.compare("euid") == 0) - { - match_info.GetProcessInfo().SetEffectiveUserID (StringConvert::ToUInt32(value.c_str(), UINT32_MAX, 0, &success)); - } - else if (key.compare("egid") == 0) - { - match_info.GetProcessInfo().SetEffectiveGroupID (StringConvert::ToUInt32(value.c_str(), UINT32_MAX, 0, &success)); - } - else if (key.compare("all_users") == 0) - { - match_info.SetMatchAllUsers(Args::StringToBoolean(value.c_str(), false, &success)); - } - else if (key.compare("triple") == 0) - { - match_info.GetProcessInfo().GetArchitecture().SetTriple (value.c_str(), NULL); - } - else - { - success = false; - } - - if (!success) - return SendErrorResponse (2); - } - } - - if (Host::FindProcesses (match_info, m_proc_infos)) - { - // We found something, return the first item by calling the get - // subsequent process info packet handler... - return Handle_qsProcessInfo (packet); +GDBRemoteCommunicationServerCommon::Handle_qfProcessInfo( + StringExtractorGDBRemote &packet) { + m_proc_infos_index = 0; + m_proc_infos.Clear(); + + ProcessInstanceInfoMatch match_info; + packet.SetFilePos(::strlen("qfProcessInfo")); + if (packet.GetChar() == ':') { + llvm::StringRef key; + llvm::StringRef value; + while (packet.GetNameColonValue(key, value)) { + bool success = true; + if (key.equals("name")) { + StringExtractor extractor(value); + std::string file; + extractor.GetHexByteString(file); + match_info.GetProcessInfo().GetExecutableFile().SetFile(file, false); + } else if (key.equals("name_match")) { + NameMatchType name_match = + llvm::StringSwitch<NameMatchType>(value) + .Case("equals", eNameMatchEquals) + .Case("starts_with", eNameMatchStartsWith) + .Case("ends_with", eNameMatchEndsWith) + .Case("contains", eNameMatchContains) + .Case("regex", eNameMatchRegularExpression) + .Default(eNameMatchIgnore); + match_info.SetNameMatchType(name_match); + if (name_match == eNameMatchIgnore) + return SendErrorResponse(2); + } else if (key.equals("pid")) { + lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; + if (value.getAsInteger(0, pid)) + return SendErrorResponse(2); + match_info.GetProcessInfo().SetProcessID(pid); + } else if (key.equals("parent_pid")) { + lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; + if (value.getAsInteger(0, pid)) + return SendErrorResponse(2); + match_info.GetProcessInfo().SetParentProcessID(pid); + } else if (key.equals("uid")) { + uint32_t uid = UINT32_MAX; + if (value.getAsInteger(0, uid)) + return SendErrorResponse(2); + match_info.GetProcessInfo().SetUserID(uid); + } else if (key.equals("gid")) { + uint32_t gid = UINT32_MAX; + if (value.getAsInteger(0, gid)) + return SendErrorResponse(2); + match_info.GetProcessInfo().SetGroupID(gid); + } else if (key.equals("euid")) { + uint32_t uid = UINT32_MAX; + if (value.getAsInteger(0, uid)) + return SendErrorResponse(2); + match_info.GetProcessInfo().SetEffectiveUserID(uid); + } else if (key.equals("egid")) { + uint32_t gid = UINT32_MAX; + if (value.getAsInteger(0, gid)) + return SendErrorResponse(2); + match_info.GetProcessInfo().SetEffectiveGroupID(gid); + } else if (key.equals("all_users")) { + match_info.SetMatchAllUsers( + Args::StringToBoolean(value, false, &success)); + } else if (key.equals("triple")) { + match_info.GetProcessInfo().GetArchitecture().SetTriple( + value.str().c_str(), NULL); + } else { + success = false; + } + + if (!success) + return SendErrorResponse(2); } - return SendErrorResponse (3); + } + + if (Host::FindProcesses(match_info, m_proc_infos)) { + // We found something, return the first item by calling the get + // subsequent process info packet handler... + return Handle_qsProcessInfo(packet); + } + return SendErrorResponse(3); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_qsProcessInfo (StringExtractorGDBRemote &packet) -{ - if (m_proc_infos_index < m_proc_infos.GetSize()) - { - StreamString response; - CreateProcessInfoResponse (m_proc_infos.GetProcessInfoAtIndex(m_proc_infos_index), response); - ++m_proc_infos_index; - return SendPacketNoLock (response.GetData(), response.GetSize()); - } - return SendErrorResponse (4); +GDBRemoteCommunicationServerCommon::Handle_qsProcessInfo( + StringExtractorGDBRemote &packet) { + if (m_proc_infos_index < m_proc_infos.GetSize()) { + StreamString response; + CreateProcessInfoResponse( + m_proc_infos.GetProcessInfoAtIndex(m_proc_infos_index), response); + ++m_proc_infos_index; + return SendPacketNoLock(response.GetString()); + } + return SendErrorResponse(4); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_qUserName (StringExtractorGDBRemote &packet) -{ +GDBRemoteCommunicationServerCommon::Handle_qUserName( + StringExtractorGDBRemote &packet) { #if !defined(LLDB_DISABLE_POSIX) - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf("GDBRemoteCommunicationServerCommon::%s begin", __FUNCTION__); - - // Packet format: "qUserName:%i" where %i is the uid - packet.SetFilePos(::strlen ("qUserName:")); - uint32_t uid = packet.GetU32 (UINT32_MAX); - if (uid != UINT32_MAX) - { - std::string name; - if (HostInfo::LookupUserName(uid, name)) - { - StreamString response; - response.PutCStringAsRawHex8 (name.c_str()); - return SendPacketNoLock (response.GetData(), response.GetSize()); - } + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf("GDBRemoteCommunicationServerCommon::%s begin", __FUNCTION__); + + // Packet format: "qUserName:%i" where %i is the uid + packet.SetFilePos(::strlen("qUserName:")); + uint32_t uid = packet.GetU32(UINT32_MAX); + if (uid != UINT32_MAX) { + std::string name; + if (HostInfo::LookupUserName(uid, name)) { + StreamString response; + response.PutCStringAsRawHex8(name.c_str()); + return SendPacketNoLock(response.GetString()); } - if (log) - log->Printf("GDBRemoteCommunicationServerCommon::%s end", __FUNCTION__); + } + if (log) + log->Printf("GDBRemoteCommunicationServerCommon::%s end", __FUNCTION__); #endif - return SendErrorResponse (5); - + return SendErrorResponse(5); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_qGroupName (StringExtractorGDBRemote &packet) -{ +GDBRemoteCommunicationServerCommon::Handle_qGroupName( + StringExtractorGDBRemote &packet) { #if !defined(LLDB_DISABLE_POSIX) - // Packet format: "qGroupName:%i" where %i is the gid - packet.SetFilePos(::strlen ("qGroupName:")); - uint32_t gid = packet.GetU32 (UINT32_MAX); - if (gid != UINT32_MAX) - { - std::string name; - if (HostInfo::LookupGroupName(gid, name)) - { - StreamString response; - response.PutCStringAsRawHex8 (name.c_str()); - return SendPacketNoLock (response.GetData(), response.GetSize()); - } + // Packet format: "qGroupName:%i" where %i is the gid + packet.SetFilePos(::strlen("qGroupName:")); + uint32_t gid = packet.GetU32(UINT32_MAX); + if (gid != UINT32_MAX) { + std::string name; + if (HostInfo::LookupGroupName(gid, name)) { + StreamString response; + response.PutCStringAsRawHex8(name.c_str()); + return SendPacketNoLock(response.GetString()); } + } #endif - return SendErrorResponse (6); + return SendErrorResponse(6); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_qSpeedTest (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen ("qSpeedTest:")); - - std::string key; - std::string value; - bool success = packet.GetNameColonValue(key, value); - if (success && key.compare("response_size") == 0) - { - uint32_t response_size = StringConvert::ToUInt32(value.c_str(), 0, 0, &success); - if (success) - { - if (response_size == 0) - return SendOKResponse(); - StreamString response; - uint32_t bytes_left = response_size; - response.PutCString("data:"); - while (bytes_left > 0) - { - if (bytes_left >= 26) - { - response.PutCString("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); - bytes_left -= 26; - } - else - { - response.Printf ("%*.*s;", bytes_left, bytes_left, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); - bytes_left = 0; - } - } - return SendPacketNoLock (response.GetData(), response.GetSize()); +GDBRemoteCommunicationServerCommon::Handle_qSpeedTest( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("qSpeedTest:")); + + llvm::StringRef key; + llvm::StringRef value; + bool success = packet.GetNameColonValue(key, value); + if (success && key.equals("response_size")) { + uint32_t response_size = 0; + if (!value.getAsInteger(0, response_size)) { + if (response_size == 0) + return SendOKResponse(); + StreamString response; + uint32_t bytes_left = response_size; + response.PutCString("data:"); + while (bytes_left > 0) { + if (bytes_left >= 26) { + response.PutCString("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); + bytes_left -= 26; + } else { + response.Printf("%*.*s;", bytes_left, bytes_left, + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); + bytes_left = 0; } + } + return SendPacketNoLock(response.GetString()); } - return SendErrorResponse (7); + } + return SendErrorResponse(7); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_vFile_Open (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen("vFile:open:")); - std::string path; - packet.GetHexByteStringTerminatedBy(path,','); - if (!path.empty()) - { - if (packet.GetChar() == ',') - { - uint32_t flags = File::ConvertOpenOptionsForPOSIXOpen( - packet.GetHexMaxU32(false, 0)); - if (packet.GetChar() == ',') - { - mode_t mode = packet.GetHexMaxU32(false, 0600); - Error error; - const FileSpec path_spec{path, true}; - int fd = ::open(path_spec.GetCString(), flags, mode); - const int save_errno = fd == -1 ? errno : 0; - StreamString response; - response.PutChar('F'); - response.Printf("%i", fd); - if (save_errno) - response.Printf(",%i", save_errno); - return SendPacketNoLock(response.GetData(), response.GetSize()); - } - } +GDBRemoteCommunicationServerCommon::Handle_vFile_Open( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("vFile:open:")); + std::string path; + packet.GetHexByteStringTerminatedBy(path, ','); + if (!path.empty()) { + if (packet.GetChar() == ',') { + uint32_t flags = + File::ConvertOpenOptionsForPOSIXOpen(packet.GetHexMaxU32(false, 0)); + if (packet.GetChar() == ',') { + mode_t mode = packet.GetHexMaxU32(false, 0600); + Error error; + const FileSpec path_spec{path, true}; + int fd = ::open(path_spec.GetCString(), flags, mode); + const int save_errno = fd == -1 ? errno : 0; + StreamString response; + response.PutChar('F'); + response.Printf("%i", fd); + if (save_errno) + response.Printf(",%i", save_errno); + return SendPacketNoLock(response.GetString()); + } } - return SendErrorResponse(18); + } + return SendErrorResponse(18); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_vFile_Close (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen("vFile:close:")); - int fd = packet.GetS32(-1); - Error error; - int err = -1; - int save_errno = 0; - if (fd >= 0) - { - err = close(fd); - save_errno = err == -1 ? errno : 0; - } - else - { - save_errno = EINVAL; - } - StreamString response; - response.PutChar('F'); - response.Printf("%i", err); - if (save_errno) - response.Printf(",%i", save_errno); - return SendPacketNoLock(response.GetData(), response.GetSize()); +GDBRemoteCommunicationServerCommon::Handle_vFile_Close( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("vFile:close:")); + int fd = packet.GetS32(-1); + Error error; + int err = -1; + int save_errno = 0; + if (fd >= 0) { + err = close(fd); + save_errno = err == -1 ? errno : 0; + } else { + save_errno = EINVAL; + } + StreamString response; + response.PutChar('F'); + response.Printf("%i", err); + if (save_errno) + response.Printf(",%i", save_errno); + return SendPacketNoLock(response.GetString()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_vFile_pRead (StringExtractorGDBRemote &packet) -{ +GDBRemoteCommunicationServerCommon::Handle_vFile_pRead( + StringExtractorGDBRemote &packet) { #ifdef _WIN32 - // Not implemented on Windows - return SendUnimplementedResponse("GDBRemoteCommunicationServerCommon::Handle_vFile_pRead() unimplemented"); + // Not implemented on Windows + return SendUnimplementedResponse( + "GDBRemoteCommunicationServerCommon::Handle_vFile_pRead() unimplemented"); #else - StreamGDBRemote response; - packet.SetFilePos(::strlen("vFile:pread:")); - int fd = packet.GetS32(-1); - if (packet.GetChar() == ',') - { - uint64_t count = packet.GetU64(UINT64_MAX); - if (packet.GetChar() == ',') - { - uint64_t offset = packet.GetU64(UINT32_MAX); - if (count == UINT64_MAX) - { - response.Printf("F-1:%i", EINVAL); - return SendPacketNoLock(response.GetData(), response.GetSize()); - } - - std::string buffer(count, 0); - const ssize_t bytes_read = ::pread (fd, &buffer[0], buffer.size(), offset); - const int save_errno = bytes_read == -1 ? errno : 0; - response.PutChar('F'); - response.Printf("%zi", bytes_read); - if (save_errno) - response.Printf(",%i", save_errno); - else - { - response.PutChar(';'); - response.PutEscapedBytes(&buffer[0], bytes_read); - } - return SendPacketNoLock(response.GetData(), response.GetSize()); - } + StreamGDBRemote response; + packet.SetFilePos(::strlen("vFile:pread:")); + int fd = packet.GetS32(-1); + if (packet.GetChar() == ',') { + uint64_t count = packet.GetU64(UINT64_MAX); + if (packet.GetChar() == ',') { + uint64_t offset = packet.GetU64(UINT32_MAX); + if (count == UINT64_MAX) { + response.Printf("F-1:%i", EINVAL); + return SendPacketNoLock(response.GetString()); + } + + std::string buffer(count, 0); + const ssize_t bytes_read = ::pread(fd, &buffer[0], buffer.size(), offset); + const int save_errno = bytes_read == -1 ? errno : 0; + response.PutChar('F'); + response.Printf("%zi", bytes_read); + if (save_errno) + response.Printf(",%i", save_errno); + else { + response.PutChar(';'); + response.PutEscapedBytes(&buffer[0], bytes_read); + } + return SendPacketNoLock(response.GetString()); } - return SendErrorResponse(21); + } + return SendErrorResponse(21); #endif } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_vFile_pWrite (StringExtractorGDBRemote &packet) -{ +GDBRemoteCommunicationServerCommon::Handle_vFile_pWrite( + StringExtractorGDBRemote &packet) { #ifdef _WIN32 - return SendUnimplementedResponse("GDBRemoteCommunicationServerCommon::Handle_vFile_pWrite() unimplemented"); + return SendUnimplementedResponse("GDBRemoteCommunicationServerCommon::Handle_" + "vFile_pWrite() unimplemented"); #else - packet.SetFilePos(::strlen("vFile:pwrite:")); - - StreamGDBRemote response; - response.PutChar('F'); - - int fd = packet.GetU32(UINT32_MAX); - if (packet.GetChar() == ',') - { - off_t offset = packet.GetU64(UINT32_MAX); - if (packet.GetChar() == ',') - { - std::string buffer; - if (packet.GetEscapedBinaryData(buffer)) - { - const ssize_t bytes_written = ::pwrite (fd, buffer.data(), buffer.size(), offset); - const int save_errno = bytes_written == -1 ? errno : 0; - response.Printf("%zi", bytes_written); - if (save_errno) - response.Printf(",%i", save_errno); - } - else - { - response.Printf ("-1,%i", EINVAL); - } - return SendPacketNoLock(response.GetData(), response.GetSize()); - } + packet.SetFilePos(::strlen("vFile:pwrite:")); + + StreamGDBRemote response; + response.PutChar('F'); + + int fd = packet.GetU32(UINT32_MAX); + if (packet.GetChar() == ',') { + off_t offset = packet.GetU64(UINT32_MAX); + if (packet.GetChar() == ',') { + std::string buffer; + if (packet.GetEscapedBinaryData(buffer)) { + const ssize_t bytes_written = + ::pwrite(fd, buffer.data(), buffer.size(), offset); + const int save_errno = bytes_written == -1 ? errno : 0; + response.Printf("%zi", bytes_written); + if (save_errno) + response.Printf(",%i", save_errno); + } else { + response.Printf("-1,%i", EINVAL); + } + return SendPacketNoLock(response.GetString()); } - return SendErrorResponse(27); + } + return SendErrorResponse(27); #endif } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_vFile_Size (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen("vFile:size:")); - std::string path; - packet.GetHexByteString(path); - if (!path.empty()) - { - lldb::user_id_t retcode = FileSystem::GetFileSize(FileSpec(path.c_str(), false)); - StreamString response; - response.PutChar('F'); - response.PutHex64(retcode); - if (retcode == UINT64_MAX) - { - response.PutChar(','); - response.PutHex64(retcode); // TODO: replace with Host::GetSyswideErrorCode() - } - return SendPacketNoLock(response.GetData(), response.GetSize()); +GDBRemoteCommunicationServerCommon::Handle_vFile_Size( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("vFile:size:")); + std::string path; + packet.GetHexByteString(path); + if (!path.empty()) { + lldb::user_id_t retcode = FileSystem::GetFileSize(FileSpec(path, false)); + StreamString response; + response.PutChar('F'); + response.PutHex64(retcode); + if (retcode == UINT64_MAX) { + response.PutChar(','); + response.PutHex64( + retcode); // TODO: replace with Host::GetSyswideErrorCode() } - return SendErrorResponse(22); + return SendPacketNoLock(response.GetString()); + } + return SendErrorResponse(22); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_vFile_Mode (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen("vFile:mode:")); - std::string path; - packet.GetHexByteString(path); - if (!path.empty()) - { - Error error; - const uint32_t mode = File::GetPermissions(FileSpec{path, true}, error); - StreamString response; - response.Printf("F%u", mode); - if (mode == 0 || error.Fail()) - response.Printf(",%i", (int)error.GetError()); - return SendPacketNoLock(response.GetData(), response.GetSize()); - } - return SendErrorResponse(23); +GDBRemoteCommunicationServerCommon::Handle_vFile_Mode( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("vFile:mode:")); + std::string path; + packet.GetHexByteString(path); + if (!path.empty()) { + Error error; + const uint32_t mode = File::GetPermissions(FileSpec{path, true}, error); + StreamString response; + response.Printf("F%u", mode); + if (mode == 0 || error.Fail()) + response.Printf(",%i", (int)error.GetError()); + return SendPacketNoLock(response.GetString()); + } + return SendErrorResponse(23); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_vFile_Exists (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen("vFile:exists:")); - std::string path; - packet.GetHexByteString(path); - if (!path.empty()) - { - bool retcode = FileSystem::GetFileExists(FileSpec(path.c_str(), false)); - StreamString response; - response.PutChar('F'); - response.PutChar(','); - if (retcode) - response.PutChar('1'); - else - response.PutChar('0'); - return SendPacketNoLock(response.GetData(), response.GetSize()); - } - return SendErrorResponse(24); +GDBRemoteCommunicationServerCommon::Handle_vFile_Exists( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("vFile:exists:")); + std::string path; + packet.GetHexByteString(path); + if (!path.empty()) { + bool retcode = FileSystem::GetFileExists(FileSpec(path, false)); + StreamString response; + response.PutChar('F'); + response.PutChar(','); + if (retcode) + response.PutChar('1'); + else + response.PutChar('0'); + return SendPacketNoLock(response.GetString()); + } + return SendErrorResponse(24); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_vFile_symlink (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen("vFile:symlink:")); - std::string dst, src; - packet.GetHexByteStringTerminatedBy(dst, ','); - packet.GetChar(); // Skip ',' char - packet.GetHexByteString(src); - Error error = FileSystem::Symlink(FileSpec{src, true}, FileSpec{dst, false}); - StreamString response; - response.Printf("F%u,%u", error.GetError(), error.GetError()); - return SendPacketNoLock(response.GetData(), response.GetSize()); +GDBRemoteCommunicationServerCommon::Handle_vFile_symlink( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("vFile:symlink:")); + std::string dst, src; + packet.GetHexByteStringTerminatedBy(dst, ','); + packet.GetChar(); // Skip ',' char + packet.GetHexByteString(src); + Error error = FileSystem::Symlink(FileSpec{src, true}, FileSpec{dst, false}); + StreamString response; + response.Printf("F%u,%u", error.GetError(), error.GetError()); + return SendPacketNoLock(response.GetString()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_vFile_unlink (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen("vFile:unlink:")); - std::string path; - packet.GetHexByteString(path); - Error error = FileSystem::Unlink(FileSpec{path, true}); - StreamString response; - response.Printf("F%u,%u", error.GetError(), error.GetError()); - return SendPacketNoLock(response.GetData(), response.GetSize()); +GDBRemoteCommunicationServerCommon::Handle_vFile_unlink( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("vFile:unlink:")); + std::string path; + packet.GetHexByteString(path); + Error error = FileSystem::Unlink(FileSpec{path, true}); + StreamString response; + response.Printf("F%u,%u", error.GetError(), error.GetError()); + return SendPacketNoLock(response.GetString()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_qPlatform_shell (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen("qPlatform_shell:")); - std::string path; - std::string working_dir; - packet.GetHexByteStringTerminatedBy(path,','); - if (!path.empty()) - { - if (packet.GetChar() == ',') - { - // FIXME: add timeout to qPlatform_shell packet - // uint32_t timeout = packet.GetHexMaxU32(false, 32); - uint32_t timeout = 10; - if (packet.GetChar() == ',') - packet.GetHexByteString(working_dir); - int status, signo; - std::string output; - Error err = Host::RunShellCommand(path.c_str(), - FileSpec{working_dir, true}, - &status, &signo, &output, timeout); - StreamGDBRemote response; - if (err.Fail()) - { - response.PutCString("F,"); - response.PutHex32(UINT32_MAX); - } - else - { - response.PutCString("F,"); - response.PutHex32(status); - response.PutChar(','); - response.PutHex32(signo); - response.PutChar(','); - response.PutEscapedBytes(output.c_str(), output.size()); - } - return SendPacketNoLock(response.GetData(), response.GetSize()); - } +GDBRemoteCommunicationServerCommon::Handle_qPlatform_shell( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("qPlatform_shell:")); + std::string path; + std::string working_dir; + packet.GetHexByteStringTerminatedBy(path, ','); + if (!path.empty()) { + if (packet.GetChar() == ',') { + // FIXME: add timeout to qPlatform_shell packet + // uint32_t timeout = packet.GetHexMaxU32(false, 32); + uint32_t timeout = 10; + if (packet.GetChar() == ',') + packet.GetHexByteString(working_dir); + int status, signo; + std::string output; + Error err = + Host::RunShellCommand(path.c_str(), FileSpec{working_dir, true}, + &status, &signo, &output, timeout); + StreamGDBRemote response; + if (err.Fail()) { + response.PutCString("F,"); + response.PutHex32(UINT32_MAX); + } else { + response.PutCString("F,"); + response.PutHex32(status); + response.PutChar(','); + response.PutHex32(signo); + response.PutChar(','); + response.PutEscapedBytes(output.c_str(), output.size()); + } + return SendPacketNoLock(response.GetString()); } - return SendErrorResponse(24); + } + return SendErrorResponse(24); } - GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_vFile_Stat (StringExtractorGDBRemote &packet) -{ - return SendUnimplementedResponse("GDBRemoteCommunicationServerCommon::Handle_vFile_Stat() unimplemented"); +GDBRemoteCommunicationServerCommon::Handle_vFile_Stat( + StringExtractorGDBRemote &packet) { + return SendUnimplementedResponse( + "GDBRemoteCommunicationServerCommon::Handle_vFile_Stat() unimplemented"); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_vFile_MD5 (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen("vFile:MD5:")); - std::string path; - packet.GetHexByteString(path); - if (!path.empty()) - { - uint64_t a,b; - StreamGDBRemote response; - if (!FileSystem::CalculateMD5(FileSpec(path.c_str(), false), a, b)) - { - response.PutCString("F,"); - response.PutCString("x"); - } - else - { - response.PutCString("F,"); - response.PutHex64(a); - response.PutHex64(b); - } - return SendPacketNoLock(response.GetData(), response.GetSize()); +GDBRemoteCommunicationServerCommon::Handle_vFile_MD5( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("vFile:MD5:")); + std::string path; + packet.GetHexByteString(path); + if (!path.empty()) { + uint64_t a, b; + StreamGDBRemote response; + if (!FileSystem::CalculateMD5(FileSpec(path, false), a, b)) { + response.PutCString("F,"); + response.PutCString("x"); + } else { + response.PutCString("F,"); + response.PutHex64(a); + response.PutHex64(b); } - return SendErrorResponse(25); + return SendPacketNoLock(response.GetString()); + } + return SendErrorResponse(25); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_qPlatform_mkdir (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen("qPlatform_mkdir:")); - mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX); - if (packet.GetChar() == ',') - { - std::string path; - packet.GetHexByteString(path); - Error error = FileSystem::MakeDirectory(FileSpec{path, false}, mode); - - StreamGDBRemote response; - response.Printf("F%u", error.GetError()); - - return SendPacketNoLock(response.GetData(), response.GetSize()); - } - return SendErrorResponse(20); +GDBRemoteCommunicationServerCommon::Handle_qPlatform_mkdir( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("qPlatform_mkdir:")); + mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX); + if (packet.GetChar() == ',') { + std::string path; + packet.GetHexByteString(path); + Error error = FileSystem::MakeDirectory(FileSpec{path, false}, mode); + + StreamGDBRemote response; + response.Printf("F%u", error.GetError()); + + return SendPacketNoLock(response.GetString()); + } + return SendErrorResponse(20); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_qPlatform_chmod (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen("qPlatform_chmod:")); +GDBRemoteCommunicationServerCommon::Handle_qPlatform_chmod( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("qPlatform_chmod:")); - mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX); - if (packet.GetChar() == ',') - { - std::string path; - packet.GetHexByteString(path); - Error error = FileSystem::SetFilePermissions(FileSpec{path, true}, mode); + mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX); + if (packet.GetChar() == ',') { + std::string path; + packet.GetHexByteString(path); + Error error = FileSystem::SetFilePermissions(FileSpec{path, true}, mode); - StreamGDBRemote response; - response.Printf("F%u", error.GetError()); + StreamGDBRemote response; + response.Printf("F%u", error.GetError()); - return SendPacketNoLock(response.GetData(), response.GetSize()); - } - return SendErrorResponse(19); + return SendPacketNoLock(response.GetString()); + } + return SendErrorResponse(19); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_qSupported (StringExtractorGDBRemote &packet) -{ - StreamGDBRemote response; - - // Features common to lldb-platform and llgs. - uint32_t max_packet_size = 128 * 1024; // 128KBytes is a reasonable max packet size--debugger can always use less - response.Printf ("PacketSize=%x", max_packet_size); - - response.PutCString (";QStartNoAckMode+"); - response.PutCString (";QThreadSuffixSupported+"); - response.PutCString (";QListThreadsInStopReply+"); - response.PutCString (";qEcho+"); +GDBRemoteCommunicationServerCommon::Handle_qSupported( + StringExtractorGDBRemote &packet) { + StreamGDBRemote response; + + // Features common to lldb-platform and llgs. + uint32_t max_packet_size = 128 * 1024; // 128KBytes is a reasonable max packet + // size--debugger can always use less + response.Printf("PacketSize=%x", max_packet_size); + + response.PutCString(";QStartNoAckMode+"); + response.PutCString(";QThreadSuffixSupported+"); + response.PutCString(";QListThreadsInStopReply+"); + response.PutCString(";qEcho+"); #if defined(__linux__) - response.PutCString (";qXfer:auxv:read+"); + response.PutCString(";qXfer:auxv:read+"); #endif - return SendPacketNoLock(response.GetData(), response.GetSize()); + return SendPacketNoLock(response.GetString()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_QThreadSuffixSupported (StringExtractorGDBRemote &packet) -{ - m_thread_suffix_supported = true; - return SendOKResponse(); +GDBRemoteCommunicationServerCommon::Handle_QThreadSuffixSupported( + StringExtractorGDBRemote &packet) { + m_thread_suffix_supported = true; + return SendOKResponse(); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_QListThreadsInStopReply (StringExtractorGDBRemote &packet) -{ - m_list_threads_in_stop_reply = true; - return SendOKResponse(); +GDBRemoteCommunicationServerCommon::Handle_QListThreadsInStopReply( + StringExtractorGDBRemote &packet) { + m_list_threads_in_stop_reply = true; + return SendOKResponse(); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_QSetDetachOnError (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen ("QSetDetachOnError:")); - if (packet.GetU32(0)) - m_process_launch_info.GetFlags().Set (eLaunchFlagDetachOnError); - else - m_process_launch_info.GetFlags().Clear (eLaunchFlagDetachOnError); - return SendOKResponse (); +GDBRemoteCommunicationServerCommon::Handle_QSetDetachOnError( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("QSetDetachOnError:")); + if (packet.GetU32(0)) + m_process_launch_info.GetFlags().Set(eLaunchFlagDetachOnError); + else + m_process_launch_info.GetFlags().Clear(eLaunchFlagDetachOnError); + return SendOKResponse(); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_QStartNoAckMode (StringExtractorGDBRemote &packet) -{ - // Send response first before changing m_send_acks to we ack this packet - PacketResult packet_result = SendOKResponse (); - m_send_acks = false; - return packet_result; +GDBRemoteCommunicationServerCommon::Handle_QStartNoAckMode( + StringExtractorGDBRemote &packet) { + // Send response first before changing m_send_acks to we ack this packet + PacketResult packet_result = SendOKResponse(); + m_send_acks = false; + return packet_result; } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_QSetSTDIN (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen ("QSetSTDIN:")); - FileAction file_action; - std::string path; - packet.GetHexByteString(path); - const bool read = false; - const bool write = true; - if (file_action.Open(STDIN_FILENO, FileSpec{path, false}, read, write)) - { - m_process_launch_info.AppendFileAction(file_action); - return SendOKResponse (); - } - return SendErrorResponse (15); +GDBRemoteCommunicationServerCommon::Handle_QSetSTDIN( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("QSetSTDIN:")); + FileAction file_action; + std::string path; + packet.GetHexByteString(path); + const bool read = true; + const bool write = false; + if (file_action.Open(STDIN_FILENO, FileSpec{path, false}, read, write)) { + m_process_launch_info.AppendFileAction(file_action); + return SendOKResponse(); + } + return SendErrorResponse(15); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_QSetSTDOUT (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen ("QSetSTDOUT:")); - FileAction file_action; - std::string path; - packet.GetHexByteString(path); - const bool read = true; - const bool write = false; - if (file_action.Open(STDOUT_FILENO, FileSpec{path, false}, read, write)) - { - m_process_launch_info.AppendFileAction(file_action); - return SendOKResponse (); - } - return SendErrorResponse (16); +GDBRemoteCommunicationServerCommon::Handle_QSetSTDOUT( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("QSetSTDOUT:")); + FileAction file_action; + std::string path; + packet.GetHexByteString(path); + const bool read = false; + const bool write = true; + if (file_action.Open(STDOUT_FILENO, FileSpec{path, false}, read, write)) { + m_process_launch_info.AppendFileAction(file_action); + return SendOKResponse(); + } + return SendErrorResponse(16); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_QSetSTDERR (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen ("QSetSTDERR:")); - FileAction file_action; - std::string path; - packet.GetHexByteString(path); - const bool read = true; - const bool write = false; - if (file_action.Open(STDERR_FILENO, FileSpec{path, false}, read, write)) - { - m_process_launch_info.AppendFileAction(file_action); - return SendOKResponse (); - } - return SendErrorResponse (17); +GDBRemoteCommunicationServerCommon::Handle_QSetSTDERR( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("QSetSTDERR:")); + FileAction file_action; + std::string path; + packet.GetHexByteString(path); + const bool read = false; + const bool write = true; + if (file_action.Open(STDERR_FILENO, FileSpec{path, false}, read, write)) { + m_process_launch_info.AppendFileAction(file_action); + return SendOKResponse(); + } + return SendErrorResponse(17); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_qLaunchSuccess (StringExtractorGDBRemote &packet) -{ - if (m_process_launch_error.Success()) - return SendOKResponse(); - StreamString response; - response.PutChar('E'); - response.PutCString(m_process_launch_error.AsCString("<unknown error>")); - return SendPacketNoLock (response.GetData(), response.GetSize()); +GDBRemoteCommunicationServerCommon::Handle_qLaunchSuccess( + StringExtractorGDBRemote &packet) { + if (m_process_launch_error.Success()) + return SendOKResponse(); + StreamString response; + response.PutChar('E'); + response.PutCString(m_process_launch_error.AsCString("<unknown error>")); + return SendPacketNoLock(response.GetString()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_QEnvironment (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen ("QEnvironment:")); - const uint32_t bytes_left = packet.GetBytesLeft(); - if (bytes_left > 0) - { - m_process_launch_info.GetEnvironmentEntries ().AppendArgument (packet.Peek()); - return SendOKResponse (); - } - return SendErrorResponse (12); +GDBRemoteCommunicationServerCommon::Handle_QEnvironment( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("QEnvironment:")); + const uint32_t bytes_left = packet.GetBytesLeft(); + if (bytes_left > 0) { + m_process_launch_info.GetEnvironmentEntries().AppendArgument( + llvm::StringRef::withNullAsEmpty(packet.Peek())); + return SendOKResponse(); + } + return SendErrorResponse(12); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_QEnvironmentHexEncoded (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen("QEnvironmentHexEncoded:")); - const uint32_t bytes_left = packet.GetBytesLeft(); - if (bytes_left > 0) - { - std::string str; - packet.GetHexByteString(str); - m_process_launch_info.GetEnvironmentEntries().AppendArgument(str.c_str()); - return SendOKResponse(); - } - return SendErrorResponse(12); +GDBRemoteCommunicationServerCommon::Handle_QEnvironmentHexEncoded( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("QEnvironmentHexEncoded:")); + const uint32_t bytes_left = packet.GetBytesLeft(); + if (bytes_left > 0) { + std::string str; + packet.GetHexByteString(str); + m_process_launch_info.GetEnvironmentEntries().AppendArgument(str); + return SendOKResponse(); + } + return SendErrorResponse(12); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_QLaunchArch (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen ("QLaunchArch:")); - const uint32_t bytes_left = packet.GetBytesLeft(); - if (bytes_left > 0) - { - const char* arch_triple = packet.Peek(); - ArchSpec arch_spec(arch_triple,NULL); - m_process_launch_info.SetArchitecture(arch_spec); - return SendOKResponse(); - } - return SendErrorResponse(13); +GDBRemoteCommunicationServerCommon::Handle_QLaunchArch( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("QLaunchArch:")); + const uint32_t bytes_left = packet.GetBytesLeft(); + if (bytes_left > 0) { + const char *arch_triple = packet.Peek(); + ArchSpec arch_spec(arch_triple, NULL); + m_process_launch_info.SetArchitecture(arch_spec); + return SendOKResponse(); + } + return SendErrorResponse(13); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_A (StringExtractorGDBRemote &packet) -{ - // The 'A' packet is the most over designed packet ever here with - // redundant argument indexes, redundant argument lengths and needed hex - // encoded argument string values. Really all that is needed is a comma - // separated hex encoded argument value list, but we will stay true to the - // documented version of the 'A' packet here... - - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - int actual_arg_index = 0; - - packet.SetFilePos(1); // Skip the 'A' - bool success = true; - while (success && packet.GetBytesLeft() > 0) - { - // Decode the decimal argument string length. This length is the - // number of hex nibbles in the argument string value. - const uint32_t arg_len = packet.GetU32(UINT32_MAX); - if (arg_len == UINT32_MAX) +GDBRemoteCommunicationServerCommon::Handle_A(StringExtractorGDBRemote &packet) { + // The 'A' packet is the most over designed packet ever here with + // redundant argument indexes, redundant argument lengths and needed hex + // encoded argument string values. Really all that is needed is a comma + // separated hex encoded argument value list, but we will stay true to the + // documented version of the 'A' packet here... + + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + int actual_arg_index = 0; + + packet.SetFilePos(1); // Skip the 'A' + bool success = true; + while (success && packet.GetBytesLeft() > 0) { + // Decode the decimal argument string length. This length is the + // number of hex nibbles in the argument string value. + const uint32_t arg_len = packet.GetU32(UINT32_MAX); + if (arg_len == UINT32_MAX) + success = false; + else { + // Make sure the argument hex string length is followed by a comma + if (packet.GetChar() != ',') + success = false; + else { + // Decode the argument index. We ignore this really because + // who would really send down the arguments in a random order??? + const uint32_t arg_idx = packet.GetU32(UINT32_MAX); + if (arg_idx == UINT32_MAX) + success = false; + else { + // Make sure the argument index is followed by a comma + if (packet.GetChar() != ',') success = false; - else - { - // Make sure the argument hex string length is followed by a comma - if (packet.GetChar() != ',') - success = false; - else - { - // Decode the argument index. We ignore this really because - // who would really send down the arguments in a random order??? - const uint32_t arg_idx = packet.GetU32(UINT32_MAX); - if (arg_idx == UINT32_MAX) - success = false; - else - { - // Make sure the argument index is followed by a comma - if (packet.GetChar() != ',') - success = false; - else - { - // Decode the argument string value from hex bytes - // back into a UTF8 string and make sure the length - // matches the one supplied in the packet - std::string arg; - if (packet.GetHexByteStringFixedLength(arg, arg_len) != (arg_len / 2)) - success = false; - else - { - // If there are any bytes left - if (packet.GetBytesLeft()) - { - if (packet.GetChar() != ',') - success = false; - } - - if (success) - { - if (arg_idx == 0) - m_process_launch_info.GetExecutableFile().SetFile(arg.c_str(), false); - m_process_launch_info.GetArguments().AppendArgument(arg.c_str()); - if (log) - log->Printf ("LLGSPacketHandler::%s added arg %d: \"%s\"", __FUNCTION__, actual_arg_index, arg.c_str ()); - ++actual_arg_index; - } - } - } - } + else { + // Decode the argument string value from hex bytes + // back into a UTF8 string and make sure the length + // matches the one supplied in the packet + std::string arg; + if (packet.GetHexByteStringFixedLength(arg, arg_len) != + (arg_len / 2)) + success = false; + else { + // If there are any bytes left + if (packet.GetBytesLeft()) { + if (packet.GetChar() != ',') + success = false; + } + + if (success) { + if (arg_idx == 0) + m_process_launch_info.GetExecutableFile().SetFile(arg, false); + m_process_launch_info.GetArguments().AppendArgument(arg); + if (log) + log->Printf("LLGSPacketHandler::%s added arg %d: \"%s\"", + __FUNCTION__, actual_arg_index, arg.c_str()); + ++actual_arg_index; + } } + } } + } } - - if (success) - { - m_process_launch_error = LaunchProcess (); - if (m_process_launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) - { - return SendOKResponse (); - } - else - { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf("LLGSPacketHandler::%s failed to launch exe: %s", - __FUNCTION__, - m_process_launch_error.AsCString()); - - } + } + + if (success) { + m_process_launch_error = LaunchProcess(); + if (m_process_launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) { + return SendOKResponse(); + } else { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf("LLGSPacketHandler::%s failed to launch exe: %s", + __FUNCTION__, m_process_launch_error.AsCString()); } - return SendErrorResponse (8); + } + return SendErrorResponse(8); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_qEcho (StringExtractorGDBRemote &packet) -{ - // Just echo back the exact same packet for qEcho... - return SendPacketNoLock(packet.GetStringRef().c_str(), packet.GetStringRef().size()); +GDBRemoteCommunicationServerCommon::Handle_qEcho( + StringExtractorGDBRemote &packet) { + // Just echo back the exact same packet for qEcho... + return SendPacketNoLock(packet.GetStringRef()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_qModuleInfo (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen ("qModuleInfo:")); - - std::string module_path; - packet.GetHexByteStringTerminatedBy(module_path, ';'); - if (module_path.empty()) - return SendErrorResponse (1); - - if (packet.GetChar() != ';') - return SendErrorResponse (2); - - std::string triple; - packet.GetHexByteString(triple); - ArchSpec arch(triple.c_str()); - - const FileSpec req_module_path_spec(module_path.c_str(), true); - const FileSpec module_path_spec = FindModuleFile(req_module_path_spec.GetPath(), arch); - const ModuleSpec module_spec(module_path_spec, arch); - - ModuleSpecList module_specs; - if (!ObjectFile::GetModuleSpecifications(module_path_spec, 0, 0, module_specs)) - return SendErrorResponse (3); +GDBRemoteCommunicationServerCommon::Handle_qModuleInfo( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("qModuleInfo:")); + + std::string module_path; + packet.GetHexByteStringTerminatedBy(module_path, ';'); + if (module_path.empty()) + return SendErrorResponse(1); + + if (packet.GetChar() != ';') + return SendErrorResponse(2); + + std::string triple; + packet.GetHexByteString(triple); + + ModuleSpec matched_module_spec = GetModuleInfo(module_path, triple); + if (!matched_module_spec.GetFileSpec()) + return SendErrorResponse(3); + + const auto file_offset = matched_module_spec.GetObjectOffset(); + const auto file_size = matched_module_spec.GetObjectSize(); + const auto uuid_str = matched_module_spec.GetUUID().GetAsString(""); + + StreamGDBRemote response; + + if (uuid_str.empty()) { + std::string md5_hash; + if (!FileSystem::CalculateMD5AsString(matched_module_spec.GetFileSpec(), + file_offset, file_size, md5_hash)) + return SendErrorResponse(5); + response.PutCString("md5:"); + response.PutCStringAsRawHex8(md5_hash.c_str()); + } else { + response.PutCString("uuid:"); + response.PutCStringAsRawHex8(uuid_str.c_str()); + } + response.PutChar(';'); + + const auto &module_arch = matched_module_spec.GetArchitecture(); + response.PutCString("triple:"); + response.PutCStringAsRawHex8(module_arch.GetTriple().getTriple().c_str()); + response.PutChar(';'); + + response.PutCString("file_path:"); + response.PutCStringAsRawHex8(matched_module_spec.GetFileSpec().GetCString()); + response.PutChar(';'); + response.PutCString("file_offset:"); + response.PutHex64(file_offset); + response.PutChar(';'); + response.PutCString("file_size:"); + response.PutHex64(file_size); + response.PutChar(';'); + + return SendPacketNoLock(response.GetString()); +} - ModuleSpec matched_module_spec; - if (!module_specs.FindMatchingModuleSpec(module_spec, matched_module_spec)) - return SendErrorResponse (4); +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerCommon::Handle_jModulesInfo( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("jModulesInfo:")); + + StructuredData::ObjectSP object_sp = StructuredData::ParseJSON(packet.Peek()); + if (!object_sp) + return SendErrorResponse(1); + + StructuredData::Array *packet_array = object_sp->GetAsArray(); + if (!packet_array) + return SendErrorResponse(2); + + JSONArray::SP response_array_sp = std::make_shared<JSONArray>(); + for (size_t i = 0; i < packet_array->GetSize(); ++i) { + StructuredData::Dictionary *query = + packet_array->GetItemAtIndex(i)->GetAsDictionary(); + if (!query) + continue; + std::string file, triple; + if (!query->GetValueForKeyAsString("file", file) || + !query->GetValueForKeyAsString("triple", triple)) + continue; + + ModuleSpec matched_module_spec = GetModuleInfo(file, triple); + if (!matched_module_spec.GetFileSpec()) + continue; const auto file_offset = matched_module_spec.GetObjectOffset(); const auto file_size = matched_module_spec.GetObjectSize(); const auto uuid_str = matched_module_spec.GetUUID().GetAsString(""); - StreamGDBRemote response; - if (uuid_str.empty()) - { - std::string md5_hash; - if (!FileSystem::CalculateMD5AsString(matched_module_spec.GetFileSpec(), file_offset, file_size, md5_hash)) - return SendErrorResponse (5); - response.PutCString ("md5:"); - response.PutCStringAsRawHex8(md5_hash.c_str()); - } - else{ - response.PutCString ("uuid:"); - response.PutCStringAsRawHex8(uuid_str.c_str()); - } - response.PutChar(';'); + continue; + + JSONObject::SP response = std::make_shared<JSONObject>(); + response_array_sp->AppendObject(response); + response->SetObject("uuid", std::make_shared<JSONString>(uuid_str)); + response->SetObject( + "triple", + std::make_shared<JSONString>( + matched_module_spec.GetArchitecture().GetTriple().getTriple())); + response->SetObject("file_path", + std::make_shared<JSONString>( + matched_module_spec.GetFileSpec().GetPath())); + response->SetObject("file_offset", + std::make_shared<JSONNumber>(file_offset)); + response->SetObject("file_size", std::make_shared<JSONNumber>(file_size)); + } + + StreamString response; + response_array_sp->Write(response); + StreamGDBRemote escaped_response; + escaped_response.PutEscapedBytes(response.GetString().data(), + response.GetSize()); + return SendPacketNoLock(escaped_response.GetString()); +} - const auto &module_arch = matched_module_spec.GetArchitecture(); +void GDBRemoteCommunicationServerCommon::CreateProcessInfoResponse( + const ProcessInstanceInfo &proc_info, StreamString &response) { + response.Printf( + "pid:%" PRIu64 ";ppid:%" PRIu64 ";uid:%i;gid:%i;euid:%i;egid:%i;", + proc_info.GetProcessID(), proc_info.GetParentProcessID(), + proc_info.GetUserID(), proc_info.GetGroupID(), + proc_info.GetEffectiveUserID(), proc_info.GetEffectiveGroupID()); + response.PutCString("name:"); + response.PutCStringAsRawHex8(proc_info.GetExecutableFile().GetCString()); + response.PutChar(';'); + const ArchSpec &proc_arch = proc_info.GetArchitecture(); + if (proc_arch.IsValid()) { + const llvm::Triple &proc_triple = proc_arch.GetTriple(); response.PutCString("triple:"); - response.PutCStringAsRawHex8( module_arch.GetTriple().getTriple().c_str()); - response.PutChar(';'); - - response.PutCString("file_path:"); - response.PutCStringAsRawHex8(module_path_spec.GetCString()); - response.PutChar(';'); - response.PutCString("file_offset:"); - response.PutHex64(file_offset); + response.PutCStringAsRawHex8(proc_triple.getTriple().c_str()); response.PutChar(';'); - response.PutCString("file_size:"); - response.PutHex64(file_size); - response.PutChar(';'); - - return SendPacketNoLock(response.GetData(), response.GetSize()); + } } -void -GDBRemoteCommunicationServerCommon::CreateProcessInfoResponse (const ProcessInstanceInfo &proc_info, - StreamString &response) -{ - response.Printf ("pid:%" PRIu64 ";ppid:%" PRIu64 ";uid:%i;gid:%i;euid:%i;egid:%i;", - proc_info.GetProcessID(), - proc_info.GetParentProcessID(), - proc_info.GetUserID(), - proc_info.GetGroupID(), - proc_info.GetEffectiveUserID(), - proc_info.GetEffectiveGroupID()); - response.PutCString ("name:"); - response.PutCStringAsRawHex8(proc_info.GetExecutableFile().GetCString()); +void GDBRemoteCommunicationServerCommon:: + CreateProcessInfoResponse_DebugServerStyle( + const ProcessInstanceInfo &proc_info, StreamString &response) { + response.Printf("pid:%" PRIx64 ";parent-pid:%" PRIx64 + ";real-uid:%x;real-gid:%x;effective-uid:%x;effective-gid:%x;", + proc_info.GetProcessID(), proc_info.GetParentProcessID(), + proc_info.GetUserID(), proc_info.GetGroupID(), + proc_info.GetEffectiveUserID(), + proc_info.GetEffectiveGroupID()); + + const ArchSpec &proc_arch = proc_info.GetArchitecture(); + if (proc_arch.IsValid()) { + const llvm::Triple &proc_triple = proc_arch.GetTriple(); +#if defined(__APPLE__) + // We'll send cputype/cpusubtype. + const uint32_t cpu_type = proc_arch.GetMachOCPUType(); + if (cpu_type != 0) + response.Printf("cputype:%" PRIx32 ";", cpu_type); + + const uint32_t cpu_subtype = proc_arch.GetMachOCPUSubType(); + if (cpu_subtype != 0) + response.Printf("cpusubtype:%" PRIx32 ";", cpu_subtype); + + const std::string vendor = proc_triple.getVendorName(); + if (!vendor.empty()) + response.Printf("vendor:%s;", vendor.c_str()); +#else + // We'll send the triple. + response.PutCString("triple:"); + response.PutCStringAsRawHex8(proc_triple.getTriple().c_str()); response.PutChar(';'); - const ArchSpec &proc_arch = proc_info.GetArchitecture(); - if (proc_arch.IsValid()) - { - const llvm::Triple &proc_triple = proc_arch.GetTriple(); - response.PutCString("triple:"); - response.PutCStringAsRawHex8(proc_triple.getTriple().c_str()); - response.PutChar(';'); +#endif + std::string ostype = proc_triple.getOSName(); + // Adjust so ostype reports ios for Apple/ARM and Apple/ARM64. + if (proc_triple.getVendor() == llvm::Triple::Apple) { + switch (proc_triple.getArch()) { + case llvm::Triple::arm: + case llvm::Triple::thumb: + case llvm::Triple::aarch64: + ostype = "ios"; + break; + default: + // No change. + break; + } + } + response.Printf("ostype:%s;", ostype.c_str()); + + switch (proc_arch.GetByteOrder()) { + case lldb::eByteOrderLittle: + response.PutCString("endian:little;"); + break; + case lldb::eByteOrderBig: + response.PutCString("endian:big;"); + break; + case lldb::eByteOrderPDP: + response.PutCString("endian:pdp;"); + break; + default: + // Nothing. + break; } + // In case of MIPS64, pointer size is depend on ELF ABI + // For N32 the pointer size is 4 and for N64 it is 8 + std::string abi = proc_arch.GetTargetABI(); + if (!abi.empty()) + response.Printf("elf_abi:%s;", abi.c_str()); + response.Printf("ptrsize:%d;", proc_arch.GetAddressByteSize()); + } } -void -GDBRemoteCommunicationServerCommon::CreateProcessInfoResponse_DebugServerStyle ( - const ProcessInstanceInfo &proc_info, StreamString &response) -{ - response.Printf ("pid:%" PRIx64 ";parent-pid:%" PRIx64 ";real-uid:%x;real-gid:%x;effective-uid:%x;effective-gid:%x;", - proc_info.GetProcessID(), - proc_info.GetParentProcessID(), - proc_info.GetUserID(), - proc_info.GetGroupID(), - proc_info.GetEffectiveUserID(), - proc_info.GetEffectiveGroupID()); - - const ArchSpec &proc_arch = proc_info.GetArchitecture(); - if (proc_arch.IsValid()) - { - const llvm::Triple &proc_triple = proc_arch.GetTriple(); -#if defined(__APPLE__) - // We'll send cputype/cpusubtype. - const uint32_t cpu_type = proc_arch.GetMachOCPUType(); - if (cpu_type != 0) - response.Printf ("cputype:%" PRIx32 ";", cpu_type); - - const uint32_t cpu_subtype = proc_arch.GetMachOCPUSubType(); - if (cpu_subtype != 0) - response.Printf ("cpusubtype:%" PRIx32 ";", cpu_subtype); - - const std::string vendor = proc_triple.getVendorName (); - if (!vendor.empty ()) - response.Printf ("vendor:%s;", vendor.c_str ()); +FileSpec GDBRemoteCommunicationServerCommon::FindModuleFile( + const std::string &module_path, const ArchSpec &arch) { +#ifdef __ANDROID__ + return HostInfoAndroid::ResolveLibraryPath(module_path, arch); #else - // We'll send the triple. - response.PutCString("triple:"); - response.PutCStringAsRawHex8(proc_triple.getTriple().c_str()); - response.PutChar(';'); + return FileSpec(module_path, true); #endif - std::string ostype = proc_triple.getOSName (); - // Adjust so ostype reports ios for Apple/ARM and Apple/ARM64. - if (proc_triple.getVendor () == llvm::Triple::Apple) - { - switch (proc_triple.getArch ()) - { - case llvm::Triple::arm: - case llvm::Triple::thumb: - case llvm::Triple::aarch64: - ostype = "ios"; - break; - default: - // No change. - break; - } - } - response.Printf ("ostype:%s;", ostype.c_str ()); +} +ModuleSpec GDBRemoteCommunicationServerCommon::GetModuleInfo( + const std::string &module_path, const std::string &triple) { + ArchSpec arch(triple.c_str()); - switch (proc_arch.GetByteOrder ()) - { - case lldb::eByteOrderLittle: response.PutCString ("endian:little;"); break; - case lldb::eByteOrderBig: response.PutCString ("endian:big;"); break; - case lldb::eByteOrderPDP: response.PutCString ("endian:pdp;"); break; - default: - // Nothing. - break; - } + const FileSpec req_module_path_spec(module_path, true); + const FileSpec module_path_spec = + FindModuleFile(req_module_path_spec.GetPath(), arch); + const ModuleSpec module_spec(module_path_spec, arch); - // In case of MIPS64, pointer size is depend on ELF ABI - // For N32 the pointer size is 4 and for N64 it is 8 - std::string abi = proc_arch.GetTargetABI(); - if (!abi.empty()) - response.Printf("elf_abi:%s;", abi.c_str()); - response.Printf("ptrsize:%d;", proc_arch.GetAddressByteSize()); - } -} + ModuleSpecList module_specs; + if (!ObjectFile::GetModuleSpecifications(module_path_spec, 0, 0, + module_specs)) + return ModuleSpec(); -FileSpec -GDBRemoteCommunicationServerCommon::FindModuleFile(const std::string& module_path, - const ArchSpec& arch) -{ -#ifdef __ANDROID__ - return HostInfoAndroid::ResolveLibraryPath(module_path, arch); -#else - return FileSpec(module_path.c_str(), true); -#endif + ModuleSpec matched_module_spec; + if (!module_specs.FindMatchingModuleSpec(module_spec, matched_module_spec)) + return ModuleSpec(); + + return matched_module_spec; } diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h index d2fd700..321a922 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h @@ -16,8 +16,8 @@ // Other libraries and framework includes // Project includes -#include "lldb/lldb-private-forward.h" #include "lldb/Target/Process.h" +#include "lldb/lldb-private-forward.h" #include "GDBRemoteCommunicationServer.h" #include "GDBRemoteCommunicationServerCommon.h" @@ -29,175 +29,132 @@ namespace process_gdb_remote { class ProcessGDBRemote; -class GDBRemoteCommunicationServerCommon : - public GDBRemoteCommunicationServer -{ +class GDBRemoteCommunicationServerCommon : public GDBRemoteCommunicationServer { public: - GDBRemoteCommunicationServerCommon(const char *comm_name, const char *listener_name); + GDBRemoteCommunicationServerCommon(const char *comm_name, + const char *listener_name); - ~GDBRemoteCommunicationServerCommon() override; + ~GDBRemoteCommunicationServerCommon() override; protected: - ProcessLaunchInfo m_process_launch_info; - Error m_process_launch_error; - ProcessInstanceInfoList m_proc_infos; - uint32_t m_proc_infos_index; - bool m_thread_suffix_supported; - bool m_list_threads_in_stop_reply; + ProcessLaunchInfo m_process_launch_info; + Error m_process_launch_error; + ProcessInstanceInfoList m_proc_infos; + uint32_t m_proc_infos_index; + bool m_thread_suffix_supported; + bool m_list_threads_in_stop_reply; + + PacketResult Handle_A(StringExtractorGDBRemote &packet); - PacketResult - Handle_A (StringExtractorGDBRemote &packet); + PacketResult Handle_qHostInfo(StringExtractorGDBRemote &packet); - PacketResult - Handle_qHostInfo (StringExtractorGDBRemote &packet); + PacketResult Handle_qProcessInfoPID(StringExtractorGDBRemote &packet); - PacketResult - Handle_qProcessInfoPID (StringExtractorGDBRemote &packet); + PacketResult Handle_qfProcessInfo(StringExtractorGDBRemote &packet); - PacketResult - Handle_qfProcessInfo (StringExtractorGDBRemote &packet); + PacketResult Handle_qsProcessInfo(StringExtractorGDBRemote &packet); - PacketResult - Handle_qsProcessInfo (StringExtractorGDBRemote &packet); + PacketResult Handle_qUserName(StringExtractorGDBRemote &packet); - PacketResult - Handle_qUserName (StringExtractorGDBRemote &packet); + PacketResult Handle_qGroupName(StringExtractorGDBRemote &packet); - PacketResult - Handle_qGroupName (StringExtractorGDBRemote &packet); + PacketResult Handle_qSpeedTest(StringExtractorGDBRemote &packet); - PacketResult - Handle_qSpeedTest (StringExtractorGDBRemote &packet); + PacketResult Handle_vFile_Open(StringExtractorGDBRemote &packet); - PacketResult - Handle_vFile_Open (StringExtractorGDBRemote &packet); + PacketResult Handle_vFile_Close(StringExtractorGDBRemote &packet); - PacketResult - Handle_vFile_Close (StringExtractorGDBRemote &packet); + PacketResult Handle_vFile_pRead(StringExtractorGDBRemote &packet); - PacketResult - Handle_vFile_pRead (StringExtractorGDBRemote &packet); + PacketResult Handle_vFile_pWrite(StringExtractorGDBRemote &packet); - PacketResult - Handle_vFile_pWrite (StringExtractorGDBRemote &packet); + PacketResult Handle_vFile_Size(StringExtractorGDBRemote &packet); - PacketResult - Handle_vFile_Size (StringExtractorGDBRemote &packet); + PacketResult Handle_vFile_Mode(StringExtractorGDBRemote &packet); - PacketResult - Handle_vFile_Mode (StringExtractorGDBRemote &packet); + PacketResult Handle_vFile_Exists(StringExtractorGDBRemote &packet); - PacketResult - Handle_vFile_Exists (StringExtractorGDBRemote &packet); + PacketResult Handle_vFile_symlink(StringExtractorGDBRemote &packet); - PacketResult - Handle_vFile_symlink (StringExtractorGDBRemote &packet); + PacketResult Handle_vFile_unlink(StringExtractorGDBRemote &packet); - PacketResult - Handle_vFile_unlink (StringExtractorGDBRemote &packet); + PacketResult Handle_vFile_Stat(StringExtractorGDBRemote &packet); - PacketResult - Handle_vFile_Stat (StringExtractorGDBRemote &packet); + PacketResult Handle_vFile_MD5(StringExtractorGDBRemote &packet); - PacketResult - Handle_vFile_MD5 (StringExtractorGDBRemote &packet); + PacketResult Handle_qEcho(StringExtractorGDBRemote &packet); - PacketResult - Handle_qEcho (StringExtractorGDBRemote &packet); + PacketResult Handle_qModuleInfo(StringExtractorGDBRemote &packet); - PacketResult - Handle_qModuleInfo (StringExtractorGDBRemote &packet); + PacketResult Handle_jModulesInfo(StringExtractorGDBRemote &packet); - PacketResult - Handle_qPlatform_shell (StringExtractorGDBRemote &packet); + PacketResult Handle_qPlatform_shell(StringExtractorGDBRemote &packet); - PacketResult - Handle_qPlatform_mkdir (StringExtractorGDBRemote &packet); + PacketResult Handle_qPlatform_mkdir(StringExtractorGDBRemote &packet); - PacketResult - Handle_qPlatform_chmod (StringExtractorGDBRemote &packet); + PacketResult Handle_qPlatform_chmod(StringExtractorGDBRemote &packet); - PacketResult - Handle_qSupported (StringExtractorGDBRemote &packet); + PacketResult Handle_qSupported(StringExtractorGDBRemote &packet); - PacketResult - Handle_QThreadSuffixSupported (StringExtractorGDBRemote &packet); + PacketResult Handle_QThreadSuffixSupported(StringExtractorGDBRemote &packet); - PacketResult - Handle_QListThreadsInStopReply (StringExtractorGDBRemote &packet); + PacketResult Handle_QListThreadsInStopReply(StringExtractorGDBRemote &packet); - PacketResult - Handle_QSetDetachOnError (StringExtractorGDBRemote &packet); + PacketResult Handle_QSetDetachOnError(StringExtractorGDBRemote &packet); - PacketResult - Handle_QStartNoAckMode (StringExtractorGDBRemote &packet); + PacketResult Handle_QStartNoAckMode(StringExtractorGDBRemote &packet); - PacketResult - Handle_QSetSTDIN (StringExtractorGDBRemote &packet); + PacketResult Handle_QSetSTDIN(StringExtractorGDBRemote &packet); - PacketResult - Handle_QSetSTDOUT (StringExtractorGDBRemote &packet); + PacketResult Handle_QSetSTDOUT(StringExtractorGDBRemote &packet); - PacketResult - Handle_QSetSTDERR (StringExtractorGDBRemote &packet); + PacketResult Handle_QSetSTDERR(StringExtractorGDBRemote &packet); - PacketResult - Handle_qLaunchSuccess (StringExtractorGDBRemote &packet); + PacketResult Handle_qLaunchSuccess(StringExtractorGDBRemote &packet); - PacketResult - Handle_QEnvironment (StringExtractorGDBRemote &packet); + PacketResult Handle_QEnvironment(StringExtractorGDBRemote &packet); - PacketResult - Handle_QEnvironmentHexEncoded (StringExtractorGDBRemote &packet); + PacketResult Handle_QEnvironmentHexEncoded(StringExtractorGDBRemote &packet); - PacketResult - Handle_QLaunchArch (StringExtractorGDBRemote &packet); + PacketResult Handle_QLaunchArch(StringExtractorGDBRemote &packet); - static void - CreateProcessInfoResponse (const ProcessInstanceInfo &proc_info, - StreamString &response); + static void CreateProcessInfoResponse(const ProcessInstanceInfo &proc_info, + StreamString &response); - static void - CreateProcessInfoResponse_DebugServerStyle (const ProcessInstanceInfo &proc_info, - StreamString &response); + static void CreateProcessInfoResponse_DebugServerStyle( + const ProcessInstanceInfo &proc_info, StreamString &response); - template <typename T> - void - RegisterMemberFunctionHandler (StringExtractorGDBRemote::ServerPacketType packet_type, - PacketResult (T::*handler) (StringExtractorGDBRemote& packet)) - { - RegisterPacketHandler(packet_type, - [this, handler] (StringExtractorGDBRemote packet, - Error &error, - bool &interrupt, - bool &quit) - { - return (static_cast<T*>(this)->*handler) (packet); - }); - } + template <typename T> + void RegisterMemberFunctionHandler( + StringExtractorGDBRemote::ServerPacketType packet_type, + PacketResult (T::*handler)(StringExtractorGDBRemote &packet)) { + RegisterPacketHandler(packet_type, + [this, handler](StringExtractorGDBRemote packet, + Error &error, bool &interrupt, + bool &quit) { + return (static_cast<T *>(this)->*handler)(packet); + }); + } - bool - GetThreadSuffixSupported () override - { - return true; - } + //------------------------------------------------------------------ + /// Launch a process with the current launch settings. + /// + /// This method supports running an lldb-gdbserver or similar + /// server in a situation where the startup code has been provided + /// with all the information for a child process to be launched. + /// + /// @return + /// An Error object indicating the success or failure of the + /// launch. + //------------------------------------------------------------------ + virtual Error LaunchProcess() = 0; - //------------------------------------------------------------------ - /// Launch a process with the current launch settings. - /// - /// This method supports running an lldb-gdbserver or similar - /// server in a situation where the startup code has been provided - /// with all the information for a child process to be launched. - /// - /// @return - /// An Error object indicating the success or failure of the - /// launch. - //------------------------------------------------------------------ - virtual Error - LaunchProcess () = 0; + virtual FileSpec FindModuleFile(const std::string &module_path, + const ArchSpec &arch); - virtual FileSpec - FindModuleFile (const std::string& module_path, const ArchSpec& arch); +private: + ModuleSpec GetModuleInfo(const std::string &module_path, + const std::string &triple); }; } // namespace process_gdb_remote diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index c468ba3..bf72673 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -16,13 +16,11 @@ // C Includes // C++ Includes -#include <cstring> #include <chrono> +#include <cstring> #include <thread> // Other libraries and framework includes -#include "llvm/ADT/Triple.h" -#include "lldb/Interpreter/Args.h" #include "lldb/Core/DataBuffer.h" #include "lldb/Core/Log.h" #include "lldb/Core/RegisterValue.h" @@ -36,20 +34,22 @@ #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" #include "lldb/Host/StringConvert.h" -#include "lldb/Host/TimeValue.h" -#include "lldb/Target/FileAction.h" -#include "lldb/Target/MemoryRegionInfo.h" -#include "lldb/Host/common/NativeRegisterContext.h" #include "lldb/Host/common/NativeProcessProtocol.h" +#include "lldb/Host/common/NativeRegisterContext.h" #include "lldb/Host/common/NativeThreadProtocol.h" +#include "lldb/Interpreter/Args.h" +#include "lldb/Target/FileAction.h" +#include "lldb/Target/MemoryRegionInfo.h" #include "lldb/Utility/JSON.h" #include "lldb/Utility/LLDBAssert.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/ScopedPrinter.h" // Project includes -#include "Utility/StringExtractorGDBRemote.h" -#include "Utility/UriParser.h" #include "ProcessGDBRemote.h" #include "ProcessGDBRemoteLog.h" +#include "Utility/StringExtractorGDBRemote.h" +#include "Utility/UriParser.h" using namespace lldb; using namespace lldb_private; @@ -60,2934 +60,3110 @@ using namespace llvm; // GDBRemote Errors //---------------------------------------------------------------------- -namespace -{ - enum GDBRemoteServerError - { - // Set to the first unused error number in literal form below - eErrorFirst = 29, - eErrorNoProcess = eErrorFirst, - eErrorResume, - eErrorExitStatus - }; +namespace { +enum GDBRemoteServerError { + // Set to the first unused error number in literal form below + eErrorFirst = 29, + eErrorNoProcess = eErrorFirst, + eErrorResume, + eErrorExitStatus +}; } //---------------------------------------------------------------------- // GDBRemoteCommunicationServerLLGS constructor //---------------------------------------------------------------------- -GDBRemoteCommunicationServerLLGS::GDBRemoteCommunicationServerLLGS(MainLoop &mainloop) - : GDBRemoteCommunicationServerCommon("gdb-remote.server", "gdb-remote.server.rx_packet"), - m_mainloop(mainloop), - m_current_tid(LLDB_INVALID_THREAD_ID), - m_continue_tid(LLDB_INVALID_THREAD_ID), - m_debugged_process_mutex(), - m_debugged_process_sp(), - m_stdio_communication("process.stdio"), +GDBRemoteCommunicationServerLLGS::GDBRemoteCommunicationServerLLGS( + MainLoop &mainloop) + : GDBRemoteCommunicationServerCommon("gdb-remote.server", + "gdb-remote.server.rx_packet"), + m_mainloop(mainloop), m_current_tid(LLDB_INVALID_THREAD_ID), + m_continue_tid(LLDB_INVALID_THREAD_ID), m_debugged_process_mutex(), + m_debugged_process_sp(), m_stdio_communication("process.stdio"), m_inferior_prev_state(StateType::eStateInvalid), - m_active_auxv_buffer_sp(), - m_saved_registers_mutex(), - m_saved_registers_map(), - m_next_saved_registers_id(1), - m_handshake_completed(false) -{ - RegisterPacketHandlers(); -} - -void -GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() -{ - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_C, - &GDBRemoteCommunicationServerLLGS::Handle_C); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_c, - &GDBRemoteCommunicationServerLLGS::Handle_c); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_D, - &GDBRemoteCommunicationServerLLGS::Handle_D); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_H, - &GDBRemoteCommunicationServerLLGS::Handle_H); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_I, - &GDBRemoteCommunicationServerLLGS::Handle_I); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_interrupt, - &GDBRemoteCommunicationServerLLGS::Handle_interrupt); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_m, - &GDBRemoteCommunicationServerLLGS::Handle_memory_read); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_M, - &GDBRemoteCommunicationServerLLGS::Handle_M); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_p, - &GDBRemoteCommunicationServerLLGS::Handle_p); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_P, - &GDBRemoteCommunicationServerLLGS::Handle_P); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qC, - &GDBRemoteCommunicationServerLLGS::Handle_qC); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qfThreadInfo, - &GDBRemoteCommunicationServerLLGS::Handle_qfThreadInfo); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qFileLoadAddress, - &GDBRemoteCommunicationServerLLGS::Handle_qFileLoadAddress); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir, - &GDBRemoteCommunicationServerLLGS::Handle_qGetWorkingDir); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qMemoryRegionInfo, - &GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qMemoryRegionInfoSupported, - &GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfoSupported); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qProcessInfo, - &GDBRemoteCommunicationServerLLGS::Handle_qProcessInfo); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qRegisterInfo, - &GDBRemoteCommunicationServerLLGS::Handle_qRegisterInfo); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QRestoreRegisterState, - &GDBRemoteCommunicationServerLLGS::Handle_QRestoreRegisterState); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSaveRegisterState, - &GDBRemoteCommunicationServerLLGS::Handle_QSaveRegisterState); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetDisableASLR, - &GDBRemoteCommunicationServerLLGS::Handle_QSetDisableASLR); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir, - &GDBRemoteCommunicationServerLLGS::Handle_QSetWorkingDir); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qsThreadInfo, - &GDBRemoteCommunicationServerLLGS::Handle_qsThreadInfo); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qThreadStopInfo, - &GDBRemoteCommunicationServerLLGS::Handle_qThreadStopInfo); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_jThreadsInfo, - &GDBRemoteCommunicationServerLLGS::Handle_jThreadsInfo); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qWatchpointSupportInfo, - &GDBRemoteCommunicationServerLLGS::Handle_qWatchpointSupportInfo); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qXfer_auxv_read, - &GDBRemoteCommunicationServerLLGS::Handle_qXfer_auxv_read); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_s, - &GDBRemoteCommunicationServerLLGS::Handle_s); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_stop_reason, - &GDBRemoteCommunicationServerLLGS::Handle_stop_reason); // ? - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vAttach, - &GDBRemoteCommunicationServerLLGS::Handle_vAttach); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vCont, - &GDBRemoteCommunicationServerLLGS::Handle_vCont); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vCont_actions, - &GDBRemoteCommunicationServerLLGS::Handle_vCont_actions); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_x, - &GDBRemoteCommunicationServerLLGS::Handle_memory_read); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_Z, - &GDBRemoteCommunicationServerLLGS::Handle_Z); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_z, - &GDBRemoteCommunicationServerLLGS::Handle_z); - - RegisterPacketHandler(StringExtractorGDBRemote::eServerPacketType_k, - [this](StringExtractorGDBRemote packet, - Error &error, - bool &interrupt, - bool &quit) - { - quit = true; - return this->Handle_k (packet); - }); -} - -Error -GDBRemoteCommunicationServerLLGS::SetLaunchArguments (const char *const args[], int argc) -{ - if ((argc < 1) || !args || !args[0] || !args[0][0]) - return Error ("%s: no process command line specified to launch", __FUNCTION__); - - m_process_launch_info.SetArguments (const_cast<const char**> (args), true); - return Error (); -} - -Error -GDBRemoteCommunicationServerLLGS::SetLaunchFlags (unsigned int launch_flags) -{ - m_process_launch_info.GetFlags ().Set (launch_flags); - return Error (); -} - -Error -GDBRemoteCommunicationServerLLGS::LaunchProcess () -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - - if (!m_process_launch_info.GetArguments ().GetArgumentCount ()) - return Error ("%s: no process command line specified to launch", __FUNCTION__); - - Error error; - { - std::lock_guard<std::recursive_mutex> guard(m_debugged_process_mutex); - assert (!m_debugged_process_sp && "lldb-gdbserver creating debugged process but one already exists"); - error = NativeProcessProtocol::Launch( - m_process_launch_info, - *this, - m_mainloop, - m_debugged_process_sp); - } - - if (!error.Success ()) - { - fprintf (stderr, "%s: failed to launch executable %s", __FUNCTION__, m_process_launch_info.GetArguments ().GetArgumentAtIndex (0)); - return error; - } - - // Handle mirroring of inferior stdout/stderr over the gdb-remote protocol - // as needed. - // llgs local-process debugging may specify PTY paths, which will make these - // file actions non-null - // process launch -i/e/o will also make these file actions non-null - // nullptr means that the traffic is expected to flow over gdb-remote protocol - if ( - m_process_launch_info.GetFileActionForFD(STDIN_FILENO) == nullptr || - m_process_launch_info.GetFileActionForFD(STDOUT_FILENO) == nullptr || - m_process_launch_info.GetFileActionForFD(STDERR_FILENO) == nullptr - ) - { - // nullptr means it's not redirected to file or pty (in case of LLGS local) - // at least one of stdio will be transferred pty<->gdb-remote - // we need to give the pty master handle to this object to read and/or write - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " setting up stdout/stderr redirection via $O gdb-remote commands", __FUNCTION__, m_debugged_process_sp->GetID ()); - - // Setup stdout/stderr mapping from inferior to $O - auto terminal_fd = m_debugged_process_sp->GetTerminalFileDescriptor (); - if (terminal_fd >= 0) - { - if (log) - log->Printf ("ProcessGDBRemoteCommunicationServerLLGS::%s setting inferior STDIO fd to %d", __FUNCTION__, terminal_fd); - error = SetSTDIOFileDescriptor (terminal_fd); - if (error.Fail ()) - return error; - } - else - { - if (log) - log->Printf ("ProcessGDBRemoteCommunicationServerLLGS::%s ignoring inferior STDIO since terminal fd reported as %d", __FUNCTION__, terminal_fd); - } - } - else - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " skipping stdout/stderr redirection via $O: inferior will communicate over client-provided file descriptors", __FUNCTION__, m_debugged_process_sp->GetID ()); - } - - printf ("Launched '%s' as process %" PRIu64 "...\n", m_process_launch_info.GetArguments ().GetArgumentAtIndex (0), m_process_launch_info.GetProcessID ()); - + m_active_auxv_buffer_sp(), m_saved_registers_mutex(), + m_saved_registers_map(), m_next_saved_registers_id(1), + m_handshake_completed(false) { + RegisterPacketHandlers(); +} + +void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() { + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_C, + &GDBRemoteCommunicationServerLLGS::Handle_C); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_c, + &GDBRemoteCommunicationServerLLGS::Handle_c); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_D, + &GDBRemoteCommunicationServerLLGS::Handle_D); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_H, + &GDBRemoteCommunicationServerLLGS::Handle_H); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_I, + &GDBRemoteCommunicationServerLLGS::Handle_I); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_interrupt, + &GDBRemoteCommunicationServerLLGS::Handle_interrupt); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_m, + &GDBRemoteCommunicationServerLLGS::Handle_memory_read); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_M, + &GDBRemoteCommunicationServerLLGS::Handle_M); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_p, + &GDBRemoteCommunicationServerLLGS::Handle_p); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_P, + &GDBRemoteCommunicationServerLLGS::Handle_P); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qC, + &GDBRemoteCommunicationServerLLGS::Handle_qC); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qfThreadInfo, + &GDBRemoteCommunicationServerLLGS::Handle_qfThreadInfo); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qFileLoadAddress, + &GDBRemoteCommunicationServerLLGS::Handle_qFileLoadAddress); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir, + &GDBRemoteCommunicationServerLLGS::Handle_qGetWorkingDir); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qMemoryRegionInfo, + &GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qMemoryRegionInfoSupported, + &GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfoSupported); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qProcessInfo, + &GDBRemoteCommunicationServerLLGS::Handle_qProcessInfo); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qRegisterInfo, + &GDBRemoteCommunicationServerLLGS::Handle_qRegisterInfo); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_QRestoreRegisterState, + &GDBRemoteCommunicationServerLLGS::Handle_QRestoreRegisterState); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_QSaveRegisterState, + &GDBRemoteCommunicationServerLLGS::Handle_QSaveRegisterState); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_QSetDisableASLR, + &GDBRemoteCommunicationServerLLGS::Handle_QSetDisableASLR); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir, + &GDBRemoteCommunicationServerLLGS::Handle_QSetWorkingDir); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qsThreadInfo, + &GDBRemoteCommunicationServerLLGS::Handle_qsThreadInfo); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qThreadStopInfo, + &GDBRemoteCommunicationServerLLGS::Handle_qThreadStopInfo); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_jThreadsInfo, + &GDBRemoteCommunicationServerLLGS::Handle_jThreadsInfo); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qWatchpointSupportInfo, + &GDBRemoteCommunicationServerLLGS::Handle_qWatchpointSupportInfo); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qXfer_auxv_read, + &GDBRemoteCommunicationServerLLGS::Handle_qXfer_auxv_read); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_s, + &GDBRemoteCommunicationServerLLGS::Handle_s); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_stop_reason, + &GDBRemoteCommunicationServerLLGS::Handle_stop_reason); // ? + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_vAttach, + &GDBRemoteCommunicationServerLLGS::Handle_vAttach); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_vCont, + &GDBRemoteCommunicationServerLLGS::Handle_vCont); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_vCont_actions, + &GDBRemoteCommunicationServerLLGS::Handle_vCont_actions); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_x, + &GDBRemoteCommunicationServerLLGS::Handle_memory_read); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_Z, + &GDBRemoteCommunicationServerLLGS::Handle_Z); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_z, + &GDBRemoteCommunicationServerLLGS::Handle_z); + + RegisterPacketHandler(StringExtractorGDBRemote::eServerPacketType_k, + [this](StringExtractorGDBRemote packet, Error &error, + bool &interrupt, bool &quit) { + quit = true; + return this->Handle_k(packet); + }); +} + +Error GDBRemoteCommunicationServerLLGS::SetLaunchArguments( + const char *const args[], int argc) { + if ((argc < 1) || !args || !args[0] || !args[0][0]) + return Error("%s: no process command line specified to launch", + __FUNCTION__); + + m_process_launch_info.SetArguments(const_cast<const char **>(args), true); + return Error(); +} + +Error GDBRemoteCommunicationServerLLGS::SetLaunchFlags( + unsigned int launch_flags) { + m_process_launch_info.GetFlags().Set(launch_flags); + return Error(); +} + +Error GDBRemoteCommunicationServerLLGS::LaunchProcess() { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + if (!m_process_launch_info.GetArguments().GetArgumentCount()) + return Error("%s: no process command line specified to launch", + __FUNCTION__); + + const bool should_forward_stdio = + m_process_launch_info.GetFileActionForFD(STDIN_FILENO) == nullptr || + m_process_launch_info.GetFileActionForFD(STDOUT_FILENO) == nullptr || + m_process_launch_info.GetFileActionForFD(STDERR_FILENO) == nullptr; + 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); + + Error error; + { + std::lock_guard<std::recursive_mutex> guard(m_debugged_process_mutex); + assert(!m_debugged_process_sp && "lldb-server creating debugged " + "process but one already exists"); + error = NativeProcessProtocol::Launch(m_process_launch_info, *this, + m_mainloop, m_debugged_process_sp); + } + + if (!error.Success()) { + fprintf(stderr, "%s: failed to launch executable %s", __FUNCTION__, + m_process_launch_info.GetArguments().GetArgumentAtIndex(0)); return error; -} - -Error -GDBRemoteCommunicationServerLLGS::AttachToProcess (lldb::pid_t pid) -{ - Error error; - - Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS)); + } + + // Handle mirroring of inferior stdout/stderr over the gdb-remote protocol + // as needed. + // llgs local-process debugging may specify PTY paths, which will make these + // file actions non-null + // process launch -i/e/o will also make these file actions non-null + // nullptr means that the traffic is expected to flow over gdb-remote protocol + if (should_forward_stdio) { + // nullptr means it's not redirected to file or pty (in case of LLGS local) + // at least one of stdio will be transferred pty<->gdb-remote + // we need to give the pty master handle to this object to read and/or write if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64, __FUNCTION__, pid); - - // Before we try to attach, make sure we aren't already monitoring something else. - if (m_debugged_process_sp && m_debugged_process_sp->GetID() != LLDB_INVALID_PROCESS_ID) - return Error("cannot attach to a process %" PRIu64 " when another process with pid %" PRIu64 " is being debugged.", pid, m_debugged_process_sp->GetID()); - - // Try to attach. - error = NativeProcessProtocol::Attach(pid, *this, m_mainloop, m_debugged_process_sp); - if (!error.Success ()) - { - fprintf (stderr, "%s: failed to attach to process %" PRIu64 ": %s", __FUNCTION__, pid, error.AsCString ()); + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 + " setting up stdout/stderr redirection via $O gdb-remote commands", + __FUNCTION__, m_debugged_process_sp->GetID()); + + // Setup stdout/stderr mapping from inferior to $O + auto terminal_fd = m_debugged_process_sp->GetTerminalFileDescriptor(); + if (terminal_fd >= 0) { + if (log) + log->Printf("ProcessGDBRemoteCommunicationServerLLGS::%s setting " + "inferior STDIO fd to %d", + __FUNCTION__, terminal_fd); + error = SetSTDIOFileDescriptor(terminal_fd); + if (error.Fail()) return error; + } else { + if (log) + log->Printf("ProcessGDBRemoteCommunicationServerLLGS::%s ignoring " + "inferior STDIO since terminal fd reported as %d", + __FUNCTION__, terminal_fd); } - - // Setup stdout/stderr mapping from inferior. - auto terminal_fd = m_debugged_process_sp->GetTerminalFileDescriptor (); - if (terminal_fd >= 0) - { - if (log) - log->Printf ("ProcessGDBRemoteCommunicationServerLLGS::%s setting inferior STDIO fd to %d", __FUNCTION__, terminal_fd); - error = SetSTDIOFileDescriptor (terminal_fd); - if (error.Fail ()) - return error; - } - else - { - if (log) - log->Printf ("ProcessGDBRemoteCommunicationServerLLGS::%s ignoring inferior STDIO since terminal fd reported as %d", __FUNCTION__, terminal_fd); - } - - printf ("Attached to process %" PRIu64 "...\n", pid); - + } else { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 + " skipping stdout/stderr redirection via $O: inferior will " + "communicate over client-provided file descriptors", + __FUNCTION__, m_debugged_process_sp->GetID()); + } + + printf("Launched '%s' as process %" PRIu64 "...\n", + m_process_launch_info.GetArguments().GetArgumentAtIndex(0), + m_process_launch_info.GetProcessID()); + + return error; +} + +Error GDBRemoteCommunicationServerLLGS::AttachToProcess(lldb::pid_t pid) { + Error error; + + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64, + __FUNCTION__, pid); + + // Before we try to attach, make sure we aren't already monitoring something + // else. + if (m_debugged_process_sp && + m_debugged_process_sp->GetID() != LLDB_INVALID_PROCESS_ID) + return Error("cannot attach to a process %" PRIu64 + " when another process with pid %" PRIu64 + " is being debugged.", + pid, m_debugged_process_sp->GetID()); + + // Try to attach. + error = NativeProcessProtocol::Attach(pid, *this, m_mainloop, + m_debugged_process_sp); + if (!error.Success()) { + fprintf(stderr, "%s: failed to attach to process %" PRIu64 ": %s", + __FUNCTION__, pid, error.AsCString()); return error; -} + } -void -GDBRemoteCommunicationServerLLGS::InitializeDelegate (NativeProcessProtocol *process) -{ - assert (process && "process cannot be NULL"); - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + // Setup stdout/stderr mapping from inferior. + auto terminal_fd = m_debugged_process_sp->GetTerminalFileDescriptor(); + if (terminal_fd >= 0) { if (log) - { - log->Printf ("GDBRemoteCommunicationServerLLGS::%s called with NativeProcessProtocol pid %" PRIu64 ", current state: %s", - __FUNCTION__, - process->GetID (), - StateAsCString (process->GetState ())); - } -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::SendWResponse (NativeProcessProtocol *process) -{ - assert (process && "process cannot be NULL"); - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - - // send W notification - ExitType exit_type = ExitType::eExitTypeInvalid; - int return_code = 0; - std::string exit_description; - - const bool got_exit_info = process->GetExitStatus (&exit_type, &return_code, exit_description); - if (!got_exit_info) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 ", failed to retrieve process exit status", __FUNCTION__, process->GetID ()); - - StreamGDBRemote response; - response.PutChar ('E'); - response.PutHex8 (GDBRemoteServerError::eErrorExitStatus); - return SendPacketNoLock(response.GetData(), response.GetSize()); - } - else - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 ", returning exit type %d, return code %d [%s]", __FUNCTION__, process->GetID (), exit_type, return_code, exit_description.c_str ()); - - StreamGDBRemote response; - - char return_type_code; - switch (exit_type) - { - case ExitType::eExitTypeExit: - return_type_code = 'W'; - break; - case ExitType::eExitTypeSignal: - return_type_code = 'X'; - break; - case ExitType::eExitTypeStop: - return_type_code = 'S'; - break; - case ExitType::eExitTypeInvalid: - return_type_code = 'E'; - break; - } - response.PutChar (return_type_code); + log->Printf("ProcessGDBRemoteCommunicationServerLLGS::%s setting " + "inferior STDIO fd to %d", + __FUNCTION__, terminal_fd); + error = SetSTDIOFileDescriptor(terminal_fd); + if (error.Fail()) + return error; + } else { + if (log) + log->Printf("ProcessGDBRemoteCommunicationServerLLGS::%s ignoring " + "inferior STDIO since terminal fd reported as %d", + __FUNCTION__, terminal_fd); + } - // POSIX exit status limited to unsigned 8 bits. - response.PutHex8 (return_code); + printf("Attached to process %" PRIu64 "...\n", pid); - return SendPacketNoLock(response.GetData(), response.GetSize()); - } + return error; } -static void -AppendHexValue (StreamString &response, const uint8_t* buf, uint32_t buf_size, bool swap) -{ - int64_t i; - if (swap) - { - for (i = buf_size-1; i >= 0; i--) - response.PutHex8 (buf[i]); - } - else - { - for (i = 0; i < buf_size; i++) - response.PutHex8 (buf[i]); - } +void GDBRemoteCommunicationServerLLGS::InitializeDelegate( + NativeProcessProtocol *process) { + assert(process && "process cannot be NULL"); + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) { + log->Printf("GDBRemoteCommunicationServerLLGS::%s called with " + "NativeProcessProtocol pid %" PRIu64 ", current state: %s", + __FUNCTION__, process->GetID(), + StateAsCString(process->GetState())); + } } -static void -WriteRegisterValueInHexFixedWidth (StreamString &response, - NativeRegisterContextSP ®_ctx_sp, - const RegisterInfo ®_info, - const RegisterValue *reg_value_p) -{ - RegisterValue reg_value; - if (!reg_value_p) - { - Error error = reg_ctx_sp->ReadRegister (®_info, reg_value); - if (error.Success ()) - reg_value_p = ®_value; - // else log. - } +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::SendWResponse( + NativeProcessProtocol *process) { + assert(process && "process cannot be NULL"); + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + // send W notification + ExitType exit_type = ExitType::eExitTypeInvalid; + int return_code = 0; + std::string exit_description; + + const bool got_exit_info = + process->GetExitStatus(&exit_type, &return_code, exit_description); + if (!got_exit_info) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 + ", failed to retrieve process exit status", + __FUNCTION__, process->GetID()); - if (reg_value_p) - { - AppendHexValue (response, (const uint8_t*) reg_value_p->GetBytes (), reg_value_p->GetByteSize (), false); - } - else - { - // Zero-out any unreadable values. - if (reg_info.byte_size > 0) - { - std::basic_string<uint8_t> zeros(reg_info.byte_size, '\0'); - AppendHexValue (response, zeros.data(), zeros.size(), false); - } - } -} + StreamGDBRemote response; + response.PutChar('E'); + response.PutHex8(GDBRemoteServerError::eErrorExitStatus); + return SendPacketNoLock(response.GetString()); + } else { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 + ", returning exit type %d, return code %d [%s]", + __FUNCTION__, process->GetID(), exit_type, return_code, + exit_description.c_str()); -static JSONObject::SP -GetRegistersAsJSON(NativeThreadProtocol &thread, bool abridged) -{ - Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_THREAD)); + StreamGDBRemote response; - NativeRegisterContextSP reg_ctx_sp = thread.GetRegisterContext (); - if (! reg_ctx_sp) - return nullptr; + char return_type_code; + switch (exit_type) { + case ExitType::eExitTypeExit: + return_type_code = 'W'; + break; + case ExitType::eExitTypeSignal: + return_type_code = 'X'; + break; + case ExitType::eExitTypeStop: + return_type_code = 'S'; + break; + case ExitType::eExitTypeInvalid: + return_type_code = 'E'; + break; + } + response.PutChar(return_type_code); + + // POSIX exit status limited to unsigned 8 bits. + response.PutHex8(return_code); + + return SendPacketNoLock(response.GetString()); + } +} + +static void AppendHexValue(StreamString &response, const uint8_t *buf, + uint32_t buf_size, bool swap) { + int64_t i; + if (swap) { + for (i = buf_size - 1; i >= 0; i--) + response.PutHex8(buf[i]); + } else { + for (i = 0; i < buf_size; i++) + response.PutHex8(buf[i]); + } +} + +static void WriteRegisterValueInHexFixedWidth( + StreamString &response, NativeRegisterContextSP ®_ctx_sp, + const RegisterInfo ®_info, const RegisterValue *reg_value_p) { + RegisterValue reg_value; + if (!reg_value_p) { + Error error = reg_ctx_sp->ReadRegister(®_info, reg_value); + if (error.Success()) + reg_value_p = ®_value; + // else log. + } + + if (reg_value_p) { + AppendHexValue(response, (const uint8_t *)reg_value_p->GetBytes(), + reg_value_p->GetByteSize(), false); + } else { + // Zero-out any unreadable values. + if (reg_info.byte_size > 0) { + std::basic_string<uint8_t> zeros(reg_info.byte_size, '\0'); + AppendHexValue(response, zeros.data(), zeros.size(), false); + } + } +} + +static JSONObject::SP GetRegistersAsJSON(NativeThreadProtocol &thread, + bool abridged) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + + NativeRegisterContextSP reg_ctx_sp = thread.GetRegisterContext(); + if (!reg_ctx_sp) + return nullptr; - JSONObject::SP register_object_sp = std::make_shared<JSONObject>(); + JSONObject::SP register_object_sp = std::make_shared<JSONObject>(); #ifdef LLDB_JTHREADSINFO_FULL_REGISTER_SET - // Expedite all registers in the first register set (i.e. should be GPRs) that are not contained in other registers. - const RegisterSet *reg_set_p = reg_ctx_sp->GetRegisterSet(0); - if (! reg_set_p) - return nullptr; - for (const uint32_t *reg_num_p = reg_set_p->registers; *reg_num_p != LLDB_INVALID_REGNUM; ++reg_num_p) - { - uint32_t reg_num = *reg_num_p; + // Expedite all registers in the first register set (i.e. should be GPRs) that + // are not contained in other registers. + const RegisterSet *reg_set_p = reg_ctx_sp->GetRegisterSet(0); + if (!reg_set_p) + return nullptr; + for (const uint32_t *reg_num_p = reg_set_p->registers; + *reg_num_p != LLDB_INVALID_REGNUM; ++reg_num_p) { + uint32_t reg_num = *reg_num_p; #else - // Expedite only a couple of registers until we figure out why sending registers is - // expensive. - static const uint32_t k_expedited_registers[] = { - LLDB_REGNUM_GENERIC_PC, LLDB_REGNUM_GENERIC_SP, LLDB_REGNUM_GENERIC_FP, LLDB_REGNUM_GENERIC_RA, LLDB_INVALID_REGNUM - }; - static const uint32_t k_abridged_expedited_registers[] = { - LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM - }; - - for (const uint32_t *generic_reg_p = abridged ? k_abridged_expedited_registers : k_expedited_registers; - *generic_reg_p != LLDB_INVALID_REGNUM; - ++generic_reg_p) - { - uint32_t reg_num = reg_ctx_sp->ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, *generic_reg_p); - if (reg_num == LLDB_INVALID_REGNUM) - continue; // Target does not support the given register. + // Expedite only a couple of registers until we figure out why sending + // registers is + // expensive. + static const uint32_t k_expedited_registers[] = { + LLDB_REGNUM_GENERIC_PC, LLDB_REGNUM_GENERIC_SP, LLDB_REGNUM_GENERIC_FP, + LLDB_REGNUM_GENERIC_RA, LLDB_INVALID_REGNUM}; + static const uint32_t k_abridged_expedited_registers[] = { + LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM}; + + for (const uint32_t *generic_reg_p = abridged ? k_abridged_expedited_registers + : k_expedited_registers; + *generic_reg_p != LLDB_INVALID_REGNUM; ++generic_reg_p) { + uint32_t reg_num = reg_ctx_sp->ConvertRegisterKindToRegisterNumber( + eRegisterKindGeneric, *generic_reg_p); + if (reg_num == LLDB_INVALID_REGNUM) + continue; // Target does not support the given register. #endif - const RegisterInfo *const reg_info_p = reg_ctx_sp->GetRegisterInfoAtIndex(reg_num); - if (reg_info_p == nullptr) - { - if (log) - log->Printf("%s failed to get register info for register index %" PRIu32, - __FUNCTION__, reg_num); - continue; - } - - if (reg_info_p->value_regs != nullptr) - continue; // Only expedite registers that are not contained in other registers. - - RegisterValue reg_value; - Error error = reg_ctx_sp->ReadRegister(reg_info_p, reg_value); - if (error.Fail()) - { - if (log) - log->Printf("%s failed to read register '%s' index %" PRIu32 ": %s", __FUNCTION__, - reg_info_p->name ? reg_info_p->name : "<unnamed-register>", reg_num, - error.AsCString ()); - continue; - } - - StreamString stream; - WriteRegisterValueInHexFixedWidth(stream, reg_ctx_sp, *reg_info_p, ®_value); - - register_object_sp->SetObject(std::to_string(reg_num), - std::make_shared<JSONString>(stream.GetString())); - } - - return register_object_sp; -} - -static const char * -GetStopReasonString(StopReason stop_reason) -{ - switch (stop_reason) - { - case eStopReasonTrace: - return "trace"; - case eStopReasonBreakpoint: - return "breakpoint"; - case eStopReasonWatchpoint: - return "watchpoint"; - case eStopReasonSignal: - return "signal"; - case eStopReasonException: - return "exception"; - case eStopReasonExec: - return "exec"; - case eStopReasonInstrumentation: - case eStopReasonInvalid: - case eStopReasonPlanComplete: - case eStopReasonThreadExiting: - case eStopReasonNone: - break; // ignored + const RegisterInfo *const reg_info_p = + reg_ctx_sp->GetRegisterInfoAtIndex(reg_num); + if (reg_info_p == nullptr) { + if (log) + log->Printf( + "%s failed to get register info for register index %" PRIu32, + __FUNCTION__, reg_num); + continue; } - return nullptr; -} -static JSONArray::SP -GetJSONThreadsInfo(NativeProcessProtocol &process, bool abridged) -{ - Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); + if (reg_info_p->value_regs != nullptr) + continue; // Only expedite registers that are not contained in other + // registers. - JSONArray::SP threads_array_sp = std::make_shared<JSONArray>(); - - // Ensure we can get info on the given thread. - uint32_t thread_idx = 0; - for ( NativeThreadProtocolSP thread_sp; - (thread_sp = process.GetThreadAtIndex(thread_idx)) != nullptr; - ++thread_idx) - { - - lldb::tid_t tid = thread_sp->GetID(); - - // Grab the reason this thread stopped. - struct ThreadStopInfo tid_stop_info; - std::string description; - if (!thread_sp->GetStopReason (tid_stop_info, description)) - return nullptr; - - const int signum = tid_stop_info.details.signal.signo; - if (log) - { - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 " got signal signo = %d, reason = %d, exc_type = %" PRIu64, + RegisterValue reg_value; + Error error = reg_ctx_sp->ReadRegister(reg_info_p, reg_value); + if (error.Fail()) { + if (log) + log->Printf("%s failed to read register '%s' index %" PRIu32 ": %s", __FUNCTION__, - process.GetID (), - tid, - signum, - tid_stop_info.reason, - tid_stop_info.details.exception.type); - } - - JSONObject::SP thread_obj_sp = std::make_shared<JSONObject>(); - threads_array_sp->AppendObject(thread_obj_sp); - - if (JSONObject::SP registers_sp = GetRegistersAsJSON(*thread_sp, abridged)) - thread_obj_sp->SetObject("registers", registers_sp); - - thread_obj_sp->SetObject("tid", std::make_shared<JSONNumber>(tid)); - if (signum != 0) - thread_obj_sp->SetObject("signal", std::make_shared<JSONNumber>(signum)); + reg_info_p->name ? reg_info_p->name : "<unnamed-register>", + reg_num, error.AsCString()); + continue; + } + + StreamString stream; + WriteRegisterValueInHexFixedWidth(stream, reg_ctx_sp, *reg_info_p, + ®_value); + + register_object_sp->SetObject( + llvm::to_string(reg_num), + std::make_shared<JSONString>(stream.GetString())); + } + + return register_object_sp; +} + +static const char *GetStopReasonString(StopReason stop_reason) { + switch (stop_reason) { + case eStopReasonTrace: + return "trace"; + case eStopReasonBreakpoint: + return "breakpoint"; + case eStopReasonWatchpoint: + return "watchpoint"; + case eStopReasonSignal: + return "signal"; + case eStopReasonException: + return "exception"; + case eStopReasonExec: + return "exec"; + case eStopReasonInstrumentation: + case eStopReasonInvalid: + case eStopReasonPlanComplete: + case eStopReasonThreadExiting: + case eStopReasonNone: + break; // ignored + } + return nullptr; +} + +static JSONArray::SP GetJSONThreadsInfo(NativeProcessProtocol &process, + bool abridged) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); + + JSONArray::SP threads_array_sp = std::make_shared<JSONArray>(); + + // Ensure we can get info on the given thread. + uint32_t thread_idx = 0; + for (NativeThreadProtocolSP thread_sp; + (thread_sp = process.GetThreadAtIndex(thread_idx)) != nullptr; + ++thread_idx) { + + lldb::tid_t tid = thread_sp->GetID(); - const std::string thread_name = thread_sp->GetName (); - if (! thread_name.empty()) - thread_obj_sp->SetObject("name", std::make_shared<JSONString>(thread_name)); - - if (const char *stop_reason_str = GetStopReasonString(tid_stop_info.reason)) - thread_obj_sp->SetObject("reason", std::make_shared<JSONString>(stop_reason_str)); - - if (! description.empty()) - thread_obj_sp->SetObject("description", std::make_shared<JSONString>(description)); - - if ((tid_stop_info.reason == eStopReasonException) && tid_stop_info.details.exception.type) - { - thread_obj_sp->SetObject("metype", - std::make_shared<JSONNumber>(tid_stop_info.details.exception.type)); - - JSONArray::SP medata_array_sp = std::make_shared<JSONArray>(); - for (uint32_t i = 0; i < tid_stop_info.details.exception.data_count; ++i) - { - medata_array_sp->AppendObject(std::make_shared<JSONNumber>( - tid_stop_info.details.exception.data[i])); - } - thread_obj_sp->SetObject("medata", medata_array_sp); - } + // Grab the reason this thread stopped. + struct ThreadStopInfo tid_stop_info; + std::string description; + if (!thread_sp->GetStopReason(tid_stop_info, description)) + return nullptr; - // TODO: Expedite interesting regions of inferior memory + const int signum = tid_stop_info.details.signal.signo; + if (log) { + log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 + " tid %" PRIu64 + " got signal signo = %d, reason = %d, exc_type = %" PRIu64, + __FUNCTION__, process.GetID(), tid, signum, + tid_stop_info.reason, tid_stop_info.details.exception.type); } - return threads_array_sp; -} + JSONObject::SP thread_obj_sp = std::make_shared<JSONObject>(); + threads_array_sp->AppendObject(thread_obj_sp); -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread (lldb::tid_t tid) -{ - Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); + if (JSONObject::SP registers_sp = GetRegistersAsJSON(*thread_sp, abridged)) + thread_obj_sp->SetObject("registers", registers_sp); - // Ensure we have a debugged process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - return SendErrorResponse (50); + thread_obj_sp->SetObject("tid", std::make_shared<JSONNumber>(tid)); + if (signum != 0) + thread_obj_sp->SetObject("signal", std::make_shared<JSONNumber>(signum)); - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s preparing packet for pid %" PRIu64 " tid %" PRIu64, - __FUNCTION__, m_debugged_process_sp->GetID (), tid); + const std::string thread_name = thread_sp->GetName(); + if (!thread_name.empty()) + thread_obj_sp->SetObject("name", + std::make_shared<JSONString>(thread_name)); - // Ensure we can get info on the given thread. - NativeThreadProtocolSP thread_sp (m_debugged_process_sp->GetThreadByID (tid)); - if (!thread_sp) - return SendErrorResponse (51); + if (const char *stop_reason_str = GetStopReasonString(tid_stop_info.reason)) + thread_obj_sp->SetObject("reason", + std::make_shared<JSONString>(stop_reason_str)); - // Grab the reason this thread stopped. - struct ThreadStopInfo tid_stop_info; - std::string description; - if (!thread_sp->GetStopReason (tid_stop_info, description)) - return SendErrorResponse (52); + if (!description.empty()) + thread_obj_sp->SetObject("description", + std::make_shared<JSONString>(description)); - // FIXME implement register handling for exec'd inferiors. - // if (tid_stop_info.reason == eStopReasonExec) - // { - // const bool force = true; - // InitializeRegisters(force); - // } + if ((tid_stop_info.reason == eStopReasonException) && + tid_stop_info.details.exception.type) { + thread_obj_sp->SetObject( + "metype", + std::make_shared<JSONNumber>(tid_stop_info.details.exception.type)); - StreamString response; - // Output the T packet with the thread - response.PutChar ('T'); - int signum = tid_stop_info.details.signal.signo; - if (log) - { - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 " got signal signo = %d, reason = %d, exc_type = %" PRIu64, - __FUNCTION__, - m_debugged_process_sp->GetID (), - tid, - signum, - tid_stop_info.reason, - tid_stop_info.details.exception.type); + JSONArray::SP medata_array_sp = std::make_shared<JSONArray>(); + for (uint32_t i = 0; i < tid_stop_info.details.exception.data_count; + ++i) { + medata_array_sp->AppendObject(std::make_shared<JSONNumber>( + tid_stop_info.details.exception.data[i])); + } + thread_obj_sp->SetObject("medata", medata_array_sp); } - // Print the signal number. - response.PutHex8 (signum & 0xff); - - // Include the tid. - response.Printf ("thread:%" PRIx64 ";", tid); - - // Include the thread name if there is one. - const std::string thread_name = thread_sp->GetName (); - if (!thread_name.empty ()) - { - size_t thread_name_len = thread_name.length (); + // TODO: Expedite interesting regions of inferior memory + } - if (::strcspn (thread_name.c_str (), "$#+-;:") == thread_name_len) - { - response.PutCString ("name:"); - response.PutCString (thread_name.c_str ()); - } - else - { - // The thread name contains special chars, send as hex bytes. - response.PutCString ("hexname:"); - response.PutCStringAsRawHex8 (thread_name.c_str ()); - } - response.PutChar (';'); - } - - // If a 'QListThreadsInStopReply' was sent to enable this feature, we - // will send all thread IDs back in the "threads" key whose value is - // a list of hex thread IDs separated by commas: - // "threads:10a,10b,10c;" - // This will save the debugger from having to send a pair of qfThreadInfo - // and qsThreadInfo packets, but it also might take a lot of room in the - // stop reply packet, so it must be enabled only on systems where there - // are no limits on packet lengths. - if (m_list_threads_in_stop_reply) - { - response.PutCString ("threads:"); - - uint32_t thread_index = 0; - NativeThreadProtocolSP listed_thread_sp; - for (listed_thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index); listed_thread_sp; ++thread_index, listed_thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index)) - { - if (thread_index > 0) - response.PutChar (','); - response.Printf ("%" PRIx64, listed_thread_sp->GetID ()); - } - response.PutChar (';'); - - // Include JSON info that describes the stop reason for any threads - // that actually have stop reasons. We use the new "jstopinfo" key - // whose values is hex ascii JSON that contains the thread IDs - // thread stop info only for threads that have stop reasons. Only send - // this if we have more than one thread otherwise this packet has all - // the info it needs. - if (thread_index > 0) - { - const bool threads_with_valid_stop_info_only = true; - JSONArray::SP threads_info_sp = GetJSONThreadsInfo(*m_debugged_process_sp, - threads_with_valid_stop_info_only); - if (threads_info_sp) - { - response.PutCString("jstopinfo:"); - StreamString unescaped_response; - threads_info_sp->Write(unescaped_response); - response.PutCStringAsRawHex8(unescaped_response.GetData()); - response.PutChar(';'); - } - else if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to prepare a jstopinfo field for pid %" PRIu64, - __FUNCTION__, m_debugged_process_sp->GetID()); + return threads_array_sp; +} - } +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread( + lldb::tid_t tid) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); + + // Ensure we have a debugged process. + if (!m_debugged_process_sp || + (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) + return SendErrorResponse(50); + + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s preparing packet for pid %" PRIu64 + " tid %" PRIu64, + __FUNCTION__, m_debugged_process_sp->GetID(), tid); + + // Ensure we can get info on the given thread. + NativeThreadProtocolSP thread_sp(m_debugged_process_sp->GetThreadByID(tid)); + if (!thread_sp) + return SendErrorResponse(51); + + // Grab the reason this thread stopped. + struct ThreadStopInfo tid_stop_info; + std::string description; + if (!thread_sp->GetStopReason(tid_stop_info, description)) + return SendErrorResponse(52); + + // FIXME implement register handling for exec'd inferiors. + // if (tid_stop_info.reason == eStopReasonExec) + // { + // const bool force = true; + // InitializeRegisters(force); + // } + + StreamString response; + // Output the T packet with the thread + response.PutChar('T'); + int signum = tid_stop_info.details.signal.signo; + if (log) { + log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 + " tid %" PRIu64 + " got signal signo = %d, reason = %d, exc_type = %" PRIu64, + __FUNCTION__, m_debugged_process_sp->GetID(), tid, signum, + tid_stop_info.reason, tid_stop_info.details.exception.type); + } + + // Print the signal number. + response.PutHex8(signum & 0xff); + + // Include the tid. + response.Printf("thread:%" PRIx64 ";", tid); + + // Include the thread name if there is one. + const std::string thread_name = thread_sp->GetName(); + if (!thread_name.empty()) { + size_t thread_name_len = thread_name.length(); + + if (::strcspn(thread_name.c_str(), "$#+-;:") == thread_name_len) { + response.PutCString("name:"); + response.PutCString(thread_name); + } else { + // The thread name contains special chars, send as hex bytes. + response.PutCString("hexname:"); + response.PutCStringAsRawHex8(thread_name.c_str()); + } + response.PutChar(';'); + } + + // If a 'QListThreadsInStopReply' was sent to enable this feature, we + // will send all thread IDs back in the "threads" key whose value is + // a list of hex thread IDs separated by commas: + // "threads:10a,10b,10c;" + // This will save the debugger from having to send a pair of qfThreadInfo + // and qsThreadInfo packets, but it also might take a lot of room in the + // stop reply packet, so it must be enabled only on systems where there + // are no limits on packet lengths. + if (m_list_threads_in_stop_reply) { + response.PutCString("threads:"); + + uint32_t thread_index = 0; + NativeThreadProtocolSP listed_thread_sp; + for (listed_thread_sp = + m_debugged_process_sp->GetThreadAtIndex(thread_index); + listed_thread_sp; ++thread_index, + listed_thread_sp = m_debugged_process_sp->GetThreadAtIndex( + thread_index)) { + if (thread_index > 0) + response.PutChar(','); + response.Printf("%" PRIx64, listed_thread_sp->GetID()); + } + response.PutChar(';'); + + // Include JSON info that describes the stop reason for any threads + // that actually have stop reasons. We use the new "jstopinfo" key + // whose values is hex ascii JSON that contains the thread IDs + // thread stop info only for threads that have stop reasons. Only send + // this if we have more than one thread otherwise this packet has all + // the info it needs. + if (thread_index > 0) { + const bool threads_with_valid_stop_info_only = true; + JSONArray::SP threads_info_sp = GetJSONThreadsInfo( + *m_debugged_process_sp, threads_with_valid_stop_info_only); + if (threads_info_sp) { + response.PutCString("jstopinfo:"); + StreamString unescaped_response; + threads_info_sp->Write(unescaped_response); + response.PutCStringAsRawHex8(unescaped_response.GetData()); + response.PutChar(';'); + } else if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed to prepare a " + "jstopinfo field for pid %" PRIu64, + __FUNCTION__, m_debugged_process_sp->GetID()); } - - // - // Expedite registers. - // - - // Grab the register context. - NativeRegisterContextSP reg_ctx_sp = thread_sp->GetRegisterContext (); - if (reg_ctx_sp) - { - // Expedite all registers in the first register set (i.e. should be GPRs) that are not contained in other registers. - const RegisterSet *reg_set_p; - if (reg_ctx_sp->GetRegisterSetCount () > 0 && ((reg_set_p = reg_ctx_sp->GetRegisterSet (0)) != nullptr)) - { + } + + // + // Expedite registers. + // + + // Grab the register context. + NativeRegisterContextSP reg_ctx_sp = thread_sp->GetRegisterContext(); + if (reg_ctx_sp) { + // Expedite all registers in the first register set (i.e. should be GPRs) + // that are not contained in other registers. + const RegisterSet *reg_set_p; + if (reg_ctx_sp->GetRegisterSetCount() > 0 && + ((reg_set_p = reg_ctx_sp->GetRegisterSet(0)) != nullptr)) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s expediting registers " + "from set '%s' (registers set count: %zu)", + __FUNCTION__, + reg_set_p->name ? reg_set_p->name : "<unnamed-set>", + reg_set_p->num_registers); + + for (const uint32_t *reg_num_p = reg_set_p->registers; + *reg_num_p != LLDB_INVALID_REGNUM; ++reg_num_p) { + const RegisterInfo *const reg_info_p = + reg_ctx_sp->GetRegisterInfoAtIndex(*reg_num_p); + if (reg_info_p == nullptr) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed to get " + "register info for register set '%s', register index " + "%" PRIu32, + __FUNCTION__, + reg_set_p->name ? reg_set_p->name : "<unnamed-set>", + *reg_num_p); + } else if (reg_info_p->value_regs == nullptr) { + // Only expediate registers that are not contained in other registers. + RegisterValue reg_value; + Error error = reg_ctx_sp->ReadRegister(reg_info_p, reg_value); + if (error.Success()) { + response.Printf("%.02x:", *reg_num_p); + WriteRegisterValueInHexFixedWidth(response, reg_ctx_sp, *reg_info_p, + ®_value); + response.PutChar(';'); + } else { if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s expediting registers from set '%s' (registers set count: %zu)", __FUNCTION__, reg_set_p->name ? reg_set_p->name : "<unnamed-set>", reg_set_p->num_registers); - - for (const uint32_t *reg_num_p = reg_set_p->registers; *reg_num_p != LLDB_INVALID_REGNUM; ++reg_num_p) - { - const RegisterInfo *const reg_info_p = reg_ctx_sp->GetRegisterInfoAtIndex (*reg_num_p); - if (reg_info_p == nullptr) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to get register info for register set '%s', register index %" PRIu32, __FUNCTION__, reg_set_p->name ? reg_set_p->name : "<unnamed-set>", *reg_num_p); - } - else if (reg_info_p->value_regs == nullptr) - { - // Only expediate registers that are not contained in other registers. - RegisterValue reg_value; - Error error = reg_ctx_sp->ReadRegister (reg_info_p, reg_value); - if (error.Success ()) - { - response.Printf ("%.02x:", *reg_num_p); - WriteRegisterValueInHexFixedWidth(response, reg_ctx_sp, *reg_info_p, ®_value); - response.PutChar (';'); - } - else - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to read register '%s' index %" PRIu32 ": %s", __FUNCTION__, reg_info_p->name ? reg_info_p->name : "<unnamed-register>", *reg_num_p, error.AsCString ()); - - } - } - } + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed to read " + "register '%s' index %" PRIu32 ": %s", + __FUNCTION__, reg_info_p->name ? reg_info_p->name + : "<unnamed-register>", + *reg_num_p, error.AsCString()); + } } + } } + } - const char* reason_str = GetStopReasonString(tid_stop_info.reason); - if (reason_str != nullptr) - { - response.Printf ("reason:%s;", reason_str); - } + const char *reason_str = GetStopReasonString(tid_stop_info.reason); + if (reason_str != nullptr) { + response.Printf("reason:%s;", reason_str); + } - if (!description.empty()) - { - // Description may contains special chars, send as hex bytes. - response.PutCString ("description:"); - response.PutCStringAsRawHex8 (description.c_str ()); - response.PutChar (';'); - } - else if ((tid_stop_info.reason == eStopReasonException) && tid_stop_info.details.exception.type) - { - response.PutCString ("metype:"); - response.PutHex64 (tid_stop_info.details.exception.type); - response.PutCString (";mecount:"); - response.PutHex32 (tid_stop_info.details.exception.data_count); - response.PutChar (';'); - - for (uint32_t i = 0; i < tid_stop_info.details.exception.data_count; ++i) - { - response.PutCString ("medata:"); - response.PutHex64 (tid_stop_info.details.exception.data[i]); - response.PutChar (';'); - } + if (!description.empty()) { + // Description may contains special chars, send as hex bytes. + response.PutCString("description:"); + response.PutCStringAsRawHex8(description.c_str()); + response.PutChar(';'); + } else if ((tid_stop_info.reason == eStopReasonException) && + tid_stop_info.details.exception.type) { + response.PutCString("metype:"); + response.PutHex64(tid_stop_info.details.exception.type); + response.PutCString(";mecount:"); + response.PutHex32(tid_stop_info.details.exception.data_count); + response.PutChar(';'); + + for (uint32_t i = 0; i < tid_stop_info.details.exception.data_count; ++i) { + response.PutCString("medata:"); + response.PutHex64(tid_stop_info.details.exception.data[i]); + response.PutChar(';'); } + } - return SendPacketNoLock (response.GetData(), response.GetSize()); + return SendPacketNoLock(response.GetString()); } -void -GDBRemoteCommunicationServerLLGS::HandleInferiorState_Exited (NativeProcessProtocol *process) -{ - assert (process && "process cannot be NULL"); - - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__); - - PacketResult result = SendStopReasonForState(StateType::eStateExited); - if (result != PacketResult::Success) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to send stop notification for PID %" PRIu64 ", state: eStateExited", __FUNCTION__, process->GetID ()); - } +void GDBRemoteCommunicationServerLLGS::HandleInferiorState_Exited( + NativeProcessProtocol *process) { + assert(process && "process cannot be NULL"); - // Close the pipe to the inferior terminal i/o if we launched it - // and set one up. - MaybeCloseInferiorTerminalConnection (); - - // We are ready to exit the debug monitor. - m_exit_now = true; -} - -void -GDBRemoteCommunicationServerLLGS::HandleInferiorState_Stopped (NativeProcessProtocol *process) -{ - assert (process && "process cannot be NULL"); - - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__); - - // Send the stop reason unless this is the stop after the - // launch or attach. - switch (m_inferior_prev_state) - { - case eStateLaunching: - case eStateAttaching: - // Don't send anything per debugserver behavior. - break; - default: - // In all other cases, send the stop reason. - PacketResult result = SendStopReasonForState(StateType::eStateStopped); - if (result != PacketResult::Success) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to send stop notification for PID %" PRIu64 ", state: eStateExited", __FUNCTION__, process->GetID ()); - } - break; - } -} + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__); -void -GDBRemoteCommunicationServerLLGS::ProcessStateChanged (NativeProcessProtocol *process, lldb::StateType state) -{ - assert (process && "process cannot be NULL"); - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + PacketResult result = SendStopReasonForState(StateType::eStateExited); + if (result != PacketResult::Success) { if (log) - { - log->Printf ("GDBRemoteCommunicationServerLLGS::%s called with NativeProcessProtocol pid %" PRIu64 ", state: %s", - __FUNCTION__, - process->GetID (), - StateAsCString (state)); - } + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed to send stop " + "notification for PID %" PRIu64 ", state: eStateExited", + __FUNCTION__, process->GetID()); + } + + // Close the pipe to the inferior terminal i/o if we launched it + // and set one up. + MaybeCloseInferiorTerminalConnection(); + + // We are ready to exit the debug monitor. + m_exit_now = true; +} + +void GDBRemoteCommunicationServerLLGS::HandleInferiorState_Stopped( + NativeProcessProtocol *process) { + assert(process && "process cannot be NULL"); + + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__); + + // Send the stop reason unless this is the stop after the + // launch or attach. + switch (m_inferior_prev_state) { + case eStateLaunching: + case eStateAttaching: + // Don't send anything per debugserver behavior. + break; + default: + // In all other cases, send the stop reason. + PacketResult result = SendStopReasonForState(StateType::eStateStopped); + if (result != PacketResult::Success) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed to send stop " + "notification for PID %" PRIu64 ", state: eStateExited", + __FUNCTION__, process->GetID()); + } + break; + } +} + +void GDBRemoteCommunicationServerLLGS::ProcessStateChanged( + NativeProcessProtocol *process, lldb::StateType state) { + assert(process && "process cannot be NULL"); + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) { + log->Printf("GDBRemoteCommunicationServerLLGS::%s called with " + "NativeProcessProtocol pid %" PRIu64 ", state: %s", + __FUNCTION__, process->GetID(), StateAsCString(state)); + } + + switch (state) { + case StateType::eStateRunning: + StartSTDIOForwarding(); + break; + + case StateType::eStateStopped: + // Make sure we get all of the pending stdout/stderr from the inferior + // and send it to the lldb host before we send the state change + // notification + SendProcessOutput(); + // Then stop the forwarding, so that any late output (see llvm.org/pr25652) + // does not + // interfere with our protocol. + StopSTDIOForwarding(); + HandleInferiorState_Stopped(process); + break; - switch (state) - { - case StateType::eStateRunning: - StartSTDIOForwarding(); - break; - - case StateType::eStateStopped: - // Make sure we get all of the pending stdout/stderr from the inferior - // and send it to the lldb host before we send the state change - // notification - SendProcessOutput(); - // Then stop the forwarding, so that any late output (see llvm.org/pr25652) does not - // interfere with our protocol. - StopSTDIOForwarding(); - HandleInferiorState_Stopped (process); - break; - - case StateType::eStateExited: - // Same as above - SendProcessOutput(); - StopSTDIOForwarding(); - HandleInferiorState_Exited (process); - break; + case StateType::eStateExited: + // Same as above + SendProcessOutput(); + StopSTDIOForwarding(); + HandleInferiorState_Exited(process); + break; - default: - if (log) - { - log->Printf ("GDBRemoteCommunicationServerLLGS::%s didn't handle state change for pid %" PRIu64 ", new state: %s", - __FUNCTION__, - process->GetID (), - StateAsCString (state)); - } - break; + default: + if (log) { + log->Printf("GDBRemoteCommunicationServerLLGS::%s didn't handle state " + "change for pid %" PRIu64 ", new state: %s", + __FUNCTION__, process->GetID(), StateAsCString(state)); } + break; + } - // Remember the previous state reported to us. - m_inferior_prev_state = state; + // Remember the previous state reported to us. + m_inferior_prev_state = state; } -void -GDBRemoteCommunicationServerLLGS::DidExec (NativeProcessProtocol *process) -{ - ClearProcessSpecificData (); +void GDBRemoteCommunicationServerLLGS::DidExec(NativeProcessProtocol *process) { + ClearProcessSpecificData(); } -void -GDBRemoteCommunicationServerLLGS::DataAvailableCallback () -{ - Log *log (GetLogIfAnyCategoriesSet(GDBR_LOG_COMM)); +void GDBRemoteCommunicationServerLLGS::DataAvailableCallback() { + Log *log(GetLogIfAnyCategoriesSet(GDBR_LOG_COMM)); - if (! m_handshake_completed) - { - if (! HandshakeWithClient()) - { - if(log) - log->Printf("GDBRemoteCommunicationServerLLGS::%s handshake with client failed, exiting", - __FUNCTION__); - m_mainloop.RequestTermination(); - return; - } - m_handshake_completed = true; + if (!m_handshake_completed) { + if (!HandshakeWithClient()) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s handshake with " + "client failed, exiting", + __FUNCTION__); + m_mainloop.RequestTermination(); + return; } + m_handshake_completed = true; + } - bool interrupt = false; - bool done = false; - Error error; - while (true) - { - const PacketResult result = GetPacketAndSendResponse (0, error, interrupt, done); - if (result == PacketResult::ErrorReplyTimeout) - break; // No more packets in the queue - - if ((result != PacketResult::Success)) - { - if(log) - log->Printf("GDBRemoteCommunicationServerLLGS::%s processing a packet failed: %s", - __FUNCTION__, error.AsCString()); - m_mainloop.RequestTermination(); - break; - } + bool interrupt = false; + bool done = false; + Error error; + while (true) { + const PacketResult result = GetPacketAndSendResponse( + std::chrono::microseconds(0), error, interrupt, done); + if (result == PacketResult::ErrorReplyTimeout) + break; // No more packets in the queue + + if ((result != PacketResult::Success)) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s processing a packet " + "failed: %s", + __FUNCTION__, error.AsCString()); + m_mainloop.RequestTermination(); + break; } + } } -Error -GDBRemoteCommunicationServerLLGS::InitializeConnection (std::unique_ptr<Connection> &&connection) -{ - IOObjectSP read_object_sp = connection->GetReadObject(); - GDBRemoteCommunicationServer::SetConnection(connection.release()); +Error GDBRemoteCommunicationServerLLGS::InitializeConnection( + std::unique_ptr<Connection> &&connection) { + IOObjectSP read_object_sp = connection->GetReadObject(); + GDBRemoteCommunicationServer::SetConnection(connection.release()); - Error error; - m_network_handle_up = m_mainloop.RegisterReadObject(read_object_sp, - [this] (MainLoopBase &) { DataAvailableCallback(); }, error); - return error; + Error error; + m_network_handle_up = m_mainloop.RegisterReadObject( + read_object_sp, [this](MainLoopBase &) { DataAvailableCallback(); }, + error); + return error; } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::SendONotification (const char *buffer, uint32_t len) -{ - if ((buffer == nullptr) || (len == 0)) - { - // Nothing to send. - return PacketResult::Success; - } - - StreamString response; - response.PutChar ('O'); - response.PutBytesAsRawHex8 (buffer, len); - - return SendPacketNoLock (response.GetData (), response.GetSize ()); -} - -Error -GDBRemoteCommunicationServerLLGS::SetSTDIOFileDescriptor (int fd) -{ - Error error; - - // Set up the reading/handling of process I/O - std::unique_ptr<ConnectionFileDescriptor> conn_up (new ConnectionFileDescriptor (fd, true)); - if (!conn_up) - { - error.SetErrorString ("failed to create ConnectionFileDescriptor"); - return error; - } +GDBRemoteCommunicationServerLLGS::SendONotification(const char *buffer, + uint32_t len) { + if ((buffer == nullptr) || (len == 0)) { + // Nothing to send. + return PacketResult::Success; + } - m_stdio_communication.SetCloseOnEOF (false); - m_stdio_communication.SetConnection (conn_up.release()); - if (!m_stdio_communication.IsConnected ()) - { - error.SetErrorString ("failed to set connection for inferior I/O communication"); - return error; - } + StreamString response; + response.PutChar('O'); + response.PutBytesAsRawHex8(buffer, len); - return Error(); + return SendPacketNoLock(response.GetString()); } -void -GDBRemoteCommunicationServerLLGS::StartSTDIOForwarding() -{ - // Don't forward if not connected (e.g. when attaching). - if (! m_stdio_communication.IsConnected()) - return; - - // llgs local-process debugging may specify PTY paths, which will make these - // file actions non-null - // process launch -e/o will also make these file actions non-null - // nullptr means that the traffic is expected to flow over gdb-remote protocol - if ( m_process_launch_info.GetFileActionForFD(STDOUT_FILENO) && - m_process_launch_info.GetFileActionForFD(STDERR_FILENO)) - return; - - Error error; - lldbassert(! m_stdio_handle_up); - m_stdio_handle_up = m_mainloop.RegisterReadObject( - m_stdio_communication.GetConnection()->GetReadObject(), - [this] (MainLoopBase &) { SendProcessOutput(); }, error); - - if (! m_stdio_handle_up) - { - // Not much we can do about the failure. Log it and continue without forwarding. - if (Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)) - log->Printf("GDBRemoteCommunicationServerLLGS::%s Failed to set up stdio forwarding: %s", - __FUNCTION__, error.AsCString()); - } -} +Error GDBRemoteCommunicationServerLLGS::SetSTDIOFileDescriptor(int fd) { + Error error; -void -GDBRemoteCommunicationServerLLGS::StopSTDIOForwarding() -{ - m_stdio_handle_up.reset(); -} + // Set up the reading/handling of process I/O + std::unique_ptr<ConnectionFileDescriptor> conn_up( + new ConnectionFileDescriptor(fd, true)); + if (!conn_up) { + error.SetErrorString("failed to create ConnectionFileDescriptor"); + return error; + } -void -GDBRemoteCommunicationServerLLGS::SendProcessOutput() -{ - char buffer[1024]; - ConnectionStatus status; - Error error; - while (true) - { - size_t bytes_read = m_stdio_communication.Read(buffer, sizeof buffer, 0, status, &error); - switch (status) - { - case eConnectionStatusSuccess: - SendONotification(buffer, bytes_read); - break; - case eConnectionStatusLostConnection: - case eConnectionStatusEndOfFile: - case eConnectionStatusError: - case eConnectionStatusNoConnection: - if (Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)) - log->Printf("GDBRemoteCommunicationServerLLGS::%s Stopping stdio forwarding as communication returned status %d (error: %s)", __FUNCTION__, status, error.AsCString()); - m_stdio_handle_up.reset(); - return; - - case eConnectionStatusInterrupted: - case eConnectionStatusTimedOut: - return; - } - } + m_stdio_communication.SetCloseOnEOF(false); + m_stdio_communication.SetConnection(conn_up.release()); + if (!m_stdio_communication.IsConnected()) { + error.SetErrorString( + "failed to set connection for inferior I/O communication"); + return error; + } + + return Error(); +} + +void GDBRemoteCommunicationServerLLGS::StartSTDIOForwarding() { + // Don't forward if not connected (e.g. when attaching). + if (!m_stdio_communication.IsConnected()) + return; + + Error error; + lldbassert(!m_stdio_handle_up); + m_stdio_handle_up = m_mainloop.RegisterReadObject( + m_stdio_communication.GetConnection()->GetReadObject(), + [this](MainLoopBase &) { SendProcessOutput(); }, error); + + if (!m_stdio_handle_up) { + // Not much we can do about the failure. Log it and continue without + // forwarding. + if (Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)) + log->Printf("GDBRemoteCommunicationServerLLGS::%s Failed to set up stdio " + "forwarding: %s", + __FUNCTION__, error.AsCString()); + } +} + +void GDBRemoteCommunicationServerLLGS::StopSTDIOForwarding() { + m_stdio_handle_up.reset(); +} + +void GDBRemoteCommunicationServerLLGS::SendProcessOutput() { + char buffer[1024]; + ConnectionStatus status; + Error error; + while (true) { + size_t bytes_read = m_stdio_communication.Read( + buffer, sizeof buffer, std::chrono::microseconds(0), status, &error); + switch (status) { + case eConnectionStatusSuccess: + SendONotification(buffer, bytes_read); + break; + case eConnectionStatusLostConnection: + case eConnectionStatusEndOfFile: + case eConnectionStatusError: + case eConnectionStatusNoConnection: + if (Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)) + log->Printf("GDBRemoteCommunicationServerLLGS::%s Stopping stdio " + "forwarding as communication returned status %d (error: " + "%s)", + __FUNCTION__, status, error.AsCString()); + m_stdio_handle_up.reset(); + return; + + case eConnectionStatusInterrupted: + case eConnectionStatusTimedOut: + return; + } + } } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_qProcessInfo (StringExtractorGDBRemote &packet) -{ - // Fail if we don't have a current process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - return SendErrorResponse (68); +GDBRemoteCommunicationServerLLGS::Handle_qProcessInfo( + StringExtractorGDBRemote &packet) { + // Fail if we don't have a current process. + if (!m_debugged_process_sp || + (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) + return SendErrorResponse(68); - lldb::pid_t pid = m_debugged_process_sp->GetID (); + lldb::pid_t pid = m_debugged_process_sp->GetID(); - if (pid == LLDB_INVALID_PROCESS_ID) - return SendErrorResponse (1); + if (pid == LLDB_INVALID_PROCESS_ID) + return SendErrorResponse(1); - ProcessInstanceInfo proc_info; - if (!Host::GetProcessInfo (pid, proc_info)) - return SendErrorResponse (1); + ProcessInstanceInfo proc_info; + if (!Host::GetProcessInfo(pid, proc_info)) + return SendErrorResponse(1); - StreamString response; - CreateProcessInfoResponse_DebugServerStyle(proc_info, response); - return SendPacketNoLock (response.GetData (), response.GetSize ()); + StreamString response; + CreateProcessInfoResponse_DebugServerStyle(proc_info, response); + return SendPacketNoLock(response.GetString()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_qC (StringExtractorGDBRemote &packet) -{ - // Fail if we don't have a current process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - return SendErrorResponse (68); +GDBRemoteCommunicationServerLLGS::Handle_qC(StringExtractorGDBRemote &packet) { + // Fail if we don't have a current process. + if (!m_debugged_process_sp || + (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) + return SendErrorResponse(68); - // Make sure we set the current thread so g and p packets return - // the data the gdb will expect. - lldb::tid_t tid = m_debugged_process_sp->GetCurrentThreadID (); - SetCurrentThreadID (tid); + // Make sure we set the current thread so g and p packets return + // the data the gdb will expect. + lldb::tid_t tid = m_debugged_process_sp->GetCurrentThreadID(); + SetCurrentThreadID(tid); - NativeThreadProtocolSP thread_sp = m_debugged_process_sp->GetCurrentThread (); - if (!thread_sp) - return SendErrorResponse (69); + NativeThreadProtocolSP thread_sp = m_debugged_process_sp->GetCurrentThread(); + if (!thread_sp) + return SendErrorResponse(69); - StreamString response; - response.Printf ("QC%" PRIx64, thread_sp->GetID ()); + StreamString response; + response.Printf("QC%" PRIx64, thread_sp->GetID()); - return SendPacketNoLock (response.GetData(), response.GetSize()); + return SendPacketNoLock(response.GetString()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_k (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); +GDBRemoteCommunicationServerLLGS::Handle_k(StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - StopSTDIOForwarding(); + StopSTDIOForwarding(); - if (! m_debugged_process_sp) - { - if (log) - log->Printf("GDBRemoteCommunicationServerLLGS::%s No debugged process found.", __FUNCTION__); - return PacketResult::Success; - } + if (!m_debugged_process_sp) { + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s No debugged process found.", + __FUNCTION__); + return PacketResult::Success; + } - Error error = m_debugged_process_sp->Kill(); - if (error.Fail() && log) - log->Printf("GDBRemoteCommunicationServerLLGS::%s Failed to kill debugged process %" PRIu64 ": %s", - __FUNCTION__, m_debugged_process_sp->GetID(), error.AsCString()); + Error error = m_debugged_process_sp->Kill(); + if (error.Fail() && log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s Failed to kill debugged " + "process %" PRIu64 ": %s", + __FUNCTION__, m_debugged_process_sp->GetID(), + error.AsCString()); - // No OK response for kill packet. - // return SendOKResponse (); - return PacketResult::Success; + // No OK response for kill packet. + // return SendOKResponse (); + return PacketResult::Success; } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_QSetDisableASLR (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen ("QSetDisableASLR:")); - if (packet.GetU32(0)) - m_process_launch_info.GetFlags().Set (eLaunchFlagDisableASLR); - else - m_process_launch_info.GetFlags().Clear (eLaunchFlagDisableASLR); - return SendOKResponse (); +GDBRemoteCommunicationServerLLGS::Handle_QSetDisableASLR( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("QSetDisableASLR:")); + if (packet.GetU32(0)) + m_process_launch_info.GetFlags().Set(eLaunchFlagDisableASLR); + else + m_process_launch_info.GetFlags().Clear(eLaunchFlagDisableASLR); + return SendOKResponse(); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_QSetWorkingDir (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos (::strlen ("QSetWorkingDir:")); - std::string path; - packet.GetHexByteString (path); - m_process_launch_info.SetWorkingDirectory(FileSpec{path, true}); - return SendOKResponse (); +GDBRemoteCommunicationServerLLGS::Handle_QSetWorkingDir( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("QSetWorkingDir:")); + std::string path; + packet.GetHexByteString(path); + m_process_launch_info.SetWorkingDirectory(FileSpec{path, true}); + return SendOKResponse(); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_qGetWorkingDir (StringExtractorGDBRemote &packet) -{ - FileSpec working_dir{m_process_launch_info.GetWorkingDirectory()}; - if (working_dir) - { - StreamString response; - response.PutCStringAsRawHex8(working_dir.GetCString()); - return SendPacketNoLock(response.GetData(), response.GetSize()); - } +GDBRemoteCommunicationServerLLGS::Handle_qGetWorkingDir( + StringExtractorGDBRemote &packet) { + FileSpec working_dir{m_process_launch_info.GetWorkingDirectory()}; + if (working_dir) { + StreamString response; + response.PutCStringAsRawHex8(working_dir.GetCString()); + return SendPacketNoLock(response.GetString()); + } - return SendErrorResponse(14); + return SendErrorResponse(14); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_C (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_THREAD)); - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__); - - // Ensure we have a native process. - if (!m_debugged_process_sp) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s no debugged process shared pointer", __FUNCTION__); - return SendErrorResponse (0x36); - } - - // Pull out the signal number. - packet.SetFilePos (::strlen ("C")); - if (packet.GetBytesLeft () < 1) - { - // Shouldn't be using a C without a signal. - return SendIllFormedResponse (packet, "C packet specified without signal."); - } - const uint32_t signo = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ()); - if (signo == std::numeric_limits<uint32_t>::max ()) - return SendIllFormedResponse (packet, "failed to parse signal number"); - - // Handle optional continue address. - if (packet.GetBytesLeft () > 0) - { - // FIXME add continue at address support for $C{signo}[;{continue-address}]. - if (*packet.Peek () == ';') - return SendUnimplementedResponse (packet.GetStringRef().c_str()); - else - return SendIllFormedResponse (packet, "unexpected content after $C{signal-number}"); - } +GDBRemoteCommunicationServerLLGS::Handle_C(StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__); - ResumeActionList resume_actions (StateType::eStateRunning, 0); - Error error; - - // We have two branches: what to do if a continue thread is specified (in which case we target - // sending the signal to that thread), or when we don't have a continue thread set (in which - // case we send a signal to the process). - - // TODO discuss with Greg Clayton, make sure this makes sense. - - lldb::tid_t signal_tid = GetContinueThreadID (); - if (signal_tid != LLDB_INVALID_THREAD_ID) - { - // The resume action for the continue thread (or all threads if a continue thread is not set). - ResumeAction action = { GetContinueThreadID (), StateType::eStateRunning, static_cast<int> (signo) }; - - // Add the action for the continue thread (or all threads when the continue thread isn't present). - resume_actions.Append (action); - } + // Ensure we have a native process. + if (!m_debugged_process_sp) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s no debugged process " + "shared pointer", + __FUNCTION__); + return SendErrorResponse(0x36); + } + + // Pull out the signal number. + packet.SetFilePos(::strlen("C")); + if (packet.GetBytesLeft() < 1) { + // Shouldn't be using a C without a signal. + return SendIllFormedResponse(packet, "C packet specified without signal."); + } + const uint32_t signo = + packet.GetHexMaxU32(false, std::numeric_limits<uint32_t>::max()); + if (signo == std::numeric_limits<uint32_t>::max()) + return SendIllFormedResponse(packet, "failed to parse signal number"); + + // Handle optional continue address. + if (packet.GetBytesLeft() > 0) { + // FIXME add continue at address support for $C{signo}[;{continue-address}]. + if (*packet.Peek() == ';') + return SendUnimplementedResponse(packet.GetStringRef().c_str()); else - { - // Send the signal to the process since we weren't targeting a specific continue thread with the signal. - error = m_debugged_process_sp->Signal (signo); - if (error.Fail ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to send signal for process %" PRIu64 ": %s", - __FUNCTION__, - m_debugged_process_sp->GetID (), - error.AsCString ()); - - return SendErrorResponse (0x52); - } - } - - // Resume the threads. - error = m_debugged_process_sp->Resume (resume_actions); - if (error.Fail ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to resume threads for process %" PRIu64 ": %s", - __FUNCTION__, - m_debugged_process_sp->GetID (), - error.AsCString ()); + return SendIllFormedResponse( + packet, "unexpected content after $C{signal-number}"); + } + + ResumeActionList resume_actions(StateType::eStateRunning, 0); + Error error; + + // We have two branches: what to do if a continue thread is specified (in + // which case we target + // sending the signal to that thread), or when we don't have a continue thread + // set (in which + // case we send a signal to the process). + + // TODO discuss with Greg Clayton, make sure this makes sense. + + lldb::tid_t signal_tid = GetContinueThreadID(); + if (signal_tid != LLDB_INVALID_THREAD_ID) { + // The resume action for the continue thread (or all threads if a continue + // thread is not set). + ResumeAction action = {GetContinueThreadID(), StateType::eStateRunning, + static_cast<int>(signo)}; + + // Add the action for the continue thread (or all threads when the continue + // thread isn't present). + resume_actions.Append(action); + } else { + // Send the signal to the process since we weren't targeting a specific + // continue thread with the signal. + error = m_debugged_process_sp->Signal(signo); + if (error.Fail()) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed to send " + "signal for process %" PRIu64 ": %s", + __FUNCTION__, m_debugged_process_sp->GetID(), + error.AsCString()); + + return SendErrorResponse(0x52); + } + } + + // Resume the threads. + error = m_debugged_process_sp->Resume(resume_actions); + if (error.Fail()) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed to resume " + "threads for process %" PRIu64 ": %s", + __FUNCTION__, m_debugged_process_sp->GetID(), + error.AsCString()); - return SendErrorResponse (0x38); - } + return SendErrorResponse(0x38); + } - // Don't send an "OK" packet; response is the stopped/exited message. - return PacketResult::Success; + // Don't send an "OK" packet; response is the stopped/exited message. + return PacketResult::Success; } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_c (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_THREAD)); - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__); - - packet.SetFilePos (packet.GetFilePos() + ::strlen ("c")); +GDBRemoteCommunicationServerLLGS::Handle_c(StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__); - // For now just support all continue. - const bool has_continue_address = (packet.GetBytesLeft () > 0); - if (has_continue_address) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s not implemented for c{address} variant [%s remains]", __FUNCTION__, packet.Peek ()); - return SendUnimplementedResponse (packet.GetStringRef().c_str()); - } + packet.SetFilePos(packet.GetFilePos() + ::strlen("c")); - // Ensure we have a native process. - if (!m_debugged_process_sp) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s no debugged process shared pointer", __FUNCTION__); - return SendErrorResponse (0x36); - } + // For now just support all continue. + const bool has_continue_address = (packet.GetBytesLeft() > 0); + if (has_continue_address) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s not implemented for " + "c{address} variant [%s remains]", + __FUNCTION__, packet.Peek()); + return SendUnimplementedResponse(packet.GetStringRef().c_str()); + } + + // Ensure we have a native process. + if (!m_debugged_process_sp) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s no debugged process " + "shared pointer", + __FUNCTION__); + return SendErrorResponse(0x36); + } - // Build the ResumeActionList - ResumeActionList actions (StateType::eStateRunning, 0); + // Build the ResumeActionList + ResumeActionList actions(StateType::eStateRunning, 0); - Error error = m_debugged_process_sp->Resume (actions); - if (error.Fail ()) - { - if (log) - { - log->Printf ("GDBRemoteCommunicationServerLLGS::%s c failed for process %" PRIu64 ": %s", - __FUNCTION__, - m_debugged_process_sp->GetID (), - error.AsCString ()); - } - return SendErrorResponse (GDBRemoteServerError::eErrorResume); + Error error = m_debugged_process_sp->Resume(actions); + if (error.Fail()) { + if (log) { + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s c failed for process %" PRIu64 + ": %s", + __FUNCTION__, m_debugged_process_sp->GetID(), error.AsCString()); } + return SendErrorResponse(GDBRemoteServerError::eErrorResume); + } - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s continued process %" PRIu64, __FUNCTION__, m_debugged_process_sp->GetID ()); + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s continued process %" PRIu64, + __FUNCTION__, m_debugged_process_sp->GetID()); - // No response required from continue. - return PacketResult::Success; + // No response required from continue. + return PacketResult::Success; } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_vCont_actions (StringExtractorGDBRemote &packet) -{ - StreamString response; - response.Printf("vCont;c;C;s;S"); +GDBRemoteCommunicationServerLLGS::Handle_vCont_actions( + StringExtractorGDBRemote &packet) { + StreamString response; + response.Printf("vCont;c;C;s;S"); - return SendPacketNoLock(response.GetData(), response.GetSize()); + return SendPacketNoLock(response.GetString()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_vCont (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s handling vCont packet", __FUNCTION__); - - packet.SetFilePos (::strlen ("vCont")); +GDBRemoteCommunicationServerLLGS::Handle_vCont( + StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s handling vCont packet", + __FUNCTION__); - if (packet.GetBytesLeft() == 0) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s missing action from vCont package", __FUNCTION__); - return SendIllFormedResponse (packet, "Missing action from vCont package"); - } + packet.SetFilePos(::strlen("vCont")); - // Check if this is all continue (no options or ";c"). - if (::strcmp (packet.Peek (), ";c") == 0) - { - // Move past the ';', then do a simple 'c'. - packet.SetFilePos (packet.GetFilePos () + 1); - return Handle_c (packet); - } - else if (::strcmp (packet.Peek (), ";s") == 0) - { - // Move past the ';', then do a simple 's'. - packet.SetFilePos (packet.GetFilePos () + 1); - return Handle_s (packet); - } + if (packet.GetBytesLeft() == 0) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s missing action from " + "vCont package", + __FUNCTION__); + return SendIllFormedResponse(packet, "Missing action from vCont package"); + } + + // Check if this is all continue (no options or ";c"). + if (::strcmp(packet.Peek(), ";c") == 0) { + // Move past the ';', then do a simple 'c'. + packet.SetFilePos(packet.GetFilePos() + 1); + return Handle_c(packet); + } else if (::strcmp(packet.Peek(), ";s") == 0) { + // Move past the ';', then do a simple 's'. + packet.SetFilePos(packet.GetFilePos() + 1); + return Handle_s(packet); + } + + // Ensure we have a native process. + if (!m_debugged_process_sp) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s no debugged process " + "shared pointer", + __FUNCTION__); + return SendErrorResponse(0x36); + } + + ResumeActionList thread_actions; + + while (packet.GetBytesLeft() && *packet.Peek() == ';') { + // Skip the semi-colon. + packet.GetChar(); + + // Build up the thread action. + ResumeAction thread_action; + thread_action.tid = LLDB_INVALID_THREAD_ID; + thread_action.state = eStateInvalid; + thread_action.signal = 0; + + const char action = packet.GetChar(); + switch (action) { + case 'C': + thread_action.signal = packet.GetHexMaxU32(false, 0); + if (thread_action.signal == 0) + return SendIllFormedResponse( + packet, "Could not parse signal in vCont packet C action"); + LLVM_FALLTHROUGH; + + case 'c': + // Continue + thread_action.state = eStateRunning; + break; + + case 'S': + thread_action.signal = packet.GetHexMaxU32(false, 0); + if (thread_action.signal == 0) + return SendIllFormedResponse( + packet, "Could not parse signal in vCont packet S action"); + LLVM_FALLTHROUGH; + + case 's': + // Step + thread_action.state = eStateStepping; + break; - // Ensure we have a native process. - if (!m_debugged_process_sp) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s no debugged process shared pointer", __FUNCTION__); - return SendErrorResponse (0x36); + default: + return SendIllFormedResponse(packet, "Unsupported vCont action"); + break; } - ResumeActionList thread_actions; - - while (packet.GetBytesLeft () && *packet.Peek () == ';') - { - // Skip the semi-colon. - packet.GetChar (); - - // Build up the thread action. - ResumeAction thread_action; - thread_action.tid = LLDB_INVALID_THREAD_ID; - thread_action.state = eStateInvalid; - thread_action.signal = 0; - - const char action = packet.GetChar (); - switch (action) - { - case 'C': - thread_action.signal = packet.GetHexMaxU32 (false, 0); - if (thread_action.signal == 0) - return SendIllFormedResponse (packet, "Could not parse signal in vCont packet C action"); - LLVM_FALLTHROUGH; - - case 'c': - // Continue - thread_action.state = eStateRunning; - break; - - case 'S': - thread_action.signal = packet.GetHexMaxU32 (false, 0); - if (thread_action.signal == 0) - return SendIllFormedResponse (packet, "Could not parse signal in vCont packet S action"); - LLVM_FALLTHROUGH; - - case 's': - // Step - thread_action.state = eStateStepping; - break; - - default: - return SendIllFormedResponse (packet, "Unsupported vCont action"); - break; - } - - // Parse out optional :{thread-id} value. - if (packet.GetBytesLeft () && (*packet.Peek () == ':')) - { - // Consume the separator. - packet.GetChar (); - - thread_action.tid = packet.GetHexMaxU32 (false, LLDB_INVALID_THREAD_ID); - if (thread_action.tid == LLDB_INVALID_THREAD_ID) - return SendIllFormedResponse (packet, "Could not parse thread number in vCont packet"); - } + // Parse out optional :{thread-id} value. + if (packet.GetBytesLeft() && (*packet.Peek() == ':')) { + // Consume the separator. + packet.GetChar(); - thread_actions.Append (thread_action); + thread_action.tid = packet.GetHexMaxU32(false, LLDB_INVALID_THREAD_ID); + if (thread_action.tid == LLDB_INVALID_THREAD_ID) + return SendIllFormedResponse( + packet, "Could not parse thread number in vCont packet"); } - Error error = m_debugged_process_sp->Resume (thread_actions); - if (error.Fail ()) - { - if (log) - { - log->Printf ("GDBRemoteCommunicationServerLLGS::%s vCont failed for process %" PRIu64 ": %s", - __FUNCTION__, - m_debugged_process_sp->GetID (), - error.AsCString ()); - } - return SendErrorResponse (GDBRemoteServerError::eErrorResume); + thread_actions.Append(thread_action); + } + + Error error = m_debugged_process_sp->Resume(thread_actions); + if (error.Fail()) { + if (log) { + log->Printf("GDBRemoteCommunicationServerLLGS::%s vCont failed for " + "process %" PRIu64 ": %s", + __FUNCTION__, m_debugged_process_sp->GetID(), + error.AsCString()); } + return SendErrorResponse(GDBRemoteServerError::eErrorResume); + } - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s continued process %" PRIu64, __FUNCTION__, m_debugged_process_sp->GetID ()); + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s continued process %" PRIu64, + __FUNCTION__, m_debugged_process_sp->GetID()); - // No response required from vCont. - return PacketResult::Success; + // No response required from vCont. + return PacketResult::Success; } -void -GDBRemoteCommunicationServerLLGS::SetCurrentThreadID (lldb::tid_t tid) -{ - Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_THREAD)); - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s setting current thread id to %" PRIu64, __FUNCTION__, tid); +void GDBRemoteCommunicationServerLLGS::SetCurrentThreadID(lldb::tid_t tid) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s setting current thread " + "id to %" PRIu64, + __FUNCTION__, tid); - m_current_tid = tid; - if (m_debugged_process_sp) - m_debugged_process_sp->SetCurrentThreadID (m_current_tid); + m_current_tid = tid; + if (m_debugged_process_sp) + m_debugged_process_sp->SetCurrentThreadID(m_current_tid); } -void -GDBRemoteCommunicationServerLLGS::SetContinueThreadID (lldb::tid_t tid) -{ - Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_THREAD)); - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s setting continue thread id to %" PRIu64, __FUNCTION__, tid); +void GDBRemoteCommunicationServerLLGS::SetContinueThreadID(lldb::tid_t tid) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s setting continue thread " + "id to %" PRIu64, + __FUNCTION__, tid); - m_continue_tid = tid; + m_continue_tid = tid; } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_stop_reason (StringExtractorGDBRemote &packet) -{ - // Handle the $? gdbremote command. +GDBRemoteCommunicationServerLLGS::Handle_stop_reason( + StringExtractorGDBRemote &packet) { + // Handle the $? gdbremote command. - // If no process, indicate error - if (!m_debugged_process_sp) - return SendErrorResponse (02); + // If no process, indicate error + if (!m_debugged_process_sp) + return SendErrorResponse(02); - return SendStopReasonForState (m_debugged_process_sp->GetState()); + return SendStopReasonForState(m_debugged_process_sp->GetState()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::SendStopReasonForState (lldb::StateType process_state) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - - switch (process_state) - { - case eStateAttaching: - case eStateLaunching: - case eStateRunning: - case eStateStepping: - case eStateDetached: - // NOTE: gdb protocol doc looks like it should return $OK - // when everything is running (i.e. no stopped result). - return PacketResult::Success; // Ignore - - case eStateSuspended: - case eStateStopped: - case eStateCrashed: - { - lldb::tid_t tid = m_debugged_process_sp->GetCurrentThreadID (); - // Make sure we set the current thread so g and p packets return - // the data the gdb will expect. - SetCurrentThreadID (tid); - return SendStopReplyPacketForThread (tid); - } +GDBRemoteCommunicationServerLLGS::SendStopReasonForState( + lldb::StateType process_state) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + switch (process_state) { + case eStateAttaching: + case eStateLaunching: + case eStateRunning: + case eStateStepping: + case eStateDetached: + // NOTE: gdb protocol doc looks like it should return $OK + // when everything is running (i.e. no stopped result). + return PacketResult::Success; // Ignore + + case eStateSuspended: + case eStateStopped: + case eStateCrashed: { + lldb::tid_t tid = m_debugged_process_sp->GetCurrentThreadID(); + // Make sure we set the current thread so g and p packets return + // the data the gdb will expect. + SetCurrentThreadID(tid); + return SendStopReplyPacketForThread(tid); + } - case eStateInvalid: - case eStateUnloaded: - case eStateExited: - return SendWResponse(m_debugged_process_sp.get()); + case eStateInvalid: + case eStateUnloaded: + case eStateExited: + return SendWResponse(m_debugged_process_sp.get()); - default: - if (log) - { - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 ", current state reporting not handled: %s", - __FUNCTION__, - m_debugged_process_sp->GetID (), - StateAsCString (process_state)); - } - break; + default: + if (log) { + log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 + ", current state reporting not handled: %s", + __FUNCTION__, m_debugged_process_sp->GetID(), + StateAsCString(process_state)); } - - return SendErrorResponse (0); + break; + } + + return SendErrorResponse(0); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_qRegisterInfo (StringExtractorGDBRemote &packet) -{ - // Fail if we don't have a current process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - return SendErrorResponse (68); - - // Ensure we have a thread. - NativeThreadProtocolSP thread_sp (m_debugged_process_sp->GetThreadAtIndex (0)); - if (!thread_sp) - return SendErrorResponse (69); - - // Get the register context for the first thread. - NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ()); - if (!reg_context_sp) - return SendErrorResponse (69); - - // Parse out the register number from the request. - packet.SetFilePos (strlen("qRegisterInfo")); - const uint32_t reg_index = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ()); - if (reg_index == std::numeric_limits<uint32_t>::max ()) - return SendErrorResponse (69); - - // Return the end of registers response if we've iterated one past the end of the register set. - if (reg_index >= reg_context_sp->GetUserRegisterCount ()) - return SendErrorResponse (69); - - const RegisterInfo *reg_info = reg_context_sp->GetRegisterInfoAtIndex(reg_index); - if (!reg_info) - return SendErrorResponse (69); - - // Build the reginfos response. - StreamGDBRemote response; - - response.PutCString ("name:"); - response.PutCString (reg_info->name); - response.PutChar (';'); - - if (reg_info->alt_name && reg_info->alt_name[0]) - { - response.PutCString ("alt-name:"); - response.PutCString (reg_info->alt_name); - response.PutChar (';'); - } - - response.Printf ("bitsize:%" PRIu32 ";offset:%" PRIu32 ";", reg_info->byte_size * 8, reg_info->byte_offset); - - switch (reg_info->encoding) - { - case eEncodingUint: response.PutCString ("encoding:uint;"); break; - case eEncodingSint: response.PutCString ("encoding:sint;"); break; - case eEncodingIEEE754: response.PutCString ("encoding:ieee754;"); break; - case eEncodingVector: response.PutCString ("encoding:vector;"); break; - default: break; - } - - switch (reg_info->format) - { - case eFormatBinary: response.PutCString ("format:binary;"); break; - case eFormatDecimal: response.PutCString ("format:decimal;"); break; - case eFormatHex: response.PutCString ("format:hex;"); break; - case eFormatFloat: response.PutCString ("format:float;"); break; - case eFormatVectorOfSInt8: response.PutCString ("format:vector-sint8;"); break; - case eFormatVectorOfUInt8: response.PutCString ("format:vector-uint8;"); break; - case eFormatVectorOfSInt16: response.PutCString ("format:vector-sint16;"); break; - case eFormatVectorOfUInt16: response.PutCString ("format:vector-uint16;"); break; - case eFormatVectorOfSInt32: response.PutCString ("format:vector-sint32;"); break; - case eFormatVectorOfUInt32: response.PutCString ("format:vector-uint32;"); break; - case eFormatVectorOfFloat32: response.PutCString ("format:vector-float32;"); break; - case eFormatVectorOfUInt128: response.PutCString ("format:vector-uint128;"); break; - default: break; - }; - - const char *const register_set_name = reg_context_sp->GetRegisterSetNameForRegisterAtIndex(reg_index); - if (register_set_name) - { - response.PutCString ("set:"); - response.PutCString (register_set_name); - response.PutChar (';'); - } - - if (reg_info->kinds[RegisterKind::eRegisterKindEHFrame] != LLDB_INVALID_REGNUM) - response.Printf ("ehframe:%" PRIu32 ";", reg_info->kinds[RegisterKind::eRegisterKindEHFrame]); - - if (reg_info->kinds[RegisterKind::eRegisterKindDWARF] != LLDB_INVALID_REGNUM) - response.Printf ("dwarf:%" PRIu32 ";", reg_info->kinds[RegisterKind::eRegisterKindDWARF]); - - switch (reg_info->kinds[RegisterKind::eRegisterKindGeneric]) - { - case LLDB_REGNUM_GENERIC_PC: response.PutCString("generic:pc;"); break; - case LLDB_REGNUM_GENERIC_SP: response.PutCString("generic:sp;"); break; - case LLDB_REGNUM_GENERIC_FP: response.PutCString("generic:fp;"); break; - case LLDB_REGNUM_GENERIC_RA: response.PutCString("generic:ra;"); break; - case LLDB_REGNUM_GENERIC_FLAGS: response.PutCString("generic:flags;"); break; - case LLDB_REGNUM_GENERIC_ARG1: response.PutCString("generic:arg1;"); break; - case LLDB_REGNUM_GENERIC_ARG2: response.PutCString("generic:arg2;"); break; - case LLDB_REGNUM_GENERIC_ARG3: response.PutCString("generic:arg3;"); break; - case LLDB_REGNUM_GENERIC_ARG4: response.PutCString("generic:arg4;"); break; - case LLDB_REGNUM_GENERIC_ARG5: response.PutCString("generic:arg5;"); break; - case LLDB_REGNUM_GENERIC_ARG6: response.PutCString("generic:arg6;"); break; - case LLDB_REGNUM_GENERIC_ARG7: response.PutCString("generic:arg7;"); break; - case LLDB_REGNUM_GENERIC_ARG8: response.PutCString("generic:arg8;"); break; - default: break; - } - - if (reg_info->value_regs && reg_info->value_regs[0] != LLDB_INVALID_REGNUM) - { - response.PutCString ("container-regs:"); - int i = 0; - for (const uint32_t *reg_num = reg_info->value_regs; *reg_num != LLDB_INVALID_REGNUM; ++reg_num, ++i) - { - if (i > 0) - response.PutChar (','); - response.Printf ("%" PRIx32, *reg_num); - } - response.PutChar (';'); - } - - if (reg_info->invalidate_regs && reg_info->invalidate_regs[0]) - { - response.PutCString ("invalidate-regs:"); - int i = 0; - for (const uint32_t *reg_num = reg_info->invalidate_regs; *reg_num != LLDB_INVALID_REGNUM; ++reg_num, ++i) - { - if (i > 0) - response.PutChar (','); - response.Printf ("%" PRIx32, *reg_num); - } - response.PutChar (';'); - } - - if (reg_info->dynamic_size_dwarf_expr_bytes) - { - const size_t dwarf_opcode_len = reg_info->dynamic_size_dwarf_len; - response.PutCString("dynamic_size_dwarf_expr_bytes:"); - for(uint32_t i = 0; i < dwarf_opcode_len; ++i) - response.PutHex8 (reg_info->dynamic_size_dwarf_expr_bytes[i]); - response.PutChar(';'); - } - return SendPacketNoLock(response.GetData(), response.GetSize()); +GDBRemoteCommunicationServerLLGS::Handle_qRegisterInfo( + StringExtractorGDBRemote &packet) { + // Fail if we don't have a current process. + if (!m_debugged_process_sp || + (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) + return SendErrorResponse(68); + + // Ensure we have a thread. + NativeThreadProtocolSP thread_sp(m_debugged_process_sp->GetThreadAtIndex(0)); + if (!thread_sp) + return SendErrorResponse(69); + + // Get the register context for the first thread. + NativeRegisterContextSP reg_context_sp(thread_sp->GetRegisterContext()); + if (!reg_context_sp) + return SendErrorResponse(69); + + // Parse out the register number from the request. + packet.SetFilePos(strlen("qRegisterInfo")); + const uint32_t reg_index = + packet.GetHexMaxU32(false, std::numeric_limits<uint32_t>::max()); + if (reg_index == std::numeric_limits<uint32_t>::max()) + return SendErrorResponse(69); + + // Return the end of registers response if we've iterated one past the end of + // the register set. + if (reg_index >= reg_context_sp->GetUserRegisterCount()) + return SendErrorResponse(69); + + const RegisterInfo *reg_info = + reg_context_sp->GetRegisterInfoAtIndex(reg_index); + if (!reg_info) + return SendErrorResponse(69); + + // Build the reginfos response. + StreamGDBRemote response; + + response.PutCString("name:"); + response.PutCString(reg_info->name); + response.PutChar(';'); + + if (reg_info->alt_name && reg_info->alt_name[0]) { + response.PutCString("alt-name:"); + response.PutCString(reg_info->alt_name); + response.PutChar(';'); + } + + response.Printf("bitsize:%" PRIu32 ";offset:%" PRIu32 ";", + reg_info->byte_size * 8, reg_info->byte_offset); + + switch (reg_info->encoding) { + case eEncodingUint: + response.PutCString("encoding:uint;"); + break; + case eEncodingSint: + response.PutCString("encoding:sint;"); + break; + case eEncodingIEEE754: + response.PutCString("encoding:ieee754;"); + break; + case eEncodingVector: + response.PutCString("encoding:vector;"); + break; + default: + break; + } + + switch (reg_info->format) { + case eFormatBinary: + response.PutCString("format:binary;"); + break; + case eFormatDecimal: + response.PutCString("format:decimal;"); + break; + case eFormatHex: + response.PutCString("format:hex;"); + break; + case eFormatFloat: + response.PutCString("format:float;"); + break; + case eFormatVectorOfSInt8: + response.PutCString("format:vector-sint8;"); + break; + case eFormatVectorOfUInt8: + response.PutCString("format:vector-uint8;"); + break; + case eFormatVectorOfSInt16: + response.PutCString("format:vector-sint16;"); + break; + case eFormatVectorOfUInt16: + response.PutCString("format:vector-uint16;"); + break; + case eFormatVectorOfSInt32: + response.PutCString("format:vector-sint32;"); + break; + case eFormatVectorOfUInt32: + response.PutCString("format:vector-uint32;"); + break; + case eFormatVectorOfFloat32: + response.PutCString("format:vector-float32;"); + break; + case eFormatVectorOfUInt64: + response.PutCString("format:vector-uint64;"); + break; + case eFormatVectorOfUInt128: + response.PutCString("format:vector-uint128;"); + break; + default: + break; + }; + + const char *const register_set_name = + reg_context_sp->GetRegisterSetNameForRegisterAtIndex(reg_index); + if (register_set_name) { + response.PutCString("set:"); + response.PutCString(register_set_name); + response.PutChar(';'); + } + + if (reg_info->kinds[RegisterKind::eRegisterKindEHFrame] != + LLDB_INVALID_REGNUM) + response.Printf("ehframe:%" PRIu32 ";", + reg_info->kinds[RegisterKind::eRegisterKindEHFrame]); + + if (reg_info->kinds[RegisterKind::eRegisterKindDWARF] != LLDB_INVALID_REGNUM) + response.Printf("dwarf:%" PRIu32 ";", + reg_info->kinds[RegisterKind::eRegisterKindDWARF]); + + switch (reg_info->kinds[RegisterKind::eRegisterKindGeneric]) { + case LLDB_REGNUM_GENERIC_PC: + response.PutCString("generic:pc;"); + break; + case LLDB_REGNUM_GENERIC_SP: + response.PutCString("generic:sp;"); + break; + case LLDB_REGNUM_GENERIC_FP: + response.PutCString("generic:fp;"); + break; + case LLDB_REGNUM_GENERIC_RA: + response.PutCString("generic:ra;"); + break; + case LLDB_REGNUM_GENERIC_FLAGS: + response.PutCString("generic:flags;"); + break; + case LLDB_REGNUM_GENERIC_ARG1: + response.PutCString("generic:arg1;"); + break; + case LLDB_REGNUM_GENERIC_ARG2: + response.PutCString("generic:arg2;"); + break; + case LLDB_REGNUM_GENERIC_ARG3: + response.PutCString("generic:arg3;"); + break; + case LLDB_REGNUM_GENERIC_ARG4: + response.PutCString("generic:arg4;"); + break; + case LLDB_REGNUM_GENERIC_ARG5: + response.PutCString("generic:arg5;"); + break; + case LLDB_REGNUM_GENERIC_ARG6: + response.PutCString("generic:arg6;"); + break; + case LLDB_REGNUM_GENERIC_ARG7: + response.PutCString("generic:arg7;"); + break; + case LLDB_REGNUM_GENERIC_ARG8: + response.PutCString("generic:arg8;"); + break; + default: + break; + } + + if (reg_info->value_regs && reg_info->value_regs[0] != LLDB_INVALID_REGNUM) { + response.PutCString("container-regs:"); + int i = 0; + for (const uint32_t *reg_num = reg_info->value_regs; + *reg_num != LLDB_INVALID_REGNUM; ++reg_num, ++i) { + if (i > 0) + response.PutChar(','); + response.Printf("%" PRIx32, *reg_num); + } + response.PutChar(';'); + } + + if (reg_info->invalidate_regs && reg_info->invalidate_regs[0]) { + response.PutCString("invalidate-regs:"); + int i = 0; + for (const uint32_t *reg_num = reg_info->invalidate_regs; + *reg_num != LLDB_INVALID_REGNUM; ++reg_num, ++i) { + if (i > 0) + response.PutChar(','); + response.Printf("%" PRIx32, *reg_num); + } + response.PutChar(';'); + } + + if (reg_info->dynamic_size_dwarf_expr_bytes) { + const size_t dwarf_opcode_len = reg_info->dynamic_size_dwarf_len; + response.PutCString("dynamic_size_dwarf_expr_bytes:"); + for (uint32_t i = 0; i < dwarf_opcode_len; ++i) + response.PutHex8(reg_info->dynamic_size_dwarf_expr_bytes[i]); + response.PutChar(';'); + } + return SendPacketNoLock(response.GetString()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_qfThreadInfo (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); - - // Fail if we don't have a current process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s() no process (%s), returning OK", __FUNCTION__, m_debugged_process_sp ? "invalid process id" : "null m_debugged_process_sp"); - return SendOKResponse (); - } - - StreamGDBRemote response; - response.PutChar ('m'); +GDBRemoteCommunicationServerLLGS::Handle_qfThreadInfo( + StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + // Fail if we don't have a current process. + if (!m_debugged_process_sp || + (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) { if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s() starting thread iteration", __FUNCTION__); - - NativeThreadProtocolSP thread_sp; - uint32_t thread_index; - for (thread_index = 0, thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index); - thread_sp; - ++thread_index, thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index)) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s() iterated thread %" PRIu32 "(%s, tid=0x%" PRIx64 ")", __FUNCTION__, thread_index, thread_sp ? "is not null" : "null", thread_sp ? thread_sp->GetID () : LLDB_INVALID_THREAD_ID); - if (thread_index > 0) - response.PutChar(','); - response.Printf ("%" PRIx64, thread_sp->GetID ()); - } - + log->Printf("GDBRemoteCommunicationServerLLGS::%s() no process (%s), " + "returning OK", + __FUNCTION__, + m_debugged_process_sp ? "invalid process id" + : "null m_debugged_process_sp"); + return SendOKResponse(); + } + + StreamGDBRemote response; + response.PutChar('m'); + + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s() starting thread iteration", + __FUNCTION__); + + NativeThreadProtocolSP thread_sp; + uint32_t thread_index; + for (thread_index = 0, + thread_sp = m_debugged_process_sp->GetThreadAtIndex(thread_index); + thread_sp; ++thread_index, + thread_sp = m_debugged_process_sp->GetThreadAtIndex(thread_index)) { if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s() finished thread iteration", __FUNCTION__); + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s() iterated thread %" PRIu32 + "(%s, tid=0x%" PRIx64 ")", + __FUNCTION__, thread_index, thread_sp ? "is not null" : "null", + thread_sp ? thread_sp->GetID() : LLDB_INVALID_THREAD_ID); + if (thread_index > 0) + response.PutChar(','); + response.Printf("%" PRIx64, thread_sp->GetID()); + } + + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s() finished thread iteration", + __FUNCTION__); - return SendPacketNoLock(response.GetData(), response.GetSize()); + return SendPacketNoLock(response.GetString()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_qsThreadInfo (StringExtractorGDBRemote &packet) -{ - // FIXME for now we return the full thread list in the initial packet and always do nothing here. - return SendPacketNoLock ("l", 1); +GDBRemoteCommunicationServerLLGS::Handle_qsThreadInfo( + StringExtractorGDBRemote &packet) { + // FIXME for now we return the full thread list in the initial packet and + // always do nothing here. + return SendPacketNoLock("l"); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_p (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); - - // Parse out the register number from the request. - packet.SetFilePos (strlen("p")); - const uint32_t reg_index = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ()); - if (reg_index == std::numeric_limits<uint32_t>::max ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, could not parse register number from request \"%s\"", __FUNCTION__, packet.GetStringRef ().c_str ()); - return SendErrorResponse (0x15); - } - - // Get the thread to use. - NativeThreadProtocolSP thread_sp = GetThreadFromSuffix (packet); - if (!thread_sp) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no thread available", __FUNCTION__); - return SendErrorResponse (0x15); - } - - // Get the thread's register context. - NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ()); - if (!reg_context_sp) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 " failed, no register context available for the thread", __FUNCTION__, m_debugged_process_sp->GetID (), thread_sp->GetID ()); - return SendErrorResponse (0x15); - } - - // Return the end of registers response if we've iterated one past the end of the register set. - if (reg_index >= reg_context_sp->GetUserRegisterCount ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, requested register %" PRIu32 " beyond register count %" PRIu32, __FUNCTION__, reg_index, reg_context_sp->GetUserRegisterCount ()); - return SendErrorResponse (0x15); - } - - const RegisterInfo *reg_info = reg_context_sp->GetRegisterInfoAtIndex(reg_index); - if (!reg_info) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, requested register %" PRIu32 " returned NULL", __FUNCTION__, reg_index); - return SendErrorResponse (0x15); - } - - // Build the reginfos response. - StreamGDBRemote response; - - // Retrieve the value - RegisterValue reg_value; - Error error = reg_context_sp->ReadRegister (reg_info, reg_value); - if (error.Fail ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, read of requested register %" PRIu32 " (%s) failed: %s", __FUNCTION__, reg_index, reg_info->name, error.AsCString ()); - return SendErrorResponse (0x15); - } - - const uint8_t *const data = reinterpret_cast<const uint8_t*> (reg_value.GetBytes ()); - if (!data) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to get data bytes from requested register %" PRIu32, __FUNCTION__, reg_index); - return SendErrorResponse (0x15); - } +GDBRemoteCommunicationServerLLGS::Handle_p(StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + + // Parse out the register number from the request. + packet.SetFilePos(strlen("p")); + const uint32_t reg_index = + packet.GetHexMaxU32(false, std::numeric_limits<uint32_t>::max()); + if (reg_index == std::numeric_limits<uint32_t>::max()) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed, could not " + "parse register number from request \"%s\"", + __FUNCTION__, packet.GetStringRef().c_str()); + return SendErrorResponse(0x15); + } + + // Get the thread to use. + NativeThreadProtocolSP thread_sp = GetThreadFromSuffix(packet); + if (!thread_sp) { + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s failed, no thread available", + __FUNCTION__); + return SendErrorResponse(0x15); + } + + // Get the thread's register context. + NativeRegisterContextSP reg_context_sp(thread_sp->GetRegisterContext()); + if (!reg_context_sp) { + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 + " failed, no register context available for the thread", + __FUNCTION__, m_debugged_process_sp->GetID(), thread_sp->GetID()); + return SendErrorResponse(0x15); + } + + // Return the end of registers response if we've iterated one past the end of + // the register set. + if (reg_index >= reg_context_sp->GetUserRegisterCount()) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed, requested " + "register %" PRIu32 " beyond register count %" PRIu32, + __FUNCTION__, reg_index, + reg_context_sp->GetUserRegisterCount()); + return SendErrorResponse(0x15); + } + + const RegisterInfo *reg_info = + reg_context_sp->GetRegisterInfoAtIndex(reg_index); + if (!reg_info) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed, requested " + "register %" PRIu32 " returned NULL", + __FUNCTION__, reg_index); + return SendErrorResponse(0x15); + } + + // Build the reginfos response. + StreamGDBRemote response; + + // Retrieve the value + RegisterValue reg_value; + Error error = reg_context_sp->ReadRegister(reg_info, reg_value); + if (error.Fail()) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed, read of " + "requested register %" PRIu32 " (%s) failed: %s", + __FUNCTION__, reg_index, reg_info->name, error.AsCString()); + return SendErrorResponse(0x15); + } + + const uint8_t *const data = + reinterpret_cast<const uint8_t *>(reg_value.GetBytes()); + if (!data) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed to get data " + "bytes from requested register %" PRIu32, + __FUNCTION__, reg_index); + return SendErrorResponse(0x15); + } - // FIXME flip as needed to get data in big/little endian format for this host. - for (uint32_t i = 0; i < reg_value.GetByteSize (); ++i) - response.PutHex8 (data[i]); + // FIXME flip as needed to get data in big/little endian format for this host. + for (uint32_t i = 0; i < reg_value.GetByteSize(); ++i) + response.PutHex8(data[i]); - return SendPacketNoLock (response.GetData (), response.GetSize ()); + return SendPacketNoLock(response.GetString()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_P (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); - - // Ensure there is more content. - if (packet.GetBytesLeft () < 1) - return SendIllFormedResponse (packet, "Empty P packet"); - - // Parse out the register number from the request. - packet.SetFilePos (strlen("P")); - const uint32_t reg_index = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ()); - if (reg_index == std::numeric_limits<uint32_t>::max ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, could not parse register number from request \"%s\"", __FUNCTION__, packet.GetStringRef ().c_str ()); - return SendErrorResponse (0x29); - } - - // Note debugserver would send an E30 here. - if ((packet.GetBytesLeft () < 1) || (packet.GetChar () != '=')) - return SendIllFormedResponse (packet, "P packet missing '=' char after register number"); - - // Get process architecture. - ArchSpec process_arch; - if (!m_debugged_process_sp || !m_debugged_process_sp->GetArchitecture (process_arch)) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to retrieve inferior architecture", __FUNCTION__); - return SendErrorResponse (0x49); - } - - // Parse out the value. - uint8_t reg_bytes[32]; // big enough to support up to 256 bit ymmN register - size_t reg_size = packet.GetHexBytesAvail (reg_bytes, sizeof(reg_bytes)); - - // Get the thread to use. - NativeThreadProtocolSP thread_sp = GetThreadFromSuffix (packet); - if (!thread_sp) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no thread available (thread index 0)", __FUNCTION__); - return SendErrorResponse (0x28); - } - - // Get the thread's register context. - NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ()); - if (!reg_context_sp) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 " failed, no register context available for the thread", __FUNCTION__, m_debugged_process_sp->GetID (), thread_sp->GetID ()); - return SendErrorResponse (0x15); - } - - const RegisterInfo *reg_info = reg_context_sp->GetRegisterInfoAtIndex (reg_index); - if (!reg_info) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, requested register %" PRIu32 " returned NULL", __FUNCTION__, reg_index); - return SendErrorResponse (0x48); - } - - // Return the end of registers response if we've iterated one past the end of the register set. - if (reg_index >= reg_context_sp->GetUserRegisterCount ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, requested register %" PRIu32 " beyond register count %" PRIu32, __FUNCTION__, reg_index, reg_context_sp->GetUserRegisterCount ()); - return SendErrorResponse (0x47); - } - - // The dwarf expression are evaluate on host site - // which may cause register size to change - // Hence the reg_size may not be same as reg_info->bytes_size - if ((reg_size != reg_info->byte_size) && !(reg_info->dynamic_size_dwarf_expr_bytes)) - { - return SendIllFormedResponse (packet, "P packet register size is incorrect"); - } - - // Build the reginfos response. - StreamGDBRemote response; - - RegisterValue reg_value (reg_bytes, reg_size, process_arch.GetByteOrder ()); - Error error = reg_context_sp->WriteRegister (reg_info, reg_value); - if (error.Fail ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, write of requested register %" PRIu32 " (%s) failed: %s", __FUNCTION__, reg_index, reg_info->name, error.AsCString ()); - return SendErrorResponse (0x32); - } +GDBRemoteCommunicationServerLLGS::Handle_P(StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + + // Ensure there is more content. + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse(packet, "Empty P packet"); + + // Parse out the register number from the request. + packet.SetFilePos(strlen("P")); + const uint32_t reg_index = + packet.GetHexMaxU32(false, std::numeric_limits<uint32_t>::max()); + if (reg_index == std::numeric_limits<uint32_t>::max()) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed, could not " + "parse register number from request \"%s\"", + __FUNCTION__, packet.GetStringRef().c_str()); + return SendErrorResponse(0x29); + } + + // Note debugserver would send an E30 here. + if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != '=')) + return SendIllFormedResponse( + packet, "P packet missing '=' char after register number"); + + // Get process architecture. + ArchSpec process_arch; + if (!m_debugged_process_sp || + !m_debugged_process_sp->GetArchitecture(process_arch)) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed to retrieve " + "inferior architecture", + __FUNCTION__); + return SendErrorResponse(0x49); + } + + // Parse out the value. + uint8_t reg_bytes[32]; // big enough to support up to 256 bit ymmN register + size_t reg_size = packet.GetHexBytesAvail(reg_bytes); + + // Get the thread to use. + NativeThreadProtocolSP thread_sp = GetThreadFromSuffix(packet); + if (!thread_sp) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed, no thread " + "available (thread index 0)", + __FUNCTION__); + return SendErrorResponse(0x28); + } + + // Get the thread's register context. + NativeRegisterContextSP reg_context_sp(thread_sp->GetRegisterContext()); + if (!reg_context_sp) { + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 + " failed, no register context available for the thread", + __FUNCTION__, m_debugged_process_sp->GetID(), thread_sp->GetID()); + return SendErrorResponse(0x15); + } + + const RegisterInfo *reg_info = + reg_context_sp->GetRegisterInfoAtIndex(reg_index); + if (!reg_info) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed, requested " + "register %" PRIu32 " returned NULL", + __FUNCTION__, reg_index); + return SendErrorResponse(0x48); + } + + // Return the end of registers response if we've iterated one past the end of + // the register set. + if (reg_index >= reg_context_sp->GetUserRegisterCount()) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed, requested " + "register %" PRIu32 " beyond register count %" PRIu32, + __FUNCTION__, reg_index, + reg_context_sp->GetUserRegisterCount()); + return SendErrorResponse(0x47); + } + + // The dwarf expression are evaluate on host site + // which may cause register size to change + // Hence the reg_size may not be same as reg_info->bytes_size + if ((reg_size != reg_info->byte_size) && + !(reg_info->dynamic_size_dwarf_expr_bytes)) { + return SendIllFormedResponse(packet, "P packet register size is incorrect"); + } + + // Build the reginfos response. + StreamGDBRemote response; + + RegisterValue reg_value(reg_bytes, reg_size, process_arch.GetByteOrder()); + Error error = reg_context_sp->WriteRegister(reg_info, reg_value); + if (error.Fail()) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed, write of " + "requested register %" PRIu32 " (%s) failed: %s", + __FUNCTION__, reg_index, reg_info->name, error.AsCString()); + return SendErrorResponse(0x32); + } - return SendOKResponse(); + return SendOKResponse(); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_H (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); - - // Fail if we don't have a current process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__); - return SendErrorResponse (0x15); - } - - // Parse out which variant of $H is requested. - packet.SetFilePos (strlen("H")); - if (packet.GetBytesLeft () < 1) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, H command missing {g,c} variant", __FUNCTION__); - return SendIllFormedResponse (packet, "H command missing {g,c} variant"); - } - - const char h_variant = packet.GetChar (); - switch (h_variant) - { - case 'g': - break; - - case 'c': - break; - - default: - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, invalid $H variant %c", __FUNCTION__, h_variant); - return SendIllFormedResponse (packet, "H variant unsupported, should be c or g"); - } - - // Parse out the thread number. - // FIXME return a parse success/fail value. All values are valid here. - const lldb::tid_t tid = packet.GetHexMaxU64 (false, std::numeric_limits<lldb::tid_t>::max ()); +GDBRemoteCommunicationServerLLGS::Handle_H(StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); - // Ensure we have the given thread when not specifying -1 (all threads) or 0 (any thread). - if (tid != LLDB_INVALID_THREAD_ID && tid != 0) - { - NativeThreadProtocolSP thread_sp (m_debugged_process_sp->GetThreadByID (tid)); - if (!thread_sp) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, tid %" PRIu64 " not found", __FUNCTION__, tid); - return SendErrorResponse (0x15); - } - } + // Fail if we don't have a current process. + if (!m_debugged_process_sp || + (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s failed, no process available", + __FUNCTION__); + return SendErrorResponse(0x15); + } + + // Parse out which variant of $H is requested. + packet.SetFilePos(strlen("H")); + if (packet.GetBytesLeft() < 1) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed, H command " + "missing {g,c} variant", + __FUNCTION__); + return SendIllFormedResponse(packet, "H command missing {g,c} variant"); + } - // Now switch the given thread type. - switch (h_variant) - { - case 'g': - SetCurrentThreadID (tid); - break; + const char h_variant = packet.GetChar(); + switch (h_variant) { + case 'g': + break; - case 'c': - SetContinueThreadID (tid); - break; + case 'c': + break; - default: - assert (false && "unsupported $H variant - shouldn't get here"); - return SendIllFormedResponse (packet, "H variant unsupported, should be c or g"); - } - - return SendOKResponse(); + default: + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s failed, invalid $H variant %c", + __FUNCTION__, h_variant); + return SendIllFormedResponse(packet, + "H variant unsupported, should be c or g"); + } + + // Parse out the thread number. + // FIXME return a parse success/fail value. All values are valid here. + const lldb::tid_t tid = + packet.GetHexMaxU64(false, std::numeric_limits<lldb::tid_t>::max()); + + // Ensure we have the given thread when not specifying -1 (all threads) or 0 + // (any thread). + if (tid != LLDB_INVALID_THREAD_ID && tid != 0) { + NativeThreadProtocolSP thread_sp(m_debugged_process_sp->GetThreadByID(tid)); + if (!thread_sp) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed, tid %" PRIu64 + " not found", + __FUNCTION__, tid); + return SendErrorResponse(0x15); + } + } + + // Now switch the given thread type. + switch (h_variant) { + case 'g': + SetCurrentThreadID(tid); + break; + + case 'c': + SetContinueThreadID(tid); + break; + + default: + assert(false && "unsupported $H variant - shouldn't get here"); + return SendIllFormedResponse(packet, + "H variant unsupported, should be c or g"); + } + + return SendOKResponse(); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_I (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); +GDBRemoteCommunicationServerLLGS::Handle_I(StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); - // Fail if we don't have a current process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__); - return SendErrorResponse (0x15); - } - - packet.SetFilePos (::strlen("I")); - char tmp[4096]; - for (;;) - { - size_t read = packet.GetHexBytesAvail(tmp, sizeof(tmp)); - if (read == 0) - { - break; - } - // write directly to stdin *this might block if stdin buffer is full* - // TODO: enqueue this block in circular buffer and send window size to remote host - ConnectionStatus status; - Error error; - m_stdio_communication.Write(tmp, read, status, &error); - if (error.Fail()) - { - return SendErrorResponse (0x15); - } + // Fail if we don't have a current process. + if (!m_debugged_process_sp || + (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s failed, no process available", + __FUNCTION__); + return SendErrorResponse(0x15); + } + + packet.SetFilePos(::strlen("I")); + uint8_t tmp[4096]; + for (;;) { + size_t read = packet.GetHexBytesAvail(tmp); + if (read == 0) { + break; + } + // write directly to stdin *this might block if stdin buffer is full* + // TODO: enqueue this block in circular buffer and send window size to + // remote host + ConnectionStatus status; + Error error; + m_stdio_communication.Write(tmp, read, status, &error); + if (error.Fail()) { + return SendErrorResponse(0x15); } + } - return SendOKResponse(); + return SendOKResponse(); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_interrupt (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); - - // Fail if we don't have a current process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__); - return SendErrorResponse (0x15); - } - - // Interrupt the process. - Error error = m_debugged_process_sp->Interrupt (); - if (error.Fail ()) - { - if (log) - { - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed for process %" PRIu64 ": %s", - __FUNCTION__, - m_debugged_process_sp->GetID (), - error.AsCString ()); - } - return SendErrorResponse (GDBRemoteServerError::eErrorResume); - } +GDBRemoteCommunicationServerLLGS::Handle_interrupt( + StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); + // Fail if we don't have a current process. + if (!m_debugged_process_sp || + (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) { if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s stopped process %" PRIu64, __FUNCTION__, m_debugged_process_sp->GetID ()); + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s failed, no process available", + __FUNCTION__); + return SendErrorResponse(0x15); + } + + // Interrupt the process. + Error error = m_debugged_process_sp->Interrupt(); + if (error.Fail()) { + if (log) { + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s failed for process %" PRIu64 + ": %s", + __FUNCTION__, m_debugged_process_sp->GetID(), error.AsCString()); + } + return SendErrorResponse(GDBRemoteServerError::eErrorResume); + } + + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s stopped process %" PRIu64, + __FUNCTION__, m_debugged_process_sp->GetID()); - // No response required from stop all. - return PacketResult::Success; + // No response required from stop all. + return PacketResult::Success; } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_memory_read(StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__); - return SendErrorResponse (0x15); - } - - // Parse out the memory address. - packet.SetFilePos (strlen("m")); - if (packet.GetBytesLeft() < 1) - return SendIllFormedResponse(packet, "Too short m packet"); - - // Read the address. Punting on validation. - // FIXME replace with Hex U64 read with no default value that fails on failed read. - const lldb::addr_t read_addr = packet.GetHexMaxU64(false, 0); - - // Validate comma. - if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ',')) - return SendIllFormedResponse(packet, "Comma sep missing in m packet"); - - // Get # bytes to read. - if (packet.GetBytesLeft() < 1) - return SendIllFormedResponse(packet, "Length missing in m packet"); - - const uint64_t byte_count = packet.GetHexMaxU64(false, 0); - if (byte_count == 0) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s nothing to read: zero-length packet", __FUNCTION__); - return SendOKResponse(); - } - - // Allocate the response buffer. - std::string buf(byte_count, '\0'); - if (buf.empty()) - return SendErrorResponse (0x78); - - - // Retrieve the process memory. - size_t bytes_read = 0; - Error error = m_debugged_process_sp->ReadMemoryWithoutTrap(read_addr, &buf[0], byte_count, bytes_read); - if (error.Fail ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " mem 0x%" PRIx64 ": failed to read. Error: %s", __FUNCTION__, m_debugged_process_sp->GetID (), read_addr, error.AsCString ()); - return SendErrorResponse (0x08); - } +GDBRemoteCommunicationServerLLGS::Handle_memory_read( + StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (bytes_read == 0) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " mem 0x%" PRIx64 ": read 0 of %" PRIu64 " requested bytes", __FUNCTION__, m_debugged_process_sp->GetID (), read_addr, byte_count); - return SendErrorResponse (0x08); - } - - StreamGDBRemote response; - packet.SetFilePos(0); - char kind = packet.GetChar('?'); - if (kind == 'x') - response.PutEscapedBytes(buf.data(), byte_count); - else - { - assert(kind == 'm'); - for (size_t i = 0; i < bytes_read; ++i) - response.PutHex8(buf[i]); - } - - return SendPacketNoLock(response.GetData(), response.GetSize()); + if (!m_debugged_process_sp || + (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s failed, no process available", + __FUNCTION__); + return SendErrorResponse(0x15); + } + + // Parse out the memory address. + packet.SetFilePos(strlen("m")); + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse(packet, "Too short m packet"); + + // Read the address. Punting on validation. + // FIXME replace with Hex U64 read with no default value that fails on failed + // read. + const lldb::addr_t read_addr = packet.GetHexMaxU64(false, 0); + + // Validate comma. + if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ',')) + return SendIllFormedResponse(packet, "Comma sep missing in m packet"); + + // Get # bytes to read. + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse(packet, "Length missing in m packet"); + + const uint64_t byte_count = packet.GetHexMaxU64(false, 0); + if (byte_count == 0) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s nothing to read: " + "zero-length packet", + __FUNCTION__); + return SendOKResponse(); + } + + // Allocate the response buffer. + std::string buf(byte_count, '\0'); + if (buf.empty()) + return SendErrorResponse(0x78); + + // Retrieve the process memory. + size_t bytes_read = 0; + Error error = m_debugged_process_sp->ReadMemoryWithoutTrap( + read_addr, &buf[0], byte_count, bytes_read); + if (error.Fail()) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 + " mem 0x%" PRIx64 ": failed to read. Error: %s", + __FUNCTION__, m_debugged_process_sp->GetID(), read_addr, + error.AsCString()); + return SendErrorResponse(0x08); + } + + if (bytes_read == 0) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 + " mem 0x%" PRIx64 ": read 0 of %" PRIu64 " requested bytes", + __FUNCTION__, m_debugged_process_sp->GetID(), read_addr, + byte_count); + return SendErrorResponse(0x08); + } + + StreamGDBRemote response; + packet.SetFilePos(0); + char kind = packet.GetChar('?'); + if (kind == 'x') + response.PutEscapedBytes(buf.data(), byte_count); + else { + assert(kind == 'm'); + for (size_t i = 0; i < bytes_read; ++i) + response.PutHex8(buf[i]); + } + + return SendPacketNoLock(response.GetString()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_M (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__); - return SendErrorResponse (0x15); - } - - // Parse out the memory address. - packet.SetFilePos (strlen("M")); - if (packet.GetBytesLeft() < 1) - return SendIllFormedResponse(packet, "Too short M packet"); - - // Read the address. Punting on validation. - // FIXME replace with Hex U64 read with no default value that fails on failed read. - const lldb::addr_t write_addr = packet.GetHexMaxU64(false, 0); - - // Validate comma. - if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ',')) - return SendIllFormedResponse(packet, "Comma sep missing in M packet"); - - // Get # bytes to read. - if (packet.GetBytesLeft() < 1) - return SendIllFormedResponse(packet, "Length missing in M packet"); +GDBRemoteCommunicationServerLLGS::Handle_M(StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - const uint64_t byte_count = packet.GetHexMaxU64(false, 0); - if (byte_count == 0) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s nothing to write: zero-length packet", __FUNCTION__); - return PacketResult::Success; - } - - // Validate colon. - if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ':')) - return SendIllFormedResponse(packet, "Comma sep missing in M packet after byte length"); - - // Allocate the conversion buffer. - std::vector<uint8_t> buf(byte_count, 0); - if (buf.empty()) - return SendErrorResponse (0x78); - - // Convert the hex memory write contents to bytes. - StreamGDBRemote response; - const uint64_t convert_count = packet.GetHexBytes(&buf[0], byte_count, 0); - if (convert_count != byte_count) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " mem 0x%" PRIx64 ": asked to write %" PRIu64 " bytes, but only found %" PRIu64 " to convert.", __FUNCTION__, m_debugged_process_sp->GetID (), write_addr, byte_count, convert_count); - return SendIllFormedResponse (packet, "M content byte length specified did not match hex-encoded content length"); - } - - // Write the process memory. - size_t bytes_written = 0; - Error error = m_debugged_process_sp->WriteMemory (write_addr, &buf[0], byte_count, bytes_written); - if (error.Fail ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " mem 0x%" PRIx64 ": failed to write. Error: %s", __FUNCTION__, m_debugged_process_sp->GetID (), write_addr, error.AsCString ()); - return SendErrorResponse (0x09); - } - - if (bytes_written == 0) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " mem 0x%" PRIx64 ": wrote 0 of %" PRIu64 " requested bytes", __FUNCTION__, m_debugged_process_sp->GetID (), write_addr, byte_count); - return SendErrorResponse (0x09); - } + if (!m_debugged_process_sp || + (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s failed, no process available", + __FUNCTION__); + return SendErrorResponse(0x15); + } + + // Parse out the memory address. + packet.SetFilePos(strlen("M")); + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse(packet, "Too short M packet"); + + // Read the address. Punting on validation. + // FIXME replace with Hex U64 read with no default value that fails on failed + // read. + const lldb::addr_t write_addr = packet.GetHexMaxU64(false, 0); + + // Validate comma. + if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ',')) + return SendIllFormedResponse(packet, "Comma sep missing in M packet"); + + // Get # bytes to read. + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse(packet, "Length missing in M packet"); + + const uint64_t byte_count = packet.GetHexMaxU64(false, 0); + if (byte_count == 0) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s nothing to write: " + "zero-length packet", + __FUNCTION__); + return PacketResult::Success; + } + + // Validate colon. + if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ':')) + return SendIllFormedResponse( + packet, "Comma sep missing in M packet after byte length"); + + // Allocate the conversion buffer. + std::vector<uint8_t> buf(byte_count, 0); + if (buf.empty()) + return SendErrorResponse(0x78); + + // Convert the hex memory write contents to bytes. + StreamGDBRemote response; + const uint64_t convert_count = packet.GetHexBytes(buf, 0); + if (convert_count != byte_count) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 + " mem 0x%" PRIx64 ": asked to write %" PRIu64 + " bytes, but only found %" PRIu64 " to convert.", + __FUNCTION__, m_debugged_process_sp->GetID(), write_addr, + byte_count, convert_count); + return SendIllFormedResponse(packet, "M content byte length specified did " + "not match hex-encoded content " + "length"); + } + + // Write the process memory. + size_t bytes_written = 0; + Error error = m_debugged_process_sp->WriteMemory(write_addr, &buf[0], + byte_count, bytes_written); + if (error.Fail()) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 + " mem 0x%" PRIx64 ": failed to write. Error: %s", + __FUNCTION__, m_debugged_process_sp->GetID(), write_addr, + error.AsCString()); + return SendErrorResponse(0x09); + } + + if (bytes_written == 0) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 + " mem 0x%" PRIx64 ": wrote 0 of %" PRIu64 " requested bytes", + __FUNCTION__, m_debugged_process_sp->GetID(), write_addr, + byte_count); + return SendErrorResponse(0x09); + } - return SendOKResponse (); + return SendOKResponse(); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfoSupported (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - - // Currently only the NativeProcessProtocol knows if it can handle a qMemoryRegionInfoSupported - // request, but we're not guaranteed to be attached to a process. For now we'll assume the - // client only asks this when a process is being debugged. - - // Ensure we have a process running; otherwise, we can't figure this out - // since we won't have a NativeProcessProtocol. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__); - return SendErrorResponse (0x15); - } +GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfoSupported( + StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + // Currently only the NativeProcessProtocol knows if it can handle a + // qMemoryRegionInfoSupported + // request, but we're not guaranteed to be attached to a process. For now + // we'll assume the + // client only asks this when a process is being debugged. + + // Ensure we have a process running; otherwise, we can't figure this out + // since we won't have a NativeProcessProtocol. + if (!m_debugged_process_sp || + (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s failed, no process available", + __FUNCTION__); + return SendErrorResponse(0x15); + } - // Test if we can get any region back when asking for the region around NULL. - MemoryRegionInfo region_info; - const Error error = m_debugged_process_sp->GetMemoryRegionInfo (0, region_info); - if (error.Fail ()) - { - // We don't support memory region info collection for this NativeProcessProtocol. - return SendUnimplementedResponse (""); - } + // Test if we can get any region back when asking for the region around NULL. + MemoryRegionInfo region_info; + const Error error = + m_debugged_process_sp->GetMemoryRegionInfo(0, region_info); + if (error.Fail()) { + // We don't support memory region info collection for this + // NativeProcessProtocol. + return SendUnimplementedResponse(""); + } - return SendOKResponse(); + return SendOKResponse(); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - - // Ensure we have a process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__); - return SendErrorResponse (0x15); - } - - // Parse out the memory address. - packet.SetFilePos (strlen("qMemoryRegionInfo:")); - if (packet.GetBytesLeft() < 1) - return SendIllFormedResponse(packet, "Too short qMemoryRegionInfo: packet"); - - // Read the address. Punting on validation. - const lldb::addr_t read_addr = packet.GetHexMaxU64(false, 0); +GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo( + StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - StreamGDBRemote response; - - // Get the memory region info for the target address. - MemoryRegionInfo region_info; - const Error error = m_debugged_process_sp->GetMemoryRegionInfo (read_addr, region_info); - if (error.Fail ()) - { - // Return the error message. - - response.PutCString ("error:"); - response.PutCStringAsRawHex8 (error.AsCString ()); - response.PutChar (';'); - } - else - { - // Range start and size. - response.Printf ("start:%" PRIx64 ";size:%" PRIx64 ";", region_info.GetRange ().GetRangeBase (), region_info.GetRange ().GetByteSize ()); - - // Permissions. - if (region_info.GetReadable () || - region_info.GetWritable () || - region_info.GetExecutable ()) - { - // Write permissions info. - response.PutCString ("permissions:"); - - if (region_info.GetReadable ()) - response.PutChar ('r'); - if (region_info.GetWritable ()) - response.PutChar('w'); - if (region_info.GetExecutable()) - response.PutChar ('x'); - - response.PutChar (';'); - } - } - - return SendPacketNoLock(response.GetData(), response.GetSize()); + // Ensure we have a process. + if (!m_debugged_process_sp || + (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s failed, no process available", + __FUNCTION__); + return SendErrorResponse(0x15); + } + + // Parse out the memory address. + packet.SetFilePos(strlen("qMemoryRegionInfo:")); + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse(packet, "Too short qMemoryRegionInfo: packet"); + + // Read the address. Punting on validation. + const lldb::addr_t read_addr = packet.GetHexMaxU64(false, 0); + + StreamGDBRemote response; + + // Get the memory region info for the target address. + MemoryRegionInfo region_info; + const Error error = + m_debugged_process_sp->GetMemoryRegionInfo(read_addr, region_info); + if (error.Fail()) { + // Return the error message. + + response.PutCString("error:"); + response.PutCStringAsRawHex8(error.AsCString()); + response.PutChar(';'); + } else { + // Range start and size. + response.Printf("start:%" PRIx64 ";size:%" PRIx64 ";", + region_info.GetRange().GetRangeBase(), + region_info.GetRange().GetByteSize()); + + // Permissions. + if (region_info.GetReadable() || region_info.GetWritable() || + region_info.GetExecutable()) { + // Write permissions info. + response.PutCString("permissions:"); + + if (region_info.GetReadable()) + response.PutChar('r'); + if (region_info.GetWritable()) + response.PutChar('w'); + if (region_info.GetExecutable()) + response.PutChar('x'); + + response.PutChar(';'); + } + + // Name + ConstString name = region_info.GetName(); + if (name) { + response.PutCString("name:"); + response.PutCStringAsRawHex8(name.AsCString()); + response.PutChar(';'); + } + } + + return SendPacketNoLock(response.GetString()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_Z (StringExtractorGDBRemote &packet) -{ - // Ensure we have a process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - { - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__); - return SendErrorResponse (0x15); - } - - // Parse out software or hardware breakpoint or watchpoint requested. - packet.SetFilePos (strlen("Z")); - if (packet.GetBytesLeft() < 1) - return SendIllFormedResponse(packet, "Too short Z packet, missing software/hardware specifier"); - - bool want_breakpoint = true; - bool want_hardware = false; - uint32_t watch_flags = 0; - - const GDBStoppointType stoppoint_type = - GDBStoppointType(packet.GetS32 (eStoppointInvalid)); - switch (stoppoint_type) - { - case eBreakpointSoftware: - want_hardware = false; want_breakpoint = true; break; - case eBreakpointHardware: - want_hardware = true; want_breakpoint = true; break; - case eWatchpointWrite: - watch_flags = 1; - want_hardware = true; want_breakpoint = false; break; - case eWatchpointRead: - watch_flags = 2; - want_hardware = true; want_breakpoint = false; break; - case eWatchpointReadWrite: - watch_flags = 3; - want_hardware = true; want_breakpoint = false; break; - case eStoppointInvalid: - return SendIllFormedResponse(packet, "Z packet had invalid software/hardware specifier"); - - } - - if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',') - return SendIllFormedResponse(packet, "Malformed Z packet, expecting comma after stoppoint type"); - - // Parse out the stoppoint address. - if (packet.GetBytesLeft() < 1) - return SendIllFormedResponse(packet, "Too short Z packet, missing address"); - const lldb::addr_t addr = packet.GetHexMaxU64(false, 0); - - if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',') - return SendIllFormedResponse(packet, "Malformed Z packet, expecting comma after address"); - - // Parse out the stoppoint size (i.e. size hint for opcode size). - const uint32_t size = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ()); - if (size == std::numeric_limits<uint32_t>::max ()) - return SendIllFormedResponse(packet, "Malformed Z packet, failed to parse size argument"); - - if (want_breakpoint) - { - // Try to set the breakpoint. - const Error error = m_debugged_process_sp->SetBreakpoint (addr, size, want_hardware); - if (error.Success ()) - return SendOKResponse (); - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 - " failed to set breakpoint: %s", - __FUNCTION__, - m_debugged_process_sp->GetID (), - error.AsCString ()); - return SendErrorResponse (0x09); - } - else - { - // Try to set the watchpoint. - const Error error = m_debugged_process_sp->SetWatchpoint ( - addr, size, watch_flags, want_hardware); - if (error.Success ()) - return SendOKResponse (); - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 - " failed to set watchpoint: %s", - __FUNCTION__, - m_debugged_process_sp->GetID (), - error.AsCString ()); - return SendErrorResponse (0x09); - } +GDBRemoteCommunicationServerLLGS::Handle_Z(StringExtractorGDBRemote &packet) { + // Ensure we have a process. + if (!m_debugged_process_sp || + (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s failed, no process available", + __FUNCTION__); + return SendErrorResponse(0x15); + } + + // Parse out software or hardware breakpoint or watchpoint requested. + packet.SetFilePos(strlen("Z")); + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse( + packet, "Too short Z packet, missing software/hardware specifier"); + + bool want_breakpoint = true; + bool want_hardware = false; + uint32_t watch_flags = 0; + + const GDBStoppointType stoppoint_type = + GDBStoppointType(packet.GetS32(eStoppointInvalid)); + switch (stoppoint_type) { + case eBreakpointSoftware: + want_hardware = false; + want_breakpoint = true; + break; + case eBreakpointHardware: + want_hardware = true; + want_breakpoint = true; + break; + case eWatchpointWrite: + watch_flags = 1; + want_hardware = true; + want_breakpoint = false; + break; + case eWatchpointRead: + watch_flags = 2; + want_hardware = true; + want_breakpoint = false; + break; + case eWatchpointReadWrite: + watch_flags = 3; + want_hardware = true; + want_breakpoint = false; + break; + case eStoppointInvalid: + return SendIllFormedResponse( + packet, "Z packet had invalid software/hardware specifier"); + } + + if ((packet.GetBytesLeft() < 1) || packet.GetChar() != ',') + return SendIllFormedResponse( + packet, "Malformed Z packet, expecting comma after stoppoint type"); + + // Parse out the stoppoint address. + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse(packet, "Too short Z packet, missing address"); + const lldb::addr_t addr = packet.GetHexMaxU64(false, 0); + + if ((packet.GetBytesLeft() < 1) || packet.GetChar() != ',') + return SendIllFormedResponse( + packet, "Malformed Z packet, expecting comma after address"); + + // Parse out the stoppoint size (i.e. size hint for opcode size). + const uint32_t size = + packet.GetHexMaxU32(false, std::numeric_limits<uint32_t>::max()); + if (size == std::numeric_limits<uint32_t>::max()) + return SendIllFormedResponse( + packet, "Malformed Z packet, failed to parse size argument"); + + if (want_breakpoint) { + // Try to set the breakpoint. + const Error error = + m_debugged_process_sp->SetBreakpoint(addr, size, want_hardware); + if (error.Success()) + return SendOKResponse(); + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 + " failed to set breakpoint: %s", + __FUNCTION__, m_debugged_process_sp->GetID(), + error.AsCString()); + return SendErrorResponse(0x09); + } else { + // Try to set the watchpoint. + const Error error = m_debugged_process_sp->SetWatchpoint( + addr, size, watch_flags, want_hardware); + if (error.Success()) + return SendOKResponse(); + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 + " failed to set watchpoint: %s", + __FUNCTION__, m_debugged_process_sp->GetID(), + error.AsCString()); + return SendErrorResponse(0x09); + } } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_z (StringExtractorGDBRemote &packet) -{ - // Ensure we have a process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - { - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__); - return SendErrorResponse (0x15); - } - - // Parse out software or hardware breakpoint or watchpoint requested. - packet.SetFilePos (strlen("z")); - if (packet.GetBytesLeft() < 1) - return SendIllFormedResponse(packet, "Too short z packet, missing software/hardware specifier"); - - bool want_breakpoint = true; - - const GDBStoppointType stoppoint_type = - GDBStoppointType(packet.GetS32 (eStoppointInvalid)); - switch (stoppoint_type) - { - case eBreakpointHardware: want_breakpoint = true; break; - case eBreakpointSoftware: want_breakpoint = true; break; - case eWatchpointWrite: want_breakpoint = false; break; - case eWatchpointRead: want_breakpoint = false; break; - case eWatchpointReadWrite: want_breakpoint = false; break; - default: - return SendIllFormedResponse(packet, "z packet had invalid software/hardware specifier"); - - } - - if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',') - return SendIllFormedResponse(packet, "Malformed z packet, expecting comma after stoppoint type"); - - // Parse out the stoppoint address. - if (packet.GetBytesLeft() < 1) - return SendIllFormedResponse(packet, "Too short z packet, missing address"); - const lldb::addr_t addr = packet.GetHexMaxU64(false, 0); - - if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',') - return SendIllFormedResponse(packet, "Malformed z packet, expecting comma after address"); - - /* - // Parse out the stoppoint size (i.e. size hint for opcode size). - const uint32_t size = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ()); - if (size == std::numeric_limits<uint32_t>::max ()) - return SendIllFormedResponse(packet, "Malformed z packet, failed to parse size argument"); - */ - - if (want_breakpoint) - { - // Try to clear the breakpoint. - const Error error = m_debugged_process_sp->RemoveBreakpoint (addr); - if (error.Success ()) - return SendOKResponse (); - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 - " failed to remove breakpoint: %s", - __FUNCTION__, - m_debugged_process_sp->GetID (), - error.AsCString ()); - return SendErrorResponse (0x09); - } - else - { - // Try to clear the watchpoint. - const Error error = m_debugged_process_sp->RemoveWatchpoint (addr); - if (error.Success ()) - return SendOKResponse (); - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 - " failed to remove watchpoint: %s", - __FUNCTION__, - m_debugged_process_sp->GetID (), - error.AsCString ()); - return SendErrorResponse (0x09); - } +GDBRemoteCommunicationServerLLGS::Handle_z(StringExtractorGDBRemote &packet) { + // Ensure we have a process. + if (!m_debugged_process_sp || + (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s failed, no process available", + __FUNCTION__); + return SendErrorResponse(0x15); + } + + // Parse out software or hardware breakpoint or watchpoint requested. + packet.SetFilePos(strlen("z")); + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse( + packet, "Too short z packet, missing software/hardware specifier"); + + bool want_breakpoint = true; + + const GDBStoppointType stoppoint_type = + GDBStoppointType(packet.GetS32(eStoppointInvalid)); + switch (stoppoint_type) { + case eBreakpointHardware: + want_breakpoint = true; + break; + case eBreakpointSoftware: + want_breakpoint = true; + break; + case eWatchpointWrite: + want_breakpoint = false; + break; + case eWatchpointRead: + want_breakpoint = false; + break; + case eWatchpointReadWrite: + want_breakpoint = false; + break; + default: + return SendIllFormedResponse( + packet, "z packet had invalid software/hardware specifier"); + } + + if ((packet.GetBytesLeft() < 1) || packet.GetChar() != ',') + return SendIllFormedResponse( + packet, "Malformed z packet, expecting comma after stoppoint type"); + + // Parse out the stoppoint address. + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse(packet, "Too short z packet, missing address"); + const lldb::addr_t addr = packet.GetHexMaxU64(false, 0); + + if ((packet.GetBytesLeft() < 1) || packet.GetChar() != ',') + return SendIllFormedResponse( + packet, "Malformed z packet, expecting comma after address"); + + /* + // Parse out the stoppoint size (i.e. size hint for opcode size). + const uint32_t size = packet.GetHexMaxU32 (false, + std::numeric_limits<uint32_t>::max ()); + if (size == std::numeric_limits<uint32_t>::max ()) + return SendIllFormedResponse(packet, "Malformed z packet, failed to parse + size argument"); + */ + + if (want_breakpoint) { + // Try to clear the breakpoint. + const Error error = m_debugged_process_sp->RemoveBreakpoint(addr); + if (error.Success()) + return SendOKResponse(); + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 + " failed to remove breakpoint: %s", + __FUNCTION__, m_debugged_process_sp->GetID(), + error.AsCString()); + return SendErrorResponse(0x09); + } else { + // Try to clear the watchpoint. + const Error error = m_debugged_process_sp->RemoveWatchpoint(addr); + if (error.Success()) + return SendOKResponse(); + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 + " failed to remove watchpoint: %s", + __FUNCTION__, m_debugged_process_sp->GetID(), + error.AsCString()); + return SendErrorResponse(0x09); + } } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_s (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_THREAD)); - - // Ensure we have a process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__); - return SendErrorResponse (0x32); - } +GDBRemoteCommunicationServerLLGS::Handle_s(StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); - // We first try to use a continue thread id. If any one or any all set, use the current thread. - // Bail out if we don't have a thread id. - lldb::tid_t tid = GetContinueThreadID (); - if (tid == 0 || tid == LLDB_INVALID_THREAD_ID) - tid = GetCurrentThreadID (); - if (tid == LLDB_INVALID_THREAD_ID) - return SendErrorResponse (0x33); - - // Double check that we have such a thread. - // TODO investigate: on MacOSX we might need to do an UpdateThreads () here. - NativeThreadProtocolSP thread_sp = m_debugged_process_sp->GetThreadByID (tid); - if (!thread_sp || thread_sp->GetID () != tid) - return SendErrorResponse (0x33); - - // Create the step action for the given thread. - ResumeAction action = { tid, eStateStepping, 0 }; - - // Setup the actions list. - ResumeActionList actions; - actions.Append (action); - - // All other threads stop while we're single stepping a thread. - actions.SetDefaultThreadActionIfNeeded(eStateStopped, 0); - Error error = m_debugged_process_sp->Resume (actions); - if (error.Fail ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 " Resume() failed with error: %s", __FUNCTION__, m_debugged_process_sp->GetID (), tid, error.AsCString ()); - return SendErrorResponse(0x49); - } + // Ensure we have a process. + if (!m_debugged_process_sp || + (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s failed, no process available", + __FUNCTION__); + return SendErrorResponse(0x32); + } + + // We first try to use a continue thread id. If any one or any all set, use + // the current thread. + // Bail out if we don't have a thread id. + lldb::tid_t tid = GetContinueThreadID(); + if (tid == 0 || tid == LLDB_INVALID_THREAD_ID) + tid = GetCurrentThreadID(); + if (tid == LLDB_INVALID_THREAD_ID) + return SendErrorResponse(0x33); + + // Double check that we have such a thread. + // TODO investigate: on MacOSX we might need to do an UpdateThreads () here. + NativeThreadProtocolSP thread_sp = m_debugged_process_sp->GetThreadByID(tid); + if (!thread_sp || thread_sp->GetID() != tid) + return SendErrorResponse(0x33); + + // Create the step action for the given thread. + ResumeAction action = {tid, eStateStepping, 0}; + + // Setup the actions list. + ResumeActionList actions; + actions.Append(action); + + // All other threads stop while we're single stepping a thread. + actions.SetDefaultThreadActionIfNeeded(eStateStopped, 0); + Error error = m_debugged_process_sp->Resume(actions); + if (error.Fail()) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 + " tid %" PRIu64 " Resume() failed with error: %s", + __FUNCTION__, m_debugged_process_sp->GetID(), tid, + error.AsCString()); + return SendErrorResponse(0x49); + } - // No response here - the stop or exit will come from the resulting action. - return PacketResult::Success; + // No response here - the stop or exit will come from the resulting action. + return PacketResult::Success; } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_qXfer_auxv_read (StringExtractorGDBRemote &packet) -{ - // *BSD impls should be able to do this too. +GDBRemoteCommunicationServerLLGS::Handle_qXfer_auxv_read( + StringExtractorGDBRemote &packet) { +// *BSD impls should be able to do this too. #if defined(__linux__) - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - - // Parse out the offset. - packet.SetFilePos (strlen("qXfer:auxv:read::")); - if (packet.GetBytesLeft () < 1) - return SendIllFormedResponse (packet, "qXfer:auxv:read:: packet missing offset"); - - const uint64_t auxv_offset = packet.GetHexMaxU64 (false, std::numeric_limits<uint64_t>::max ()); - if (auxv_offset == std::numeric_limits<uint64_t>::max ()) - return SendIllFormedResponse (packet, "qXfer:auxv:read:: packet missing offset"); - - // Parse out comma. - if (packet.GetBytesLeft () < 1 || packet.GetChar () != ',') - return SendIllFormedResponse (packet, "qXfer:auxv:read:: packet missing comma after offset"); - - // Parse out the length. - const uint64_t auxv_length = packet.GetHexMaxU64 (false, std::numeric_limits<uint64_t>::max ()); - if (auxv_length == std::numeric_limits<uint64_t>::max ()) - return SendIllFormedResponse (packet, "qXfer:auxv:read:: packet missing length"); - - // Grab the auxv data if we need it. - if (!m_active_auxv_buffer_sp) - { - // Make sure we have a valid process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__); - return SendErrorResponse (0x10); - } - - // Grab the auxv data. - m_active_auxv_buffer_sp = Host::GetAuxvData (m_debugged_process_sp->GetID ()); - if (!m_active_auxv_buffer_sp || m_active_auxv_buffer_sp->GetByteSize () == 0) - { - // Hmm, no auxv data, call that an error. - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no auxv data retrieved", __FUNCTION__); - m_active_auxv_buffer_sp.reset (); - return SendErrorResponse (0x11); - } - } - - // FIXME find out if/how I lock the stream here. - - StreamGDBRemote response; - bool done_with_buffer = false; - - if (auxv_offset >= m_active_auxv_buffer_sp->GetByteSize ()) - { - // We have nothing left to send. Mark the buffer as complete. - response.PutChar ('l'); - done_with_buffer = true; - } - else - { - // Figure out how many bytes are available starting at the given offset. - const uint64_t bytes_remaining = m_active_auxv_buffer_sp->GetByteSize () - auxv_offset; - - // Figure out how many bytes we're going to read. - const uint64_t bytes_to_read = (auxv_length > bytes_remaining) ? bytes_remaining : auxv_length; - - // Mark the response type according to whether we're reading the remainder of the auxv data. - if (bytes_to_read >= bytes_remaining) - { - // There will be nothing left to read after this - response.PutChar ('l'); - done_with_buffer = true; - } - else - { - // There will still be bytes to read after this request. - response.PutChar ('m'); - } - - // Now write the data in encoded binary form. - response.PutEscapedBytes (m_active_auxv_buffer_sp->GetBytes () + auxv_offset, bytes_to_read); - } - - if (done_with_buffer) - m_active_auxv_buffer_sp.reset (); - - return SendPacketNoLock(response.GetData(), response.GetSize()); + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + // Parse out the offset. + packet.SetFilePos(strlen("qXfer:auxv:read::")); + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse(packet, + "qXfer:auxv:read:: packet missing offset"); + + const uint64_t auxv_offset = + packet.GetHexMaxU64(false, std::numeric_limits<uint64_t>::max()); + if (auxv_offset == std::numeric_limits<uint64_t>::max()) + return SendIllFormedResponse(packet, + "qXfer:auxv:read:: packet missing offset"); + + // Parse out comma. + if (packet.GetBytesLeft() < 1 || packet.GetChar() != ',') + return SendIllFormedResponse( + packet, "qXfer:auxv:read:: packet missing comma after offset"); + + // Parse out the length. + const uint64_t auxv_length = + packet.GetHexMaxU64(false, std::numeric_limits<uint64_t>::max()); + if (auxv_length == std::numeric_limits<uint64_t>::max()) + return SendIllFormedResponse(packet, + "qXfer:auxv:read:: packet missing length"); + + // Grab the auxv data if we need it. + if (!m_active_auxv_buffer_sp) { + // Make sure we have a valid process. + if (!m_debugged_process_sp || + (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s failed, no process available", + __FUNCTION__); + return SendErrorResponse(0x10); + } + + // Grab the auxv data. + m_active_auxv_buffer_sp = Host::GetAuxvData(m_debugged_process_sp->GetID()); + if (!m_active_auxv_buffer_sp || + m_active_auxv_buffer_sp->GetByteSize() == 0) { + // Hmm, no auxv data, call that an error. + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed, no auxv data " + "retrieved", + __FUNCTION__); + m_active_auxv_buffer_sp.reset(); + return SendErrorResponse(0x11); + } + } + + // FIXME find out if/how I lock the stream here. + + StreamGDBRemote response; + bool done_with_buffer = false; + + if (auxv_offset >= m_active_auxv_buffer_sp->GetByteSize()) { + // We have nothing left to send. Mark the buffer as complete. + response.PutChar('l'); + done_with_buffer = true; + } else { + // Figure out how many bytes are available starting at the given offset. + const uint64_t bytes_remaining = + m_active_auxv_buffer_sp->GetByteSize() - auxv_offset; + + // Figure out how many bytes we're going to read. + const uint64_t bytes_to_read = + (auxv_length > bytes_remaining) ? bytes_remaining : auxv_length; + + // Mark the response type according to whether we're reading the remainder + // of the auxv data. + if (bytes_to_read >= bytes_remaining) { + // There will be nothing left to read after this + response.PutChar('l'); + done_with_buffer = true; + } else { + // There will still be bytes to read after this request. + response.PutChar('m'); + } + + // Now write the data in encoded binary form. + response.PutEscapedBytes(m_active_auxv_buffer_sp->GetBytes() + auxv_offset, + bytes_to_read); + } + + if (done_with_buffer) + m_active_auxv_buffer_sp.reset(); + + return SendPacketNoLock(response.GetString()); #else - return SendUnimplementedResponse ("not implemented on this platform"); + return SendUnimplementedResponse("not implemented on this platform"); #endif } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_QSaveRegisterState (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); - - // Move past packet name. - packet.SetFilePos (strlen ("QSaveRegisterState")); - - // Get the thread to use. - NativeThreadProtocolSP thread_sp = GetThreadFromSuffix (packet); - if (!thread_sp) - { - if (m_thread_suffix_supported) - return SendIllFormedResponse (packet, "No thread specified in QSaveRegisterState packet"); - else - return SendIllFormedResponse (packet, "No thread was is set with the Hg packet"); - } - - // Grab the register context for the thread. - NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ()); - if (!reg_context_sp) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 " failed, no register context available for the thread", __FUNCTION__, m_debugged_process_sp->GetID (), thread_sp->GetID ()); - return SendErrorResponse (0x15); - } - - // Save registers to a buffer. - DataBufferSP register_data_sp; - Error error = reg_context_sp->ReadAllRegisterValues (register_data_sp); - if (error.Fail ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " failed to save all register values: %s", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ()); - return SendErrorResponse (0x75); - } - - // Allocate a new save id. - const uint32_t save_id = GetNextSavedRegistersID (); - assert ((m_saved_registers_map.find (save_id) == m_saved_registers_map.end ()) && "GetNextRegisterSaveID() returned an existing register save id"); +GDBRemoteCommunicationServerLLGS::Handle_QSaveRegisterState( + StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + + // Move past packet name. + packet.SetFilePos(strlen("QSaveRegisterState")); + + // Get the thread to use. + NativeThreadProtocolSP thread_sp = GetThreadFromSuffix(packet); + if (!thread_sp) { + if (m_thread_suffix_supported) + return SendIllFormedResponse( + packet, "No thread specified in QSaveRegisterState packet"); + else + return SendIllFormedResponse(packet, + "No thread was is set with the Hg packet"); + } - // Save the register data buffer under the save id. - { - std::lock_guard<std::mutex> guard(m_saved_registers_mutex); - m_saved_registers_map[save_id] = register_data_sp; - } + // Grab the register context for the thread. + NativeRegisterContextSP reg_context_sp(thread_sp->GetRegisterContext()); + if (!reg_context_sp) { + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 + " failed, no register context available for the thread", + __FUNCTION__, m_debugged_process_sp->GetID(), thread_sp->GetID()); + return SendErrorResponse(0x15); + } + + // Save registers to a buffer. + DataBufferSP register_data_sp; + Error error = reg_context_sp->ReadAllRegisterValues(register_data_sp); + if (error.Fail()) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 + " failed to save all register values: %s", + __FUNCTION__, m_debugged_process_sp->GetID(), + error.AsCString()); + return SendErrorResponse(0x75); + } + + // Allocate a new save id. + const uint32_t save_id = GetNextSavedRegistersID(); + assert((m_saved_registers_map.find(save_id) == m_saved_registers_map.end()) && + "GetNextRegisterSaveID() returned an existing register save id"); + + // Save the register data buffer under the save id. + { + std::lock_guard<std::mutex> guard(m_saved_registers_mutex); + m_saved_registers_map[save_id] = register_data_sp; + } - // Write the response. - StreamGDBRemote response; - response.Printf ("%" PRIu32, save_id); - return SendPacketNoLock(response.GetData(), response.GetSize()); + // Write the response. + StreamGDBRemote response; + response.Printf("%" PRIu32, save_id); + return SendPacketNoLock(response.GetString()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_QRestoreRegisterState (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); - - // Parse out save id. - packet.SetFilePos (strlen ("QRestoreRegisterState:")); - if (packet.GetBytesLeft () < 1) - return SendIllFormedResponse (packet, "QRestoreRegisterState packet missing register save id"); - - const uint32_t save_id = packet.GetU32 (0); - if (save_id == 0) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s QRestoreRegisterState packet has malformed save id, expecting decimal uint32_t", __FUNCTION__); - return SendErrorResponse (0x76); - } +GDBRemoteCommunicationServerLLGS::Handle_QRestoreRegisterState( + StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + + // Parse out save id. + packet.SetFilePos(strlen("QRestoreRegisterState:")); + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse( + packet, "QRestoreRegisterState packet missing register save id"); + + const uint32_t save_id = packet.GetU32(0); + if (save_id == 0) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s QRestoreRegisterState " + "packet has malformed save id, expecting decimal uint32_t", + __FUNCTION__); + return SendErrorResponse(0x76); + } + + // Get the thread to use. + NativeThreadProtocolSP thread_sp = GetThreadFromSuffix(packet); + if (!thread_sp) { + if (m_thread_suffix_supported) + return SendIllFormedResponse( + packet, "No thread specified in QRestoreRegisterState packet"); + else + return SendIllFormedResponse(packet, + "No thread was is set with the Hg packet"); + } - // Get the thread to use. - NativeThreadProtocolSP thread_sp = GetThreadFromSuffix (packet); - if (!thread_sp) - { - if (m_thread_suffix_supported) - return SendIllFormedResponse (packet, "No thread specified in QRestoreRegisterState packet"); - else - return SendIllFormedResponse (packet, "No thread was is set with the Hg packet"); - } + // Grab the register context for the thread. + NativeRegisterContextSP reg_context_sp(thread_sp->GetRegisterContext()); + if (!reg_context_sp) { + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 + " failed, no register context available for the thread", + __FUNCTION__, m_debugged_process_sp->GetID(), thread_sp->GetID()); + return SendErrorResponse(0x15); + } + + // Retrieve register state buffer, then remove from the list. + DataBufferSP register_data_sp; + { + std::lock_guard<std::mutex> guard(m_saved_registers_mutex); - // Grab the register context for the thread. - NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ()); - if (!reg_context_sp) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 " failed, no register context available for the thread", __FUNCTION__, m_debugged_process_sp->GetID (), thread_sp->GetID ()); - return SendErrorResponse (0x15); + // Find the register set buffer for the given save id. + auto it = m_saved_registers_map.find(save_id); + if (it == m_saved_registers_map.end()) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 + " does not have a register set save buffer for id %" PRIu32, + __FUNCTION__, m_debugged_process_sp->GetID(), save_id); + return SendErrorResponse(0x77); } + register_data_sp = it->second; - // Retrieve register state buffer, then remove from the list. - DataBufferSP register_data_sp; - { - std::lock_guard<std::mutex> guard(m_saved_registers_mutex); - - // Find the register set buffer for the given save id. - auto it = m_saved_registers_map.find (save_id); - if (it == m_saved_registers_map.end ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " does not have a register set save buffer for id %" PRIu32, __FUNCTION__, m_debugged_process_sp->GetID (), save_id); - return SendErrorResponse (0x77); - } - register_data_sp = it->second; - - // Remove it from the map. - m_saved_registers_map.erase (it); - } + // Remove it from the map. + m_saved_registers_map.erase(it); + } - Error error = reg_context_sp->WriteAllRegisterValues (register_data_sp); - if (error.Fail ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " failed to restore all register values: %s", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ()); - return SendErrorResponse (0x77); - } + Error error = reg_context_sp->WriteAllRegisterValues(register_data_sp); + if (error.Fail()) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 + " failed to restore all register values: %s", + __FUNCTION__, m_debugged_process_sp->GetID(), + error.AsCString()); + return SendErrorResponse(0x77); + } - return SendOKResponse(); + return SendOKResponse(); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_vAttach (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - - // Consume the ';' after vAttach. - packet.SetFilePos (strlen ("vAttach")); - if (!packet.GetBytesLeft () || packet.GetChar () != ';') - return SendIllFormedResponse (packet, "vAttach missing expected ';'"); - - // Grab the PID to which we will attach (assume hex encoding). - lldb::pid_t pid = packet.GetU32 (LLDB_INVALID_PROCESS_ID, 16); - if (pid == LLDB_INVALID_PROCESS_ID) - return SendIllFormedResponse (packet, "vAttach failed to parse the process id"); - - // Attempt to attach. +GDBRemoteCommunicationServerLLGS::Handle_vAttach( + StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + // Consume the ';' after vAttach. + packet.SetFilePos(strlen("vAttach")); + if (!packet.GetBytesLeft() || packet.GetChar() != ';') + return SendIllFormedResponse(packet, "vAttach missing expected ';'"); + + // Grab the PID to which we will attach (assume hex encoding). + lldb::pid_t pid = packet.GetU32(LLDB_INVALID_PROCESS_ID, 16); + if (pid == LLDB_INVALID_PROCESS_ID) + return SendIllFormedResponse(packet, + "vAttach failed to parse the process id"); + + // Attempt to attach. + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s attempting to attach to " + "pid %" PRIu64, + __FUNCTION__, pid); + + Error error = AttachToProcess(pid); + + if (error.Fail()) { if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s attempting to attach to pid %" PRIu64, __FUNCTION__, pid); + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed to attach to " + "pid %" PRIu64 ": %s\n", + __FUNCTION__, pid, error.AsCString()); + return SendErrorResponse(0x01); + } - Error error = AttachToProcess (pid); - - if (error.Fail ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to attach to pid %" PRIu64 ": %s\n", __FUNCTION__, pid, error.AsCString()); - return SendErrorResponse (0x01); - } - - // Notify we attached by sending a stop packet. - return SendStopReasonForState (m_debugged_process_sp->GetState ()); + // Notify we attached by sending a stop packet. + return SendStopReasonForState(m_debugged_process_sp->GetState()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_D (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS)); +GDBRemoteCommunicationServerLLGS::Handle_D(StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - StopSTDIOForwarding(); + StopSTDIOForwarding(); - // Fail if we don't have a current process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__); - return SendErrorResponse (0x15); - } - - lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; - - // Consume the ';' after D. - packet.SetFilePos (1); - if (packet.GetBytesLeft ()) - { - if (packet.GetChar () != ';') - return SendIllFormedResponse (packet, "D missing expected ';'"); - - // Grab the PID from which we will detach (assume hex encoding). - pid = packet.GetU32 (LLDB_INVALID_PROCESS_ID, 16); - if (pid == LLDB_INVALID_PROCESS_ID) - return SendIllFormedResponse (packet, "D failed to parse the process id"); - } + // Fail if we don't have a current process. + if (!m_debugged_process_sp || + (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s failed, no process available", + __FUNCTION__); + return SendErrorResponse(0x15); + } + + lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; + + // Consume the ';' after D. + packet.SetFilePos(1); + if (packet.GetBytesLeft()) { + if (packet.GetChar() != ';') + return SendIllFormedResponse(packet, "D missing expected ';'"); + + // Grab the PID from which we will detach (assume hex encoding). + pid = packet.GetU32(LLDB_INVALID_PROCESS_ID, 16); + if (pid == LLDB_INVALID_PROCESS_ID) + return SendIllFormedResponse(packet, "D failed to parse the process id"); + } - if (pid != LLDB_INVALID_PROCESS_ID && - m_debugged_process_sp->GetID () != pid) - { - return SendIllFormedResponse (packet, "Invalid pid"); - } + if (pid != LLDB_INVALID_PROCESS_ID && m_debugged_process_sp->GetID() != pid) { + return SendIllFormedResponse(packet, "Invalid pid"); + } - const Error error = m_debugged_process_sp->Detach (); - if (error.Fail ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to detach from pid %" PRIu64 ": %s\n", - __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ()); - return SendErrorResponse (0x01); - } + const Error error = m_debugged_process_sp->Detach(); + if (error.Fail()) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed to detach from " + "pid %" PRIu64 ": %s\n", + __FUNCTION__, m_debugged_process_sp->GetID(), + error.AsCString()); + return SendErrorResponse(0x01); + } - return SendOKResponse (); + return SendOKResponse(); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_qThreadStopInfo (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); - - packet.SetFilePos (strlen("qThreadStopInfo")); - const lldb::tid_t tid = packet.GetHexMaxU32 (false, LLDB_INVALID_THREAD_ID); - if (tid == LLDB_INVALID_THREAD_ID) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, could not parse thread id from request \"%s\"", __FUNCTION__, packet.GetStringRef ().c_str ()); - return SendErrorResponse (0x15); - } - return SendStopReplyPacketForThread (tid); +GDBRemoteCommunicationServerLLGS::Handle_qThreadStopInfo( + StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + + packet.SetFilePos(strlen("qThreadStopInfo")); + const lldb::tid_t tid = packet.GetHexMaxU32(false, LLDB_INVALID_THREAD_ID); + if (tid == LLDB_INVALID_THREAD_ID) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed, could not " + "parse thread id from request \"%s\"", + __FUNCTION__, packet.GetStringRef().c_str()); + return SendErrorResponse(0x15); + } + return SendStopReplyPacketForThread(tid); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_jThreadsInfo (StringExtractorGDBRemote &) -{ - Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); - - // Ensure we have a debugged process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - return SendErrorResponse (50); - - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s preparing packet for pid %" PRIu64, +GDBRemoteCommunicationServerLLGS::Handle_jThreadsInfo( + StringExtractorGDBRemote &) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); + + // Ensure we have a debugged process. + if (!m_debugged_process_sp || + (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) + return SendErrorResponse(50); + + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s preparing packet for pid " + "%" PRIu64, __FUNCTION__, m_debugged_process_sp->GetID()); + StreamString response; + const bool threads_with_valid_stop_info_only = false; + JSONArray::SP threads_array_sp = GetJSONThreadsInfo( + *m_debugged_process_sp, threads_with_valid_stop_info_only); + if (!threads_array_sp) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed to prepare a " + "packet for pid %" PRIu64, + __FUNCTION__, m_debugged_process_sp->GetID()); + return SendErrorResponse(52); + } - StreamString response; - const bool threads_with_valid_stop_info_only = false; - JSONArray::SP threads_array_sp = GetJSONThreadsInfo(*m_debugged_process_sp, - threads_with_valid_stop_info_only); - if (! threads_array_sp) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to prepare a packet for pid %" PRIu64, - __FUNCTION__, m_debugged_process_sp->GetID()); - return SendErrorResponse(52); - } - - threads_array_sp->Write(response); - StreamGDBRemote escaped_response; - escaped_response.PutEscapedBytes(response.GetData(), response.GetSize()); - return SendPacketNoLock (escaped_response.GetData(), escaped_response.GetSize()); + threads_array_sp->Write(response); + StreamGDBRemote escaped_response; + escaped_response.PutEscapedBytes(response.GetData(), response.GetSize()); + return SendPacketNoLock(escaped_response.GetString()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_qWatchpointSupportInfo (StringExtractorGDBRemote &packet) -{ - // Fail if we don't have a current process. - if (!m_debugged_process_sp || - m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID) - return SendErrorResponse (68); - - packet.SetFilePos(strlen("qWatchpointSupportInfo")); - if (packet.GetBytesLeft() == 0) - return SendOKResponse(); - if (packet.GetChar() != ':') - return SendErrorResponse(67); +GDBRemoteCommunicationServerLLGS::Handle_qWatchpointSupportInfo( + StringExtractorGDBRemote &packet) { + // Fail if we don't have a current process. + if (!m_debugged_process_sp || + m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID) + return SendErrorResponse(68); + + packet.SetFilePos(strlen("qWatchpointSupportInfo")); + if (packet.GetBytesLeft() == 0) + return SendOKResponse(); + if (packet.GetChar() != ':') + return SendErrorResponse(67); - uint32_t num = m_debugged_process_sp->GetMaxWatchpoints(); - StreamGDBRemote response; - response.Printf ("num:%d;", num); - return SendPacketNoLock(response.GetData(), response.GetSize()); + uint32_t num = m_debugged_process_sp->GetMaxWatchpoints(); + StreamGDBRemote response; + response.Printf("num:%d;", num); + return SendPacketNoLock(response.GetString()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_qFileLoadAddress (StringExtractorGDBRemote &packet) -{ - // Fail if we don't have a current process. - if (!m_debugged_process_sp || - m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID) - return SendErrorResponse(67); +GDBRemoteCommunicationServerLLGS::Handle_qFileLoadAddress( + StringExtractorGDBRemote &packet) { + // Fail if we don't have a current process. + if (!m_debugged_process_sp || + m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID) + return SendErrorResponse(67); - packet.SetFilePos(strlen("qFileLoadAddress:")); - if (packet.GetBytesLeft() == 0) - return SendErrorResponse(68); + packet.SetFilePos(strlen("qFileLoadAddress:")); + if (packet.GetBytesLeft() == 0) + return SendErrorResponse(68); - std::string file_name; - packet.GetHexByteString(file_name); + std::string file_name; + packet.GetHexByteString(file_name); - lldb::addr_t file_load_address = LLDB_INVALID_ADDRESS; - Error error = m_debugged_process_sp->GetFileLoadAddress(file_name, file_load_address); - if (error.Fail()) - return SendErrorResponse(69); + lldb::addr_t file_load_address = LLDB_INVALID_ADDRESS; + Error error = + m_debugged_process_sp->GetFileLoadAddress(file_name, file_load_address); + if (error.Fail()) + return SendErrorResponse(69); - if (file_load_address == LLDB_INVALID_ADDRESS) - return SendErrorResponse(1); // File not loaded + if (file_load_address == LLDB_INVALID_ADDRESS) + return SendErrorResponse(1); // File not loaded - StreamGDBRemote response; - response.PutHex64(file_load_address); - return SendPacketNoLock(response.GetData(), response.GetSize()); -} - -void -GDBRemoteCommunicationServerLLGS::MaybeCloseInferiorTerminalConnection () -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - - // Tell the stdio connection to shut down. - if (m_stdio_communication.IsConnected()) - { - auto connection = m_stdio_communication.GetConnection(); - if (connection) - { - Error error; - connection->Disconnect (&error); - - if (error.Success ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s disconnect process terminal stdio - SUCCESS", __FUNCTION__); - } - else - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s disconnect process terminal stdio - FAIL: %s", __FUNCTION__, error.AsCString ()); - } - } - } + StreamGDBRemote response; + response.PutHex64(file_load_address); + return SendPacketNoLock(response.GetString()); } +void GDBRemoteCommunicationServerLLGS::MaybeCloseInferiorTerminalConnection() { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); -NativeThreadProtocolSP -GDBRemoteCommunicationServerLLGS::GetThreadFromSuffix (StringExtractorGDBRemote &packet) -{ - NativeThreadProtocolSP thread_sp; + // Tell the stdio connection to shut down. + if (m_stdio_communication.IsConnected()) { + auto connection = m_stdio_communication.GetConnection(); + if (connection) { + Error error; + connection->Disconnect(&error); - // We have no thread if we don't have a process. - if (!m_debugged_process_sp || m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID) - return thread_sp; - - // If the client hasn't asked for thread suffix support, there will not be a thread suffix. - // Use the current thread in that case. - if (!m_thread_suffix_supported) - { - const lldb::tid_t current_tid = GetCurrentThreadID (); - if (current_tid == LLDB_INVALID_THREAD_ID) - return thread_sp; - else if (current_tid == 0) - { - // Pick a thread. - return m_debugged_process_sp->GetThreadAtIndex (0); - } - else - return m_debugged_process_sp->GetThreadByID (current_tid); + if (error.Success()) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s disconnect process " + "terminal stdio - SUCCESS", + __FUNCTION__); + } else { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s disconnect process " + "terminal stdio - FAIL: %s", + __FUNCTION__, error.AsCString()); + } } + } +} - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); +NativeThreadProtocolSP GDBRemoteCommunicationServerLLGS::GetThreadFromSuffix( + StringExtractorGDBRemote &packet) { + NativeThreadProtocolSP thread_sp; - // Parse out the ';'. - if (packet.GetBytesLeft () < 1 || packet.GetChar () != ';') - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s gdb-remote parse error: expected ';' prior to start of thread suffix: packet contents = '%s'", __FUNCTION__, packet.GetStringRef ().c_str ()); - return thread_sp; - } + // We have no thread if we don't have a process. + if (!m_debugged_process_sp || + m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID) + return thread_sp; - if (!packet.GetBytesLeft ()) - return thread_sp; + // If the client hasn't asked for thread suffix support, there will not be a + // thread suffix. + // Use the current thread in that case. + if (!m_thread_suffix_supported) { + const lldb::tid_t current_tid = GetCurrentThreadID(); + if (current_tid == LLDB_INVALID_THREAD_ID) + return thread_sp; + else if (current_tid == 0) { + // Pick a thread. + return m_debugged_process_sp->GetThreadAtIndex(0); + } else + return m_debugged_process_sp->GetThreadByID(current_tid); + } + + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + + // Parse out the ';'. + if (packet.GetBytesLeft() < 1 || packet.GetChar() != ';') { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s gdb-remote parse " + "error: expected ';' prior to start of thread suffix: packet " + "contents = '%s'", + __FUNCTION__, packet.GetStringRef().c_str()); + return thread_sp; + } - // Parse out thread: portion. - if (strncmp (packet.Peek (), "thread:", strlen("thread:")) != 0) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s gdb-remote parse error: expected 'thread:' but not found, packet contents = '%s'", __FUNCTION__, packet.GetStringRef ().c_str ()); - return thread_sp; - } - packet.SetFilePos (packet.GetFilePos () + strlen("thread:")); - const lldb::tid_t tid = packet.GetHexMaxU64(false, 0); - if (tid != 0) - return m_debugged_process_sp->GetThreadByID (tid); + if (!packet.GetBytesLeft()) + return thread_sp; + // Parse out thread: portion. + if (strncmp(packet.Peek(), "thread:", strlen("thread:")) != 0) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s gdb-remote parse " + "error: expected 'thread:' but not found, packet contents = " + "'%s'", + __FUNCTION__, packet.GetStringRef().c_str()); return thread_sp; + } + packet.SetFilePos(packet.GetFilePos() + strlen("thread:")); + const lldb::tid_t tid = packet.GetHexMaxU64(false, 0); + if (tid != 0) + return m_debugged_process_sp->GetThreadByID(tid); + + return thread_sp; } -lldb::tid_t -GDBRemoteCommunicationServerLLGS::GetCurrentThreadID () const -{ - if (m_current_tid == 0 || m_current_tid == LLDB_INVALID_THREAD_ID) - { - // Use whatever the debug process says is the current thread id - // since the protocol either didn't specify or specified we want - // any/all threads marked as the current thread. - if (!m_debugged_process_sp) - return LLDB_INVALID_THREAD_ID; - return m_debugged_process_sp->GetCurrentThreadID (); - } - // Use the specific current thread id set by the gdb remote protocol. - return m_current_tid; +lldb::tid_t GDBRemoteCommunicationServerLLGS::GetCurrentThreadID() const { + if (m_current_tid == 0 || m_current_tid == LLDB_INVALID_THREAD_ID) { + // Use whatever the debug process says is the current thread id + // since the protocol either didn't specify or specified we want + // any/all threads marked as the current thread. + if (!m_debugged_process_sp) + return LLDB_INVALID_THREAD_ID; + return m_debugged_process_sp->GetCurrentThreadID(); + } + // Use the specific current thread id set by the gdb remote protocol. + return m_current_tid; } -uint32_t -GDBRemoteCommunicationServerLLGS::GetNextSavedRegistersID () -{ - std::lock_guard<std::mutex> guard(m_saved_registers_mutex); - return m_next_saved_registers_id++; +uint32_t GDBRemoteCommunicationServerLLGS::GetNextSavedRegistersID() { + std::lock_guard<std::mutex> guard(m_saved_registers_mutex); + return m_next_saved_registers_id++; } -void -GDBRemoteCommunicationServerLLGS::ClearProcessSpecificData () -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|GDBR_LOG_PROCESS)); - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s()", __FUNCTION__); +void GDBRemoteCommunicationServerLLGS::ClearProcessSpecificData() { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | GDBR_LOG_PROCESS)); + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s()", __FUNCTION__); - // Clear any auxv cached data. - // *BSD impls should be able to do this too. +// Clear any auxv cached data. +// *BSD impls should be able to do this too. #if defined(__linux__) - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s clearing auxv buffer (previously %s)", - __FUNCTION__, - m_active_auxv_buffer_sp ? "was set" : "was not set"); - m_active_auxv_buffer_sp.reset (); + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s clearing auxv buffer " + "(previously %s)", + __FUNCTION__, + m_active_auxv_buffer_sp ? "was set" : "was not set"); + m_active_auxv_buffer_sp.reset(); #endif } FileSpec -GDBRemoteCommunicationServerLLGS::FindModuleFile(const std::string& module_path, - const ArchSpec& arch) -{ - if (m_debugged_process_sp) - { - FileSpec file_spec; - if (m_debugged_process_sp->GetLoadedModuleFileSpec(module_path.c_str(), file_spec).Success()) - { - if (file_spec.Exists()) - return file_spec; - } - } - - return GDBRemoteCommunicationServerCommon::FindModuleFile(module_path, arch); +GDBRemoteCommunicationServerLLGS::FindModuleFile(const std::string &module_path, + const ArchSpec &arch) { + if (m_debugged_process_sp) { + FileSpec file_spec; + if (m_debugged_process_sp + ->GetLoadedModuleFileSpec(module_path.c_str(), file_spec) + .Success()) { + if (file_spec.Exists()) + return file_spec; + } + } + + return GDBRemoteCommunicationServerCommon::FindModuleFile(module_path, arch); } diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h index caf6eb3..fa52cda 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h @@ -16,10 +16,10 @@ #include <unordered_map> // Other libraries and framework includes -#include "lldb/lldb-private-forward.h" #include "lldb/Core/Communication.h" -#include "lldb/Host/common/NativeProcessProtocol.h" #include "lldb/Host/MainLoop.h" +#include "lldb/Host/common/NativeProcessProtocol.h" +#include "lldb/lldb-private-forward.h" // Project includes #include "GDBRemoteCommunicationServerCommon.h" @@ -32,282 +32,220 @@ namespace process_gdb_remote { class ProcessGDBRemote; -class GDBRemoteCommunicationServerLLGS : - public GDBRemoteCommunicationServerCommon, - public NativeProcessProtocol::NativeDelegate -{ +class GDBRemoteCommunicationServerLLGS + : public GDBRemoteCommunicationServerCommon, + public NativeProcessProtocol::NativeDelegate { public: - //------------------------------------------------------------------ - // Constructors and Destructors - //------------------------------------------------------------------ - GDBRemoteCommunicationServerLLGS(MainLoop &mainloop); - - //------------------------------------------------------------------ - /// Specify the program to launch and its arguments. - /// - /// @param[in] args - /// The command line to launch. - /// - /// @param[in] argc - /// The number of elements in the args array of cstring pointers. - /// - /// @return - /// An Error object indicating the success or failure of making - /// the setting. - //------------------------------------------------------------------ - Error - SetLaunchArguments (const char *const args[], int argc); - - //------------------------------------------------------------------ - /// Specify the launch flags for the process. - /// - /// @param[in] launch_flags - /// The launch flags to use when launching this process. - /// - /// @return - /// An Error object indicating the success or failure of making - /// the setting. - //------------------------------------------------------------------ - Error - SetLaunchFlags (unsigned int launch_flags); - - //------------------------------------------------------------------ - /// Launch a process with the current launch settings. - /// - /// This method supports running an lldb-gdbserver or similar - /// server in a situation where the startup code has been provided - /// with all the information for a child process to be launched. - /// - /// @return - /// An Error object indicating the success or failure of the - /// launch. - //------------------------------------------------------------------ - Error - LaunchProcess () override; - - //------------------------------------------------------------------ - /// Attach to a process. - /// - /// This method supports attaching llgs to a process accessible via the - /// configured Platform. - /// - /// @return - /// An Error object indicating the success or failure of the - /// attach operation. - //------------------------------------------------------------------ - Error - AttachToProcess (lldb::pid_t pid); - - //------------------------------------------------------------------ - // NativeProcessProtocol::NativeDelegate overrides - //------------------------------------------------------------------ - void - InitializeDelegate (NativeProcessProtocol *process) override; - - void - ProcessStateChanged (NativeProcessProtocol *process, lldb::StateType state) override; - - void - DidExec (NativeProcessProtocol *process) override; - - Error - InitializeConnection (std::unique_ptr<Connection> &&connection); + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + GDBRemoteCommunicationServerLLGS(MainLoop &mainloop); + + //------------------------------------------------------------------ + /// Specify the program to launch and its arguments. + /// + /// @param[in] args + /// The command line to launch. + /// + /// @param[in] argc + /// The number of elements in the args array of cstring pointers. + /// + /// @return + /// An Error object indicating the success or failure of making + /// the setting. + //------------------------------------------------------------------ + Error SetLaunchArguments(const char *const args[], int argc); + + //------------------------------------------------------------------ + /// Specify the launch flags for the process. + /// + /// @param[in] launch_flags + /// The launch flags to use when launching this process. + /// + /// @return + /// An Error object indicating the success or failure of making + /// the setting. + //------------------------------------------------------------------ + Error SetLaunchFlags(unsigned int launch_flags); + + //------------------------------------------------------------------ + /// Launch a process with the current launch settings. + /// + /// This method supports running an lldb-gdbserver or similar + /// server in a situation where the startup code has been provided + /// with all the information for a child process to be launched. + /// + /// @return + /// An Error object indicating the success or failure of the + /// launch. + //------------------------------------------------------------------ + Error LaunchProcess() override; + + //------------------------------------------------------------------ + /// Attach to a process. + /// + /// This method supports attaching llgs to a process accessible via the + /// configured Platform. + /// + /// @return + /// An Error object indicating the success or failure of the + /// attach operation. + //------------------------------------------------------------------ + Error AttachToProcess(lldb::pid_t pid); + + //------------------------------------------------------------------ + // NativeProcessProtocol::NativeDelegate overrides + //------------------------------------------------------------------ + void InitializeDelegate(NativeProcessProtocol *process) override; + + void ProcessStateChanged(NativeProcessProtocol *process, + lldb::StateType state) override; + + void DidExec(NativeProcessProtocol *process) override; + + Error InitializeConnection(std::unique_ptr<Connection> &&connection); protected: - MainLoop &m_mainloop; - MainLoop::ReadHandleUP m_network_handle_up; - lldb::tid_t m_current_tid; - lldb::tid_t m_continue_tid; - std::recursive_mutex m_debugged_process_mutex; - NativeProcessProtocolSP m_debugged_process_sp; + MainLoop &m_mainloop; + MainLoop::ReadHandleUP m_network_handle_up; + lldb::tid_t m_current_tid; + lldb::tid_t m_continue_tid; + std::recursive_mutex m_debugged_process_mutex; + NativeProcessProtocolSP m_debugged_process_sp; - Communication m_stdio_communication; - MainLoop::ReadHandleUP m_stdio_handle_up; + Communication m_stdio_communication; + MainLoop::ReadHandleUP m_stdio_handle_up; - lldb::StateType m_inferior_prev_state; - lldb::DataBufferSP m_active_auxv_buffer_sp; - std::mutex m_saved_registers_mutex; - std::unordered_map<uint32_t, lldb::DataBufferSP> m_saved_registers_map; - uint32_t m_next_saved_registers_id; - bool m_handshake_completed : 1; + lldb::StateType m_inferior_prev_state; + lldb::DataBufferSP m_active_auxv_buffer_sp; + std::mutex m_saved_registers_mutex; + std::unordered_map<uint32_t, lldb::DataBufferSP> m_saved_registers_map; + uint32_t m_next_saved_registers_id; + bool m_handshake_completed : 1; - PacketResult - SendONotification (const char *buffer, uint32_t len); + PacketResult SendONotification(const char *buffer, uint32_t len); - PacketResult - SendWResponse (NativeProcessProtocol *process); + PacketResult SendWResponse(NativeProcessProtocol *process); - PacketResult - SendStopReplyPacketForThread (lldb::tid_t tid); + PacketResult SendStopReplyPacketForThread(lldb::tid_t tid); - PacketResult - SendStopReasonForState (lldb::StateType process_state); + PacketResult SendStopReasonForState(lldb::StateType process_state); - PacketResult - Handle_k (StringExtractorGDBRemote &packet); + PacketResult Handle_k(StringExtractorGDBRemote &packet); - PacketResult - Handle_qProcessInfo (StringExtractorGDBRemote &packet); + PacketResult Handle_qProcessInfo(StringExtractorGDBRemote &packet); - PacketResult - Handle_qC (StringExtractorGDBRemote &packet); + PacketResult Handle_qC(StringExtractorGDBRemote &packet); - PacketResult - Handle_QSetDisableASLR (StringExtractorGDBRemote &packet); + PacketResult Handle_QSetDisableASLR(StringExtractorGDBRemote &packet); - PacketResult - Handle_QSetWorkingDir (StringExtractorGDBRemote &packet); + PacketResult Handle_QSetWorkingDir(StringExtractorGDBRemote &packet); - PacketResult - Handle_qGetWorkingDir (StringExtractorGDBRemote &packet); + PacketResult Handle_qGetWorkingDir(StringExtractorGDBRemote &packet); - PacketResult - Handle_C (StringExtractorGDBRemote &packet); + PacketResult Handle_C(StringExtractorGDBRemote &packet); - PacketResult - Handle_c (StringExtractorGDBRemote &packet); + PacketResult Handle_c(StringExtractorGDBRemote &packet); - PacketResult - Handle_vCont (StringExtractorGDBRemote &packet); + PacketResult Handle_vCont(StringExtractorGDBRemote &packet); - PacketResult - Handle_vCont_actions (StringExtractorGDBRemote &packet); + PacketResult Handle_vCont_actions(StringExtractorGDBRemote &packet); - PacketResult - Handle_stop_reason (StringExtractorGDBRemote &packet); + PacketResult Handle_stop_reason(StringExtractorGDBRemote &packet); - PacketResult - Handle_qRegisterInfo (StringExtractorGDBRemote &packet); + PacketResult Handle_qRegisterInfo(StringExtractorGDBRemote &packet); - PacketResult - Handle_qfThreadInfo (StringExtractorGDBRemote &packet); + PacketResult Handle_qfThreadInfo(StringExtractorGDBRemote &packet); - PacketResult - Handle_qsThreadInfo (StringExtractorGDBRemote &packet); + PacketResult Handle_qsThreadInfo(StringExtractorGDBRemote &packet); - PacketResult - Handle_p (StringExtractorGDBRemote &packet); + PacketResult Handle_p(StringExtractorGDBRemote &packet); - PacketResult - Handle_P (StringExtractorGDBRemote &packet); + PacketResult Handle_P(StringExtractorGDBRemote &packet); - PacketResult - Handle_H (StringExtractorGDBRemote &packet); + PacketResult Handle_H(StringExtractorGDBRemote &packet); - PacketResult - Handle_I (StringExtractorGDBRemote &packet); + PacketResult Handle_I(StringExtractorGDBRemote &packet); - PacketResult - Handle_interrupt (StringExtractorGDBRemote &packet); + PacketResult Handle_interrupt(StringExtractorGDBRemote &packet); - // Handles $m and $x packets. - PacketResult - Handle_memory_read (StringExtractorGDBRemote &packet); + // Handles $m and $x packets. + PacketResult Handle_memory_read(StringExtractorGDBRemote &packet); - PacketResult - Handle_M (StringExtractorGDBRemote &packet); + PacketResult Handle_M(StringExtractorGDBRemote &packet); - PacketResult - Handle_qMemoryRegionInfoSupported (StringExtractorGDBRemote &packet); + PacketResult + Handle_qMemoryRegionInfoSupported(StringExtractorGDBRemote &packet); - PacketResult - Handle_qMemoryRegionInfo (StringExtractorGDBRemote &packet); + PacketResult Handle_qMemoryRegionInfo(StringExtractorGDBRemote &packet); - PacketResult - Handle_Z (StringExtractorGDBRemote &packet); + PacketResult Handle_Z(StringExtractorGDBRemote &packet); - PacketResult - Handle_z (StringExtractorGDBRemote &packet); + PacketResult Handle_z(StringExtractorGDBRemote &packet); - PacketResult - Handle_s (StringExtractorGDBRemote &packet); + PacketResult Handle_s(StringExtractorGDBRemote &packet); - PacketResult - Handle_qXfer_auxv_read (StringExtractorGDBRemote &packet); + PacketResult Handle_qXfer_auxv_read(StringExtractorGDBRemote &packet); - PacketResult - Handle_QSaveRegisterState (StringExtractorGDBRemote &packet); + PacketResult Handle_QSaveRegisterState(StringExtractorGDBRemote &packet); - PacketResult - Handle_QRestoreRegisterState (StringExtractorGDBRemote &packet); + PacketResult Handle_QRestoreRegisterState(StringExtractorGDBRemote &packet); - PacketResult - Handle_vAttach (StringExtractorGDBRemote &packet); + PacketResult Handle_vAttach(StringExtractorGDBRemote &packet); - PacketResult - Handle_D (StringExtractorGDBRemote &packet); + PacketResult Handle_D(StringExtractorGDBRemote &packet); - PacketResult - Handle_qThreadStopInfo (StringExtractorGDBRemote &packet); + PacketResult Handle_qThreadStopInfo(StringExtractorGDBRemote &packet); - PacketResult - Handle_jThreadsInfo (StringExtractorGDBRemote &packet); + PacketResult Handle_jThreadsInfo(StringExtractorGDBRemote &packet); - PacketResult - Handle_qWatchpointSupportInfo (StringExtractorGDBRemote &packet); + PacketResult Handle_qWatchpointSupportInfo(StringExtractorGDBRemote &packet); - PacketResult - Handle_qFileLoadAddress (StringExtractorGDBRemote &packet); + PacketResult Handle_qFileLoadAddress(StringExtractorGDBRemote &packet); - void - SetCurrentThreadID (lldb::tid_t tid); + void SetCurrentThreadID(lldb::tid_t tid); - lldb::tid_t - GetCurrentThreadID () const; + lldb::tid_t GetCurrentThreadID() const; - void - SetContinueThreadID (lldb::tid_t tid); + void SetContinueThreadID(lldb::tid_t tid); - lldb::tid_t - GetContinueThreadID () const { return m_continue_tid; } + lldb::tid_t GetContinueThreadID() const { return m_continue_tid; } - Error - SetSTDIOFileDescriptor (int fd); + Error SetSTDIOFileDescriptor(int fd); - FileSpec - FindModuleFile (const std::string& module_path, const ArchSpec& arch) override; + FileSpec FindModuleFile(const std::string &module_path, + const ArchSpec &arch) override; private: - void - HandleInferiorState_Exited (NativeProcessProtocol *process); + void HandleInferiorState_Exited(NativeProcessProtocol *process); - void - HandleInferiorState_Stopped (NativeProcessProtocol *process); + void HandleInferiorState_Stopped(NativeProcessProtocol *process); - NativeThreadProtocolSP - GetThreadFromSuffix (StringExtractorGDBRemote &packet); + NativeThreadProtocolSP GetThreadFromSuffix(StringExtractorGDBRemote &packet); - uint32_t - GetNextSavedRegistersID (); + uint32_t GetNextSavedRegistersID(); - void - MaybeCloseInferiorTerminalConnection (); + void MaybeCloseInferiorTerminalConnection(); - void - ClearProcessSpecificData (); + void ClearProcessSpecificData(); - void - RegisterPacketHandlers (); + void RegisterPacketHandlers(); - void - DataAvailableCallback (); + void DataAvailableCallback(); - void - SendProcessOutput (); + void SendProcessOutput(); - void - StartSTDIOForwarding(); + void StartSTDIOForwarding(); - void - StopSTDIOForwarding(); + void StopSTDIOForwarding(); - //------------------------------------------------------------------ - // For GDBRemoteCommunicationServerLLGS only - //------------------------------------------------------------------ - DISALLOW_COPY_AND_ASSIGN (GDBRemoteCommunicationServerLLGS); + //------------------------------------------------------------------ + // For GDBRemoteCommunicationServerLLGS only + //------------------------------------------------------------------ + DISALLOW_COPY_AND_ASSIGN(GDBRemoteCommunicationServerLLGS); }; } // namespace process_gdb_remote } // namespace lldb_private -#endif // liblldb_GDBRemoteCommunicationServerLLGS_h_ +#endif // liblldb_GDBRemoteCommunicationServerLLGS_h_ diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp index d6900c2..1106974 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp @@ -13,8 +13,8 @@ // C Includes // C++ Includes -#include <cstring> #include <chrono> +#include <cstring> #include <mutex> #include <sstream> @@ -47,549 +47,525 @@ using namespace lldb_private::process_gdb_remote; //---------------------------------------------------------------------- // GDBRemoteCommunicationServerPlatform constructor //---------------------------------------------------------------------- -GDBRemoteCommunicationServerPlatform::GDBRemoteCommunicationServerPlatform(const Socket::SocketProtocol socket_protocol, - const char *socket_scheme) - : GDBRemoteCommunicationServerCommon("gdb-remote.server", "gdb-remote.server.rx_packet"), - m_socket_protocol(socket_protocol), - m_socket_scheme(socket_scheme), - m_spawned_pids_mutex(), - m_port_map(), - m_port_offset(0) -{ - m_pending_gdb_server.pid = LLDB_INVALID_PROCESS_ID; - m_pending_gdb_server.port = 0; - - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qC, - &GDBRemoteCommunicationServerPlatform::Handle_qC); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir, - &GDBRemoteCommunicationServerPlatform::Handle_qGetWorkingDir); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qLaunchGDBServer, - &GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qQueryGDBServer, - &GDBRemoteCommunicationServerPlatform::Handle_qQueryGDBServer); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qKillSpawnedProcess, - &GDBRemoteCommunicationServerPlatform::Handle_qKillSpawnedProcess); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qProcessInfo, - &GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir, - &GDBRemoteCommunicationServerPlatform::Handle_QSetWorkingDir); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_jSignalsInfo, - &GDBRemoteCommunicationServerPlatform::Handle_jSignalsInfo); - - RegisterPacketHandler(StringExtractorGDBRemote::eServerPacketType_interrupt, - [this](StringExtractorGDBRemote packet, Error &error, bool &interrupt, bool &quit) { - error.SetErrorString("interrupt received"); - interrupt = true; - return PacketResult::Success; - }); +GDBRemoteCommunicationServerPlatform::GDBRemoteCommunicationServerPlatform( + const Socket::SocketProtocol socket_protocol, const char *socket_scheme) + : GDBRemoteCommunicationServerCommon("gdb-remote.server", + "gdb-remote.server.rx_packet"), + m_socket_protocol(socket_protocol), m_socket_scheme(socket_scheme), + m_spawned_pids_mutex(), m_port_map(), m_port_offset(0) { + m_pending_gdb_server.pid = LLDB_INVALID_PROCESS_ID; + m_pending_gdb_server.port = 0; + + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qC, + &GDBRemoteCommunicationServerPlatform::Handle_qC); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir, + &GDBRemoteCommunicationServerPlatform::Handle_qGetWorkingDir); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qLaunchGDBServer, + &GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qQueryGDBServer, + &GDBRemoteCommunicationServerPlatform::Handle_qQueryGDBServer); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qKillSpawnedProcess, + &GDBRemoteCommunicationServerPlatform::Handle_qKillSpawnedProcess); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qProcessInfo, + &GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir, + &GDBRemoteCommunicationServerPlatform::Handle_QSetWorkingDir); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_jSignalsInfo, + &GDBRemoteCommunicationServerPlatform::Handle_jSignalsInfo); + + RegisterPacketHandler(StringExtractorGDBRemote::eServerPacketType_interrupt, + [this](StringExtractorGDBRemote packet, Error &error, + bool &interrupt, bool &quit) { + error.SetErrorString("interrupt received"); + interrupt = true; + return PacketResult::Success; + }); } //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- -GDBRemoteCommunicationServerPlatform::~GDBRemoteCommunicationServerPlatform() -{ -} - -Error -GDBRemoteCommunicationServerPlatform::LaunchGDBServer(const lldb_private::Args& args, - std::string hostname, - lldb::pid_t& pid, - uint16_t& port, - std::string& socket_name) -{ - if (port == UINT16_MAX) - port = GetNextAvailablePort(); - - // Spawn a new thread to accept the port that gets bound after - // binding to port 0 (zero). - - // ignore the hostname send from the remote end, just use the ip address - // that we're currently communicating with as the hostname - - // Spawn a debugserver and try to get the port it listens to. - ProcessLaunchInfo debugserver_launch_info; - if (hostname.empty()) - hostname = "127.0.0.1"; - - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); - if (log) - log->Printf("Launching debugserver with: %s:%u...", hostname.c_str(), port); - - // Do not run in a new session so that it can not linger after the - // platform closes. - debugserver_launch_info.SetLaunchInSeparateProcessGroup(false); - debugserver_launch_info.SetMonitorProcessCallback( - std::bind(&GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped, this, std::placeholders::_1), false); - - std::string platform_scheme; - std::string platform_ip; - int platform_port; - std::string platform_path; - bool ok = UriParser::Parse(GetConnection()->GetURI().c_str(), platform_scheme, platform_ip, platform_port, platform_path); - UNUSED_IF_ASSERT_DISABLED(ok); - assert(ok); - - std::ostringstream url; - // debugserver does not accept the URL scheme prefix. +GDBRemoteCommunicationServerPlatform::~GDBRemoteCommunicationServerPlatform() {} + +Error GDBRemoteCommunicationServerPlatform::LaunchGDBServer( + const lldb_private::Args &args, std::string hostname, lldb::pid_t &pid, + uint16_t &port, std::string &socket_name) { + if (port == UINT16_MAX) + port = GetNextAvailablePort(); + + // Spawn a new thread to accept the port that gets bound after + // binding to port 0 (zero). + + // ignore the hostname send from the remote end, just use the ip address + // that we're currently communicating with as the hostname + + // Spawn a debugserver and try to get the port it listens to. + ProcessLaunchInfo debugserver_launch_info; + if (hostname.empty()) + hostname = "127.0.0.1"; + + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) + log->Printf("Launching debugserver with: %s:%u...", hostname.c_str(), port); + + // Do not run in a new session so that it can not linger after the + // platform closes. + debugserver_launch_info.SetLaunchInSeparateProcessGroup(false); + debugserver_launch_info.SetMonitorProcessCallback( + std::bind(&GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped, + this, std::placeholders::_1), + false); + + llvm::StringRef platform_scheme; + llvm::StringRef platform_ip; + int platform_port; + llvm::StringRef platform_path; + bool ok = UriParser::Parse(GetConnection()->GetURI(), platform_scheme, + platform_ip, platform_port, platform_path); + UNUSED_IF_ASSERT_DISABLED(ok); + assert(ok); + + std::ostringstream url; +// debugserver does not accept the URL scheme prefix. #if !defined(__APPLE__) - url << m_socket_scheme << "://"; + url << m_socket_scheme << "://"; #endif - uint16_t* port_ptr = &port; - if (m_socket_protocol == Socket::ProtocolTcp) - url << platform_ip << ":" << port; - else - { - socket_name = GetDomainSocketPath("gdbserver").GetPath(); - url << socket_name; - port_ptr = nullptr; - } - - Error error = StartDebugserverProcess (url.str().c_str(), - nullptr, - debugserver_launch_info, - port_ptr, - args); - - pid = debugserver_launch_info.GetProcessID(); - if (pid != LLDB_INVALID_PROCESS_ID) - { - std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); - m_spawned_pids.insert(pid); - if (port > 0) - AssociatePortWithProcess(port, pid); - } - else - { - if (port > 0) - FreePort(port); - } - return error; + uint16_t *port_ptr = &port; + if (m_socket_protocol == Socket::ProtocolTcp) + url << platform_ip.str() << ":" << port; + else { + socket_name = GetDomainSocketPath("gdbserver").GetPath(); + url << socket_name; + port_ptr = nullptr; + } + + Error error = StartDebugserverProcess( + url.str().c_str(), nullptr, debugserver_launch_info, port_ptr, &args, -1); + + pid = debugserver_launch_info.GetProcessID(); + if (pid != LLDB_INVALID_PROCESS_ID) { + std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); + m_spawned_pids.insert(pid); + if (port > 0) + AssociatePortWithProcess(port, pid); + } else { + if (port > 0) + FreePort(port); + } + return error; } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet) -{ +GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer( + StringExtractorGDBRemote &packet) { #ifdef _WIN32 - return SendErrorResponse(9); + return SendErrorResponse(9); #else - // Spawn a local debugserver as a platform so we can then attach or launch - // a process... - - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); + // Spawn a local debugserver as a platform so we can then attach or launch + // a process... + + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) + log->Printf("GDBRemoteCommunicationServerPlatform::%s() called", + __FUNCTION__); + + ConnectionFileDescriptor file_conn; + std::string hostname; + packet.SetFilePos(::strlen("qLaunchGDBServer;")); + llvm::StringRef name; + llvm::StringRef value; + uint16_t port = UINT16_MAX; + while (packet.GetNameColonValue(name, value)) { + if (name.equals("host")) + hostname = value; + else if (name.equals("port")) + value.getAsInteger(0, port); + } + + lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID; + std::string socket_name; + Error error = + LaunchGDBServer(Args(), hostname, debugserver_pid, port, socket_name); + if (error.Fail()) { if (log) - log->Printf ("GDBRemoteCommunicationServerPlatform::%s() called", __FUNCTION__); - - ConnectionFileDescriptor file_conn; - std::string hostname; - packet.SetFilePos(::strlen ("qLaunchGDBServer;")); - std::string name; - std::string value; - uint16_t port = UINT16_MAX; - while (packet.GetNameColonValue(name, value)) - { - if (name.compare ("host") == 0) - hostname.swap(value); - else if (name.compare ("port") == 0) - port = StringConvert::ToUInt32(value.c_str(), 0, 0); - } - - lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID; - std::string socket_name; - Error error = LaunchGDBServer(Args(), hostname, debugserver_pid, port, socket_name); - if (error.Fail()) - { - if (log) - log->Printf("GDBRemoteCommunicationServerPlatform::%s() debugserver launch failed: %s", __FUNCTION__, error.AsCString ()); - return SendErrorResponse(9); - } - - if (log) - log->Printf ("GDBRemoteCommunicationServerPlatform::%s() debugserver launched successfully as pid %" PRIu64, __FUNCTION__, debugserver_pid); - - StreamGDBRemote response; - response.Printf("pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset); - if (!socket_name.empty()) - { - response.PutCString("socket_name:"); - response.PutCStringAsRawHex8(socket_name.c_str()); - response.PutChar(';'); - } - - PacketResult packet_result = SendPacketNoLock(response.GetData(), response.GetSize()); - if (packet_result != PacketResult::Success) - { - if (debugserver_pid != LLDB_INVALID_PROCESS_ID) - ::kill (debugserver_pid, SIGINT); - } - return packet_result; + log->Printf("GDBRemoteCommunicationServerPlatform::%s() debugserver " + "launch failed: %s", + __FUNCTION__, error.AsCString()); + return SendErrorResponse(9); + } + + if (log) + log->Printf("GDBRemoteCommunicationServerPlatform::%s() debugserver " + "launched successfully as pid %" PRIu64, + __FUNCTION__, debugserver_pid); + + StreamGDBRemote response; + response.Printf("pid:%" PRIu64 ";port:%u;", debugserver_pid, + port + m_port_offset); + if (!socket_name.empty()) { + response.PutCString("socket_name:"); + response.PutCStringAsRawHex8(socket_name.c_str()); + response.PutChar(';'); + } + + PacketResult packet_result = SendPacketNoLock(response.GetString()); + if (packet_result != PacketResult::Success) { + if (debugserver_pid != LLDB_INVALID_PROCESS_ID) + ::kill(debugserver_pid, SIGINT); + } + return packet_result; #endif } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerPlatform::Handle_qQueryGDBServer (StringExtractorGDBRemote &packet) -{ - if (m_pending_gdb_server.pid == LLDB_INVALID_PROCESS_ID) - return SendErrorResponse(4); - - JSONObject::SP server_sp = std::make_shared<JSONObject>(); - server_sp->SetObject("port", std::make_shared<JSONNumber>(m_pending_gdb_server.port)); - if (!m_pending_gdb_server.socket_name.empty()) - server_sp->SetObject("socket_name", - std::make_shared<JSONString>(m_pending_gdb_server.socket_name.c_str())); - - JSONArray server_list; - server_list.AppendObject(server_sp); - - StreamGDBRemote response; - server_list.Write(response); - - StreamGDBRemote escaped_response; - escaped_response.PutEscapedBytes(response.GetData(), response.GetSize()); - return SendPacketNoLock(escaped_response.GetData(), escaped_response.GetSize()); +GDBRemoteCommunicationServerPlatform::Handle_qQueryGDBServer( + StringExtractorGDBRemote &packet) { + if (m_pending_gdb_server.pid == LLDB_INVALID_PROCESS_ID) + return SendErrorResponse(4); + + JSONObject::SP server_sp = std::make_shared<JSONObject>(); + server_sp->SetObject("port", + std::make_shared<JSONNumber>(m_pending_gdb_server.port)); + if (!m_pending_gdb_server.socket_name.empty()) + server_sp->SetObject( + "socket_name", + std::make_shared<JSONString>(m_pending_gdb_server.socket_name.c_str())); + + JSONArray server_list; + server_list.AppendObject(server_sp); + + StreamGDBRemote response; + server_list.Write(response); + + StreamGDBRemote escaped_response; + escaped_response.PutEscapedBytes(response.GetString().data(), + response.GetSize()); + return SendPacketNoLock(escaped_response.GetString()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerPlatform::Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen ("qKillSpawnedProcess:")); +GDBRemoteCommunicationServerPlatform::Handle_qKillSpawnedProcess( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("qKillSpawnedProcess:")); - lldb::pid_t pid = packet.GetU64(LLDB_INVALID_PROCESS_ID); + lldb::pid_t pid = packet.GetU64(LLDB_INVALID_PROCESS_ID); - // verify that we know anything about this pid. - // Scope for locker - { - std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); - if (m_spawned_pids.find(pid) == m_spawned_pids.end()) - { - // not a pid we know about - return SendErrorResponse (10); - } + // verify that we know anything about this pid. + // Scope for locker + { + std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); + if (m_spawned_pids.find(pid) == m_spawned_pids.end()) { + // not a pid we know about + return SendErrorResponse(10); } + } - // go ahead and attempt to kill the spawned process - if (KillSpawnedProcess (pid)) - return SendOKResponse (); - else - return SendErrorResponse (11); + // go ahead and attempt to kill the spawned process + if (KillSpawnedProcess(pid)) + return SendOKResponse(); + else + return SendErrorResponse(11); } -bool -GDBRemoteCommunicationServerPlatform::KillSpawnedProcess (lldb::pid_t pid) -{ - // make sure we know about this process - { - std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); - if (m_spawned_pids.find(pid) == m_spawned_pids.end()) - return false; - } +bool GDBRemoteCommunicationServerPlatform::KillSpawnedProcess(lldb::pid_t pid) { + // make sure we know about this process + { + std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); + if (m_spawned_pids.find(pid) == m_spawned_pids.end()) + return false; + } - // first try a SIGTERM (standard kill) - Host::Kill (pid, SIGTERM); + // first try a SIGTERM (standard kill) + Host::Kill(pid, SIGTERM); - // check if that worked - for (size_t i=0; i<10; ++i) + // check if that worked + for (size_t i = 0; i < 10; ++i) { { - { - std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); - if (m_spawned_pids.find(pid) == m_spawned_pids.end()) - { - // it is now killed - return true; - } - } - usleep (10000); + std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); + if (m_spawned_pids.find(pid) == m_spawned_pids.end()) { + // it is now killed + return true; + } } + usleep(10000); + } - // check one more time after the final usleep - { - std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); - if (m_spawned_pids.find(pid) == m_spawned_pids.end()) - return true; - } + // check one more time after the final usleep + { + std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); + if (m_spawned_pids.find(pid) == m_spawned_pids.end()) + return true; + } - // the launched process still lives. Now try killing it again, - // this time with an unblockable signal. - Host::Kill (pid, SIGKILL); + // the launched process still lives. Now try killing it again, + // this time with an unblockable signal. + Host::Kill(pid, SIGKILL); - for (size_t i=0; i<10; ++i) + for (size_t i = 0; i < 10; ++i) { { - { - std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); - if (m_spawned_pids.find(pid) == m_spawned_pids.end()) - { - // it is now killed - return true; - } - } - usleep (10000); + std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); + if (m_spawned_pids.find(pid) == m_spawned_pids.end()) { + // it is now killed + return true; + } } + usleep(10000); + } - // check one more time after the final usleep - // Scope for locker - { - std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); - if (m_spawned_pids.find(pid) == m_spawned_pids.end()) - return true; - } + // check one more time after the final usleep + // Scope for locker + { + std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); + if (m_spawned_pids.find(pid) == m_spawned_pids.end()) + return true; + } - // no luck - the process still lives - return false; + // no luck - the process still lives + return false; } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo (StringExtractorGDBRemote &packet) -{ - lldb::pid_t pid = m_process_launch_info.GetProcessID (); - m_process_launch_info.Clear (); +GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo( + StringExtractorGDBRemote &packet) { + lldb::pid_t pid = m_process_launch_info.GetProcessID(); + m_process_launch_info.Clear(); - if (pid == LLDB_INVALID_PROCESS_ID) - return SendErrorResponse (1); + if (pid == LLDB_INVALID_PROCESS_ID) + return SendErrorResponse(1); - ProcessInstanceInfo proc_info; - if (!Host::GetProcessInfo (pid, proc_info)) - return SendErrorResponse (1); + ProcessInstanceInfo proc_info; + if (!Host::GetProcessInfo(pid, proc_info)) + return SendErrorResponse(1); - StreamString response; - CreateProcessInfoResponse_DebugServerStyle(proc_info, response); - return SendPacketNoLock (response.GetData (), response.GetSize ()); + StreamString response; + CreateProcessInfoResponse_DebugServerStyle(proc_info, response); + return SendPacketNoLock(response.GetString()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerPlatform::Handle_qGetWorkingDir (StringExtractorGDBRemote &packet) -{ - // If this packet is sent to a platform, then change the current working directory - - char cwd[PATH_MAX]; - if (getcwd(cwd, sizeof(cwd)) == NULL) - return SendErrorResponse(errno); - - StreamString response; - response.PutBytesAsRawHex8(cwd, strlen(cwd)); - return SendPacketNoLock(response.GetData(), response.GetSize()); +GDBRemoteCommunicationServerPlatform::Handle_qGetWorkingDir( + StringExtractorGDBRemote &packet) { + // If this packet is sent to a platform, then change the current working + // directory + + char cwd[PATH_MAX]; + if (getcwd(cwd, sizeof(cwd)) == NULL) + return SendErrorResponse(errno); + + StreamString response; + response.PutBytesAsRawHex8(cwd, strlen(cwd)); + return SendPacketNoLock(response.GetString()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerPlatform::Handle_QSetWorkingDir (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos (::strlen ("QSetWorkingDir:")); - std::string path; - packet.GetHexByteString (path); - - // If this packet is sent to a platform, then change the current working directory - if (::chdir(path.c_str()) != 0) - return SendErrorResponse (errno); - return SendOKResponse (); +GDBRemoteCommunicationServerPlatform::Handle_QSetWorkingDir( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("QSetWorkingDir:")); + std::string path; + packet.GetHexByteString(path); + + // If this packet is sent to a platform, then change the current working + // directory + if (::chdir(path.c_str()) != 0) + return SendErrorResponse(errno); + return SendOKResponse(); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerPlatform::Handle_qC (StringExtractorGDBRemote &packet) -{ - // NOTE: lldb should now be using qProcessInfo for process IDs. This path here - // should not be used. It is reporting process id instead of thread id. The - // correct answer doesn't seem to make much sense for lldb-platform. - // CONSIDER: flip to "unsupported". - lldb::pid_t pid = m_process_launch_info.GetProcessID(); - - StreamString response; - response.Printf("QC%" PRIx64, pid); - - // If we launch a process and this GDB server is acting as a platform, - // then we need to clear the process launch state so we can start - // launching another process. In order to launch a process a bunch or - // packets need to be sent: environment packets, working directory, - // disable ASLR, and many more settings. When we launch a process we - // then need to know when to clear this information. Currently we are - // selecting the 'qC' packet as that packet which seems to make the most - // sense. - if (pid != LLDB_INVALID_PROCESS_ID) - { - m_process_launch_info.Clear(); - } - - return SendPacketNoLock (response.GetData(), response.GetSize()); +GDBRemoteCommunicationServerPlatform::Handle_qC( + StringExtractorGDBRemote &packet) { + // NOTE: lldb should now be using qProcessInfo for process IDs. This path + // here + // should not be used. It is reporting process id instead of thread id. The + // correct answer doesn't seem to make much sense for lldb-platform. + // CONSIDER: flip to "unsupported". + lldb::pid_t pid = m_process_launch_info.GetProcessID(); + + StreamString response; + response.Printf("QC%" PRIx64, pid); + + // If we launch a process and this GDB server is acting as a platform, + // then we need to clear the process launch state so we can start + // launching another process. In order to launch a process a bunch or + // packets need to be sent: environment packets, working directory, + // disable ASLR, and many more settings. When we launch a process we + // then need to know when to clear this information. Currently we are + // selecting the 'qC' packet as that packet which seems to make the most + // sense. + if (pid != LLDB_INVALID_PROCESS_ID) { + m_process_launch_info.Clear(); + } + + return SendPacketNoLock(response.GetString()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerPlatform::Handle_jSignalsInfo(StringExtractorGDBRemote &packet) -{ - StructuredData::Array signal_array; - - const auto &signals = Host::GetUnixSignals(); - for (auto signo = signals->GetFirstSignalNumber(); - signo != LLDB_INVALID_SIGNAL_NUMBER; - signo = signals->GetNextSignalNumber(signo)) - { - auto dictionary = std::make_shared<StructuredData::Dictionary>(); - - dictionary->AddIntegerItem("signo", signo); - dictionary->AddStringItem("name", signals->GetSignalAsCString(signo)); - - bool suppress, stop, notify; - signals->GetSignalInfo(signo, suppress, stop, notify); - dictionary->AddBooleanItem("suppress", suppress); - dictionary->AddBooleanItem("stop", stop); - dictionary->AddBooleanItem("notify", notify); - - signal_array.Push(dictionary); - } - - StreamString response; - signal_array.Dump(response); - return SendPacketNoLock(response.GetData(), response.GetSize()); +GDBRemoteCommunicationServerPlatform::Handle_jSignalsInfo( + StringExtractorGDBRemote &packet) { + StructuredData::Array signal_array; + + const auto &signals = Host::GetUnixSignals(); + for (auto signo = signals->GetFirstSignalNumber(); + signo != LLDB_INVALID_SIGNAL_NUMBER; + signo = signals->GetNextSignalNumber(signo)) { + auto dictionary = std::make_shared<StructuredData::Dictionary>(); + + dictionary->AddIntegerItem("signo", signo); + dictionary->AddStringItem("name", signals->GetSignalAsCString(signo)); + + bool suppress, stop, notify; + signals->GetSignalInfo(signo, suppress, stop, notify); + dictionary->AddBooleanItem("suppress", suppress); + dictionary->AddBooleanItem("stop", stop); + dictionary->AddBooleanItem("notify", notify); + + signal_array.Push(dictionary); + } + + StreamString response; + signal_array.Dump(response); + return SendPacketNoLock(response.GetString()); } -bool -GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped (lldb::pid_t pid) -{ - std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); - FreePortForProcess(pid); - m_spawned_pids.erase(pid); - return true; +bool GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped( + lldb::pid_t pid) { + std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); + FreePortForProcess(pid); + m_spawned_pids.erase(pid); + return true; } -Error -GDBRemoteCommunicationServerPlatform::LaunchProcess () -{ - if (!m_process_launch_info.GetArguments ().GetArgumentCount ()) - return Error ("%s: no process command line specified to launch", __FUNCTION__); - - // specify the process monitor if not already set. This should - // generally be what happens since we need to reap started - // processes. - if (!m_process_launch_info.GetMonitorProcessCallback ()) - m_process_launch_info.SetMonitorProcessCallback( - std::bind(&GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped, this, std::placeholders::_1), - false); - - Error error = Host::LaunchProcess(m_process_launch_info); - if (!error.Success ()) - { - fprintf (stderr, "%s: failed to launch executable %s", __FUNCTION__, m_process_launch_info.GetArguments ().GetArgumentAtIndex (0)); - return error; - } +Error GDBRemoteCommunicationServerPlatform::LaunchProcess() { + if (!m_process_launch_info.GetArguments().GetArgumentCount()) + return Error("%s: no process command line specified to launch", + __FUNCTION__); + + // specify the process monitor if not already set. This should + // generally be what happens since we need to reap started + // processes. + if (!m_process_launch_info.GetMonitorProcessCallback()) + m_process_launch_info.SetMonitorProcessCallback( + std::bind( + &GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped, + this, std::placeholders::_1), + false); + + Error error = Host::LaunchProcess(m_process_launch_info); + if (!error.Success()) { + fprintf(stderr, "%s: failed to launch executable %s", __FUNCTION__, + m_process_launch_info.GetArguments().GetArgumentAtIndex(0)); + return error; + } - printf ("Launched '%s' as process %" PRIu64 "...\n", m_process_launch_info.GetArguments ().GetArgumentAtIndex (0), m_process_launch_info.GetProcessID()); + printf("Launched '%s' as process %" PRIu64 "...\n", + m_process_launch_info.GetArguments().GetArgumentAtIndex(0), + m_process_launch_info.GetProcessID()); - // add to list of spawned processes. On an lldb-gdbserver, we - // would expect there to be only one. - const auto pid = m_process_launch_info.GetProcessID(); - if (pid != LLDB_INVALID_PROCESS_ID) - { - // add to spawned pids - std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); - m_spawned_pids.insert(pid); - } + // add to list of spawned processes. On an lldb-gdbserver, we + // would expect there to be only one. + const auto pid = m_process_launch_info.GetProcessID(); + if (pid != LLDB_INVALID_PROCESS_ID) { + // add to spawned pids + std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); + m_spawned_pids.insert(pid); + } - return error; + return error; } -void -GDBRemoteCommunicationServerPlatform::SetPortMap (PortMap &&port_map) -{ - m_port_map = port_map; +void GDBRemoteCommunicationServerPlatform::SetPortMap(PortMap &&port_map) { + m_port_map = port_map; } -uint16_t -GDBRemoteCommunicationServerPlatform::GetNextAvailablePort () -{ - if (m_port_map.empty()) - return 0; // Bind to port zero and get a port, we didn't have any limitations +uint16_t GDBRemoteCommunicationServerPlatform::GetNextAvailablePort() { + if (m_port_map.empty()) + return 0; // Bind to port zero and get a port, we didn't have any + // limitations - for (auto &pair : m_port_map) - { - if (pair.second == LLDB_INVALID_PROCESS_ID) - { - pair.second = ~(lldb::pid_t)LLDB_INVALID_PROCESS_ID; - return pair.first; - } + for (auto &pair : m_port_map) { + if (pair.second == LLDB_INVALID_PROCESS_ID) { + pair.second = ~(lldb::pid_t)LLDB_INVALID_PROCESS_ID; + return pair.first; } - return UINT16_MAX; + } + return UINT16_MAX; } -bool -GDBRemoteCommunicationServerPlatform::AssociatePortWithProcess (uint16_t port, lldb::pid_t pid) -{ - PortMap::iterator pos = m_port_map.find(port); - if (pos != m_port_map.end()) - { - pos->second = pid; - return true; - } - return false; +bool GDBRemoteCommunicationServerPlatform::AssociatePortWithProcess( + uint16_t port, lldb::pid_t pid) { + PortMap::iterator pos = m_port_map.find(port); + if (pos != m_port_map.end()) { + pos->second = pid; + return true; + } + return false; } -bool -GDBRemoteCommunicationServerPlatform::FreePort (uint16_t port) -{ - PortMap::iterator pos = m_port_map.find(port); - if (pos != m_port_map.end()) - { - pos->second = LLDB_INVALID_PROCESS_ID; - return true; - } - return false; +bool GDBRemoteCommunicationServerPlatform::FreePort(uint16_t port) { + PortMap::iterator pos = m_port_map.find(port); + if (pos != m_port_map.end()) { + pos->second = LLDB_INVALID_PROCESS_ID; + return true; + } + return false; } -bool -GDBRemoteCommunicationServerPlatform::FreePortForProcess (lldb::pid_t pid) -{ - if (!m_port_map.empty()) - { - for (auto &pair : m_port_map) - { - if (pair.second == pid) - { - pair.second = LLDB_INVALID_PROCESS_ID; - return true; - } - } +bool GDBRemoteCommunicationServerPlatform::FreePortForProcess(lldb::pid_t pid) { + if (!m_port_map.empty()) { + for (auto &pair : m_port_map) { + if (pair.second == pid) { + pair.second = LLDB_INVALID_PROCESS_ID; + return true; + } } - return false; + } + return false; } -const FileSpec& -GDBRemoteCommunicationServerPlatform::GetDomainSocketDir() -{ - static FileSpec g_domainsocket_dir; - static std::once_flag g_once_flag; - - std::call_once(g_once_flag, []() { - const char* domainsocket_dir_env = ::getenv("LLDB_DEBUGSERVER_DOMAINSOCKET_DIR"); - if (domainsocket_dir_env != nullptr) - g_domainsocket_dir = FileSpec(domainsocket_dir_env, false); - else - HostInfo::GetLLDBPath(ePathTypeLLDBTempSystemDir, g_domainsocket_dir); - }); - - return g_domainsocket_dir; +const FileSpec &GDBRemoteCommunicationServerPlatform::GetDomainSocketDir() { + static FileSpec g_domainsocket_dir; + static std::once_flag g_once_flag; + + std::call_once(g_once_flag, []() { + const char *domainsocket_dir_env = + ::getenv("LLDB_DEBUGSERVER_DOMAINSOCKET_DIR"); + if (domainsocket_dir_env != nullptr) + g_domainsocket_dir = FileSpec(domainsocket_dir_env, false); + else + HostInfo::GetLLDBPath(ePathTypeLLDBTempSystemDir, g_domainsocket_dir); + }); + + return g_domainsocket_dir; } FileSpec -GDBRemoteCommunicationServerPlatform::GetDomainSocketPath(const char* prefix) -{ - llvm::SmallString<PATH_MAX> socket_path; - llvm::SmallString<PATH_MAX> socket_name((llvm::StringRef(prefix) + ".%%%%%%").str()); +GDBRemoteCommunicationServerPlatform::GetDomainSocketPath(const char *prefix) { + llvm::SmallString<PATH_MAX> socket_path; + llvm::SmallString<PATH_MAX> socket_name( + (llvm::StringRef(prefix) + ".%%%%%%").str()); - FileSpec socket_path_spec(GetDomainSocketDir()); - socket_path_spec.AppendPathComponent(socket_name.c_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); + llvm::sys::fs::createUniqueFile(socket_path_spec.GetCString(), socket_path); + return FileSpec(socket_path.c_str(), false); } -void -GDBRemoteCommunicationServerPlatform::SetPortOffset(uint16_t port_offset) -{ - m_port_offset = port_offset; +void GDBRemoteCommunicationServerPlatform::SetPortOffset(uint16_t port_offset) { + m_port_offset = port_offset; } -void -GDBRemoteCommunicationServerPlatform::SetPendingGdbServer(lldb::pid_t pid, - uint16_t port, - const std::string& socket_name) -{ - m_pending_gdb_server.pid = pid; - m_pending_gdb_server.port = port; - m_pending_gdb_server.socket_name = socket_name; +void GDBRemoteCommunicationServerPlatform::SetPendingGdbServer( + lldb::pid_t pid, uint16_t port, const std::string &socket_name) { + m_pending_gdb_server.pid = pid; + m_pending_gdb_server.port = port; + m_pending_gdb_server.socket_name = socket_name; } diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h index 1f4d08c..472d86e 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h @@ -24,110 +24,90 @@ namespace lldb_private { namespace process_gdb_remote { -class GDBRemoteCommunicationServerPlatform : - public GDBRemoteCommunicationServerCommon -{ +class GDBRemoteCommunicationServerPlatform + : public GDBRemoteCommunicationServerCommon { public: - typedef std::map<uint16_t, lldb::pid_t> PortMap; + typedef std::map<uint16_t, lldb::pid_t> PortMap; - GDBRemoteCommunicationServerPlatform(const Socket::SocketProtocol socket_protocol, - const char* socket_scheme); + GDBRemoteCommunicationServerPlatform( + const Socket::SocketProtocol socket_protocol, const char *socket_scheme); - ~GDBRemoteCommunicationServerPlatform() override; + ~GDBRemoteCommunicationServerPlatform() override; - Error - LaunchProcess () override; + Error LaunchProcess() override; - // Set both ports to zero to let the platform automatically bind to - // a port chosen by the OS. - void - SetPortMap (PortMap &&port_map); + // Set both ports to zero to let the platform automatically bind to + // a port chosen by the OS. + void SetPortMap(PortMap &&port_map); - //---------------------------------------------------------------------- - // If we are using a port map where we can only use certain ports, - // get the next available port. - // - // If we are using a port map and we are out of ports, return UINT16_MAX - // - // If we aren't using a port map, return 0 to indicate we should bind to - // port 0 and then figure out which port we used. - //---------------------------------------------------------------------- - uint16_t - GetNextAvailablePort (); + //---------------------------------------------------------------------- + // If we are using a port map where we can only use certain ports, + // get the next available port. + // + // If we are using a port map and we are out of ports, return UINT16_MAX + // + // If we aren't using a port map, return 0 to indicate we should bind to + // port 0 and then figure out which port we used. + //---------------------------------------------------------------------- + uint16_t GetNextAvailablePort(); - bool - AssociatePortWithProcess (uint16_t port, lldb::pid_t pid); + bool AssociatePortWithProcess(uint16_t port, lldb::pid_t pid); - bool - FreePort (uint16_t port); + bool FreePort(uint16_t port); - bool - FreePortForProcess (lldb::pid_t pid); + bool FreePortForProcess(lldb::pid_t pid); - void - SetPortOffset (uint16_t port_offset); + void SetPortOffset(uint16_t port_offset); - void - SetInferiorArguments (const lldb_private::Args& args); + void SetInferiorArguments(const lldb_private::Args &args); - Error - LaunchGDBServer(const lldb_private::Args& args, - std::string hostname, - lldb::pid_t& pid, - uint16_t& port, - std::string& socket_name); + Error LaunchGDBServer(const lldb_private::Args &args, std::string hostname, + lldb::pid_t &pid, uint16_t &port, + std::string &socket_name); - void - SetPendingGdbServer(lldb::pid_t pid, uint16_t port, const std::string& socket_name); + void SetPendingGdbServer(lldb::pid_t pid, uint16_t port, + const std::string &socket_name); protected: - const Socket::SocketProtocol m_socket_protocol; - const std::string m_socket_scheme; - std::recursive_mutex m_spawned_pids_mutex; - std::set<lldb::pid_t> m_spawned_pids; + const Socket::SocketProtocol m_socket_protocol; + const std::string m_socket_scheme; + std::recursive_mutex m_spawned_pids_mutex; + std::set<lldb::pid_t> m_spawned_pids; - PortMap m_port_map; - uint16_t m_port_offset; - struct { lldb::pid_t pid; uint16_t port; std::string socket_name; } m_pending_gdb_server; + PortMap m_port_map; + uint16_t m_port_offset; + struct { + lldb::pid_t pid; + uint16_t port; + std::string socket_name; + } m_pending_gdb_server; - PacketResult - Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet); + PacketResult Handle_qLaunchGDBServer(StringExtractorGDBRemote &packet); - PacketResult - Handle_qQueryGDBServer (StringExtractorGDBRemote &packet); + PacketResult Handle_qQueryGDBServer(StringExtractorGDBRemote &packet); - PacketResult - Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet); + PacketResult Handle_qKillSpawnedProcess(StringExtractorGDBRemote &packet); - PacketResult - Handle_qProcessInfo (StringExtractorGDBRemote &packet); + PacketResult Handle_qProcessInfo(StringExtractorGDBRemote &packet); - PacketResult - Handle_qGetWorkingDir (StringExtractorGDBRemote &packet); + PacketResult Handle_qGetWorkingDir(StringExtractorGDBRemote &packet); - PacketResult - Handle_QSetWorkingDir (StringExtractorGDBRemote &packet); + PacketResult Handle_QSetWorkingDir(StringExtractorGDBRemote &packet); - PacketResult - Handle_qC (StringExtractorGDBRemote &packet); + PacketResult Handle_qC(StringExtractorGDBRemote &packet); - PacketResult - Handle_jSignalsInfo(StringExtractorGDBRemote &packet); + PacketResult Handle_jSignalsInfo(StringExtractorGDBRemote &packet); private: - bool - KillSpawnedProcess (lldb::pid_t pid); + bool KillSpawnedProcess(lldb::pid_t pid); - bool - DebugserverProcessReaped (lldb::pid_t pid); + bool DebugserverProcessReaped(lldb::pid_t pid); - static const FileSpec& - GetDomainSocketDir(); + static const FileSpec &GetDomainSocketDir(); - static FileSpec - GetDomainSocketPath(const char* prefix); + static FileSpec GetDomainSocketPath(const char *prefix); - DISALLOW_COPY_AND_ASSIGN (GDBRemoteCommunicationServerPlatform); + DISALLOW_COPY_AND_ASSIGN(GDBRemoteCommunicationServerPlatform); }; } // namespace process_gdb_remote diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp index 57983c4..27ce67d 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp @@ -21,12 +21,12 @@ #include "lldb/Target/Target.h" #include "lldb/Utility/Utils.h" // Project includes -#include "Utility/StringExtractorGDBRemote.h" #include "ProcessGDBRemote.h" #include "ProcessGDBRemoteLog.h" #include "ThreadGDBRemote.h" #include "Utility/ARM_DWARF_Registers.h" #include "Utility/ARM_ehframe_Registers.h" +#include "Utility/StringExtractorGDBRemote.h" using namespace lldb; using namespace lldb_private; @@ -35,1189 +35,953 @@ using namespace lldb_private::process_gdb_remote; //---------------------------------------------------------------------- // GDBRemoteRegisterContext constructor //---------------------------------------------------------------------- -GDBRemoteRegisterContext::GDBRemoteRegisterContext -( - ThreadGDBRemote &thread, - uint32_t concrete_frame_idx, - GDBRemoteDynamicRegisterInfo ®_info, - bool read_all_at_once -) : - RegisterContext (thread, concrete_frame_idx), - m_reg_info (reg_info), - m_reg_valid (), - m_reg_data (), - m_read_all_at_once (read_all_at_once) -{ - // Resize our vector of bools to contain one bool for every register. - // We will use these boolean values to know when a register value - // is valid in m_reg_data. - m_reg_valid.resize (reg_info.GetNumRegisters()); - - // Make a heap based buffer that is big enough to store all registers - DataBufferSP reg_data_sp(new DataBufferHeap (reg_info.GetRegisterDataByteSize(), 0)); - m_reg_data.SetData (reg_data_sp); - m_reg_data.SetByteOrder(thread.GetProcess()->GetByteOrder()); +GDBRemoteRegisterContext::GDBRemoteRegisterContext( + ThreadGDBRemote &thread, uint32_t concrete_frame_idx, + GDBRemoteDynamicRegisterInfo ®_info, bool read_all_at_once) + : RegisterContext(thread, concrete_frame_idx), m_reg_info(reg_info), + m_reg_valid(), m_reg_data(), m_read_all_at_once(read_all_at_once) { + // Resize our vector of bools to contain one bool for every register. + // We will use these boolean values to know when a register value + // is valid in m_reg_data. + m_reg_valid.resize(reg_info.GetNumRegisters()); + + // Make a heap based buffer that is big enough to store all registers + DataBufferSP reg_data_sp( + new DataBufferHeap(reg_info.GetRegisterDataByteSize(), 0)); + m_reg_data.SetData(reg_data_sp); + m_reg_data.SetByteOrder(thread.GetProcess()->GetByteOrder()); } //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- -GDBRemoteRegisterContext::~GDBRemoteRegisterContext() -{ -} +GDBRemoteRegisterContext::~GDBRemoteRegisterContext() {} -void -GDBRemoteRegisterContext::InvalidateAllRegisters () -{ - SetAllRegisterValid (false); +void GDBRemoteRegisterContext::InvalidateAllRegisters() { + SetAllRegisterValid(false); } -void -GDBRemoteRegisterContext::SetAllRegisterValid (bool b) -{ - std::vector<bool>::iterator pos, end = m_reg_valid.end(); - for (pos = m_reg_valid.begin(); pos != end; ++pos) - *pos = b; +void GDBRemoteRegisterContext::SetAllRegisterValid(bool b) { + std::vector<bool>::iterator pos, end = m_reg_valid.end(); + for (pos = m_reg_valid.begin(); pos != end; ++pos) + *pos = b; } -size_t -GDBRemoteRegisterContext::GetRegisterCount () -{ - return m_reg_info.GetNumRegisters (); +size_t GDBRemoteRegisterContext::GetRegisterCount() { + return m_reg_info.GetNumRegisters(); } const RegisterInfo * -GDBRemoteRegisterContext::GetRegisterInfoAtIndex (size_t reg) -{ - RegisterInfo* reg_info = m_reg_info.GetRegisterInfoAtIndex (reg); - - if (reg_info && reg_info->dynamic_size_dwarf_expr_bytes) - { - const ArchSpec &arch = m_thread.GetProcess ()->GetTarget ().GetArchitecture (); - uint8_t reg_size = UpdateDynamicRegisterSize (arch, reg_info); - reg_info->byte_size = reg_size; - } - return reg_info; +GDBRemoteRegisterContext::GetRegisterInfoAtIndex(size_t reg) { + RegisterInfo *reg_info = m_reg_info.GetRegisterInfoAtIndex(reg); + + if (reg_info && reg_info->dynamic_size_dwarf_expr_bytes) { + const ArchSpec &arch = m_thread.GetProcess()->GetTarget().GetArchitecture(); + uint8_t reg_size = UpdateDynamicRegisterSize(arch, reg_info); + reg_info->byte_size = reg_size; + } + return reg_info; } -size_t -GDBRemoteRegisterContext::GetRegisterSetCount () -{ - return m_reg_info.GetNumRegisterSets (); +size_t GDBRemoteRegisterContext::GetRegisterSetCount() { + return m_reg_info.GetNumRegisterSets(); } - - -const RegisterSet * -GDBRemoteRegisterContext::GetRegisterSet (size_t reg_set) -{ - return m_reg_info.GetRegisterSet (reg_set); +const RegisterSet *GDBRemoteRegisterContext::GetRegisterSet(size_t reg_set) { + return m_reg_info.GetRegisterSet(reg_set); } +bool GDBRemoteRegisterContext::ReadRegister(const RegisterInfo *reg_info, + RegisterValue &value) { + // Read the register + if (ReadRegisterBytes(reg_info, m_reg_data)) { + const bool partial_data_ok = false; + Error error(value.SetValueFromData(reg_info, m_reg_data, + reg_info->byte_offset, partial_data_ok)); + return error.Success(); + } + return false; +} - -bool -GDBRemoteRegisterContext::ReadRegister (const RegisterInfo *reg_info, RegisterValue &value) -{ - // Read the register - if (ReadRegisterBytes (reg_info, m_reg_data)) - { - const bool partial_data_ok = false; - Error error (value.SetValueFromData(reg_info, m_reg_data, reg_info->byte_offset, partial_data_ok)); - return error.Success(); - } +bool GDBRemoteRegisterContext::PrivateSetRegisterValue( + uint32_t reg, llvm::ArrayRef<uint8_t> data) { + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); + if (reg_info == NULL) return false; -} -bool -GDBRemoteRegisterContext::PrivateSetRegisterValue (uint32_t reg, StringExtractor &response) -{ - const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg); - if (reg_info == NULL) - return false; - - // Invalidate if needed - InvalidateIfNeeded(false); - - const uint32_t reg_byte_size = reg_info->byte_size; - const size_t bytes_copied = response.GetHexBytes (const_cast<uint8_t*>(m_reg_data.PeekData(reg_info->byte_offset, reg_byte_size)), reg_byte_size, '\xcc'); - bool success = bytes_copied == reg_byte_size; - if (success) - { - SetRegisterIsValid(reg, true); - } - else if (bytes_copied > 0) - { - // Only set register is valid to false if we copied some bytes, else - // leave it as it was. - SetRegisterIsValid(reg, false); - } - return success; + // Invalidate if needed + InvalidateIfNeeded(false); + + const size_t reg_byte_size = reg_info->byte_size; + memcpy(const_cast<uint8_t *>( + m_reg_data.PeekData(reg_info->byte_offset, reg_byte_size)), + data.data(), std::min(data.size(), reg_byte_size)); + bool success = data.size() >= reg_byte_size; + if (success) { + SetRegisterIsValid(reg, true); + } else if (data.size() > 0) { + // Only set register is valid to false if we copied some bytes, else + // leave it as it was. + SetRegisterIsValid(reg, false); + } + return success; } -bool -GDBRemoteRegisterContext::PrivateSetRegisterValue (uint32_t reg, uint64_t new_reg_val) -{ - const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg); - if (reg_info == NULL) - return false; - - // Early in process startup, we can get a thread that has an invalid byte order - // because the process hasn't been completely set up yet (see the ctor where the - // byte order is setfrom the process). If that's the case, we can't set the - // value here. - if (m_reg_data.GetByteOrder() == eByteOrderInvalid) - { - return false; - } - - // Invalidate if needed - InvalidateIfNeeded (false); +bool GDBRemoteRegisterContext::PrivateSetRegisterValue(uint32_t reg, + uint64_t new_reg_val) { + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); + if (reg_info == NULL) + return false; - DataBufferSP buffer_sp (new DataBufferHeap (&new_reg_val, sizeof (new_reg_val))); - DataExtractor data (buffer_sp, endian::InlHostByteOrder(), sizeof (void*)); + // Early in process startup, we can get a thread that has an invalid byte + // order + // because the process hasn't been completely set up yet (see the ctor where + // the + // byte order is setfrom the process). If that's the case, we can't set the + // value here. + if (m_reg_data.GetByteOrder() == eByteOrderInvalid) { + return false; + } - // If our register context and our register info disagree, which should never happen, don't - // overwrite past the end of the buffer. - if (m_reg_data.GetByteSize() < reg_info->byte_offset + reg_info->byte_size) - return false; + // Invalidate if needed + InvalidateIfNeeded(false); - // Grab a pointer to where we are going to put this register - uint8_t *dst = const_cast<uint8_t*>(m_reg_data.PeekData(reg_info->byte_offset, reg_info->byte_size)); + DataBufferSP buffer_sp(new DataBufferHeap(&new_reg_val, sizeof(new_reg_val))); + DataExtractor data(buffer_sp, endian::InlHostByteOrder(), sizeof(void *)); - if (dst == NULL) - return false; + // If our register context and our register info disagree, which should never + // happen, don't + // overwrite past the end of the buffer. + if (m_reg_data.GetByteSize() < reg_info->byte_offset + reg_info->byte_size) + return false; + // Grab a pointer to where we are going to put this register + uint8_t *dst = const_cast<uint8_t *>( + m_reg_data.PeekData(reg_info->byte_offset, reg_info->byte_size)); - if (data.CopyByteOrderedData (0, // src offset - reg_info->byte_size, // src length - dst, // dst - reg_info->byte_size, // dst length - m_reg_data.GetByteOrder())) // dst byte order - { - SetRegisterIsValid (reg, true); - return true; - } + if (dst == NULL) return false; + + if (data.CopyByteOrderedData(0, // src offset + reg_info->byte_size, // src length + dst, // dst + reg_info->byte_size, // dst length + m_reg_data.GetByteOrder())) // dst byte order + { + SetRegisterIsValid(reg, true); + return true; + } + return false; } // Helper function for GDBRemoteRegisterContext::ReadRegisterBytes(). -bool -GDBRemoteRegisterContext::GetPrimordialRegister(const RegisterInfo *reg_info, - GDBRemoteCommunicationClient &gdb_comm) -{ - const uint32_t lldb_reg = reg_info->kinds[eRegisterKindLLDB]; - const uint32_t remote_reg = reg_info->kinds[eRegisterKindProcessPlugin]; - StringExtractorGDBRemote response; - if (gdb_comm.ReadRegister(m_thread.GetProtocolID(), remote_reg, response)) - return PrivateSetRegisterValue (lldb_reg, response); - return false; +bool GDBRemoteRegisterContext::GetPrimordialRegister( + const RegisterInfo *reg_info, GDBRemoteCommunicationClient &gdb_comm) { + const uint32_t lldb_reg = reg_info->kinds[eRegisterKindLLDB]; + const uint32_t remote_reg = reg_info->kinds[eRegisterKindProcessPlugin]; + StringExtractorGDBRemote response; + if (DataBufferSP buffer_sp = + gdb_comm.ReadRegister(m_thread.GetProtocolID(), remote_reg)) + return PrivateSetRegisterValue( + lldb_reg, llvm::ArrayRef<uint8_t>(buffer_sp->GetBytes(), + buffer_sp->GetByteSize())); + return false; } -bool -GDBRemoteRegisterContext::ReadRegisterBytes (const RegisterInfo *reg_info, DataExtractor &data) -{ - ExecutionContext exe_ctx (CalculateThread()); +bool GDBRemoteRegisterContext::ReadRegisterBytes(const RegisterInfo *reg_info, + DataExtractor &data) { + ExecutionContext exe_ctx(CalculateThread()); - Process *process = exe_ctx.GetProcessPtr(); - Thread *thread = exe_ctx.GetThreadPtr(); - if (process == NULL || thread == NULL) - return false; - - GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote()); + Process *process = exe_ctx.GetProcessPtr(); + Thread *thread = exe_ctx.GetThreadPtr(); + if (process == NULL || thread == NULL) + return false; - InvalidateIfNeeded(false); + GDBRemoteCommunicationClient &gdb_comm( + ((ProcessGDBRemote *)process)->GetGDBRemote()); - const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + InvalidateIfNeeded(false); - if (!GetRegisterIsValid(reg)) - { - if (m_read_all_at_once) - { - StringExtractorGDBRemote response; - if (!gdb_comm.ReadAllRegisters(m_thread.GetProtocolID(), response)) - return false; - if (response.IsNormalResponse()) - if (response.GetHexBytes(const_cast<void *>(reinterpret_cast<const void *>(m_reg_data.GetDataStart())), - m_reg_data.GetByteSize(), '\xcc') == m_reg_data.GetByteSize()) - SetAllRegisterValid (true); - } - else if (reg_info->value_regs) - { - // Process this composite register request by delegating to the constituent - // primordial registers. - - // Index of the primordial register. - bool success = true; - for (uint32_t idx = 0; success; ++idx) - { - const uint32_t prim_reg = reg_info->value_regs[idx]; - if (prim_reg == LLDB_INVALID_REGNUM) - break; - // We have a valid primordial register as our constituent. - // Grab the corresponding register info. - const RegisterInfo *prim_reg_info = GetRegisterInfoAtIndex(prim_reg); - if (prim_reg_info == NULL) - success = false; - else - { - // Read the containing register if it hasn't already been read - if (!GetRegisterIsValid(prim_reg)) - success = GetPrimordialRegister(prim_reg_info, gdb_comm); - } - } + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - if (success) - { - // If we reach this point, all primordial register requests have succeeded. - // Validate this composite register. - SetRegisterIsValid (reg_info, true); - } + if (!GetRegisterIsValid(reg)) { + if (m_read_all_at_once) { + if (DataBufferSP buffer_sp = + gdb_comm.ReadAllRegisters(m_thread.GetProtocolID())) { + memcpy(const_cast<uint8_t *>(m_reg_data.GetDataStart()), + buffer_sp->GetBytes(), + std::min(buffer_sp->GetByteSize(), m_reg_data.GetByteSize())); + if (buffer_sp->GetByteSize() >= m_reg_data.GetByteSize()) { + SetAllRegisterValid(true); + return true; } - else - { - // Get each register individually - GetPrimordialRegister(reg_info, gdb_comm); + } + return false; + } + if (reg_info->value_regs) { + // Process this composite register request by delegating to the + // constituent + // primordial registers. + + // Index of the primordial register. + bool success = true; + for (uint32_t idx = 0; success; ++idx) { + const uint32_t prim_reg = reg_info->value_regs[idx]; + if (prim_reg == LLDB_INVALID_REGNUM) + break; + // We have a valid primordial register as our constituent. + // Grab the corresponding register info. + const RegisterInfo *prim_reg_info = GetRegisterInfoAtIndex(prim_reg); + if (prim_reg_info == NULL) + success = false; + else { + // Read the containing register if it hasn't already been read + if (!GetRegisterIsValid(prim_reg)) + success = GetPrimordialRegister(prim_reg_info, gdb_comm); } - - // Make sure we got a valid register value after reading it - if (!GetRegisterIsValid(reg)) - return false; + } + + if (success) { + // If we reach this point, all primordial register requests have + // succeeded. + // Validate this composite register. + SetRegisterIsValid(reg_info, true); + } + } else { + // Get each register individually + GetPrimordialRegister(reg_info, gdb_comm); } - if (&data != &m_reg_data) - { -#if defined (LLDB_CONFIGURATION_DEBUG) - assert (m_reg_data.GetByteSize() >= reg_info->byte_offset + reg_info->byte_size); -#endif - // If our register context and our register info disagree, which should never happen, don't - // read past the end of the buffer. - if (m_reg_data.GetByteSize() < reg_info->byte_offset + reg_info->byte_size) - return false; - - // If we aren't extracting into our own buffer (which - // only happens when this function is called from - // ReadRegisterValue(uint32_t, Scalar&)) then - // we transfer bytes from our buffer into the data - // buffer that was passed in - - data.SetByteOrder (m_reg_data.GetByteOrder()); - data.SetData (m_reg_data, reg_info->byte_offset, reg_info->byte_size); - } - return true; -} + // Make sure we got a valid register value after reading it + if (!GetRegisterIsValid(reg)) + return false; + } -bool -GDBRemoteRegisterContext::WriteRegister (const RegisterInfo *reg_info, - const RegisterValue &value) -{ - DataExtractor data; - if (value.GetData (data)) - return WriteRegisterBytes (reg_info, data, 0); - return false; + if (&data != &m_reg_data) { +#if defined(LLDB_CONFIGURATION_DEBUG) + assert(m_reg_data.GetByteSize() >= + reg_info->byte_offset + reg_info->byte_size); +#endif + // If our register context and our register info disagree, which should + // never happen, don't + // read past the end of the buffer. + if (m_reg_data.GetByteSize() < reg_info->byte_offset + reg_info->byte_size) + return false; + + // If we aren't extracting into our own buffer (which + // only happens when this function is called from + // ReadRegisterValue(uint32_t, Scalar&)) then + // we transfer bytes from our buffer into the data + // buffer that was passed in + + data.SetByteOrder(m_reg_data.GetByteOrder()); + data.SetData(m_reg_data, reg_info->byte_offset, reg_info->byte_size); + } + return true; } -// Helper function for GDBRemoteRegisterContext::WriteRegisterBytes(). -bool -GDBRemoteRegisterContext::SetPrimordialRegister(const RegisterInfo *reg_info, - GDBRemoteCommunicationClient &gdb_comm) -{ - StreamString packet; - StringExtractorGDBRemote response; - const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - packet.Printf ("P%x=", reg_info->kinds[eRegisterKindProcessPlugin]); - packet.PutBytesAsRawHex8 (m_reg_data.PeekData(reg_info->byte_offset, reg_info->byte_size), - reg_info->byte_size, - endian::InlHostByteOrder(), - endian::InlHostByteOrder()); - - if (gdb_comm.GetThreadSuffixSupported()) - packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID()); - - // Invalidate just this register - SetRegisterIsValid(reg, false); - if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), - packet.GetString().size(), - response, - false) == GDBRemoteCommunication::PacketResult::Success) - { - if (response.IsOKResponse()) - return true; - } - return false; +bool GDBRemoteRegisterContext::WriteRegister(const RegisterInfo *reg_info, + const RegisterValue &value) { + DataExtractor data; + if (value.GetData(data)) + return WriteRegisterBytes(reg_info, data, 0); + return false; } -void -GDBRemoteRegisterContext::SyncThreadState(Process *process) -{ - // NB. We assume our caller has locked the sequence mutex. - - GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *) process)->GetGDBRemote()); - if (!gdb_comm.GetSyncThreadStateSupported()) - return; - - StreamString packet; - StringExtractorGDBRemote response; - packet.Printf ("QSyncThreadState:%4.4" PRIx64 ";", m_thread.GetProtocolID()); - if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), - packet.GetString().size(), - response, - false) == GDBRemoteCommunication::PacketResult::Success) - { - if (response.IsOKResponse()) - InvalidateAllRegisters(); - } +// Helper function for GDBRemoteRegisterContext::WriteRegisterBytes(). +bool GDBRemoteRegisterContext::SetPrimordialRegister( + const RegisterInfo *reg_info, GDBRemoteCommunicationClient &gdb_comm) { + StreamString packet; + StringExtractorGDBRemote response; + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + // Invalidate just this register + SetRegisterIsValid(reg, false); + + return gdb_comm.WriteRegister( + m_thread.GetProtocolID(), reg_info->kinds[eRegisterKindProcessPlugin], + {m_reg_data.PeekData(reg_info->byte_offset, reg_info->byte_size), + reg_info->byte_size}); } -bool -GDBRemoteRegisterContext::WriteRegisterBytes (const RegisterInfo *reg_info, DataExtractor &data, uint32_t data_offset) -{ - ExecutionContext exe_ctx (CalculateThread()); +bool GDBRemoteRegisterContext::WriteRegisterBytes(const RegisterInfo *reg_info, + DataExtractor &data, + uint32_t data_offset) { + ExecutionContext exe_ctx(CalculateThread()); - Process *process = exe_ctx.GetProcessPtr(); - Thread *thread = exe_ctx.GetThreadPtr(); - if (process == NULL || thread == NULL) - return false; - - GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote()); -// FIXME: This check isn't right because IsRunning checks the Public state, but this -// is work you need to do - for instance in ShouldStop & friends - before the public -// state has been changed. -// if (gdb_comm.IsRunning()) -// return false; + Process *process = exe_ctx.GetProcessPtr(); + Thread *thread = exe_ctx.GetThreadPtr(); + if (process == NULL || thread == NULL) + return false; + GDBRemoteCommunicationClient &gdb_comm( + ((ProcessGDBRemote *)process)->GetGDBRemote()); -#if defined (LLDB_CONFIGURATION_DEBUG) - assert (m_reg_data.GetByteSize() >= reg_info->byte_offset + reg_info->byte_size); +#if defined(LLDB_CONFIGURATION_DEBUG) + assert(m_reg_data.GetByteSize() >= + reg_info->byte_offset + reg_info->byte_size); #endif - // If our register context and our register info disagree, which should never happen, don't - // overwrite past the end of the buffer. - if (m_reg_data.GetByteSize() < reg_info->byte_offset + reg_info->byte_size) - return false; + // If our register context and our register info disagree, which should never + // happen, don't + // overwrite past the end of the buffer. + if (m_reg_data.GetByteSize() < reg_info->byte_offset + reg_info->byte_size) + return false; - // Grab a pointer to where we are going to put this register - uint8_t *dst = const_cast<uint8_t*>(m_reg_data.PeekData(reg_info->byte_offset, reg_info->byte_size)); + // Grab a pointer to where we are going to put this register + uint8_t *dst = const_cast<uint8_t *>( + m_reg_data.PeekData(reg_info->byte_offset, reg_info->byte_size)); - if (dst == NULL) - return false; + if (dst == NULL) + return false; + if (data.CopyByteOrderedData(data_offset, // src offset + reg_info->byte_size, // src length + dst, // dst + reg_info->byte_size, // dst length + m_reg_data.GetByteOrder())) // dst byte order + { + GDBRemoteClientBase::Lock lock(gdb_comm, false); + if (lock) { + if (m_read_all_at_once) { + // Invalidate all register values + InvalidateIfNeeded(true); + + // Set all registers in one packet + if (gdb_comm.WriteAllRegisters( + m_thread.GetProtocolID(), + {m_reg_data.GetDataStart(), size_t(m_reg_data.GetByteSize())})) - if (data.CopyByteOrderedData (data_offset, // src offset - reg_info->byte_size, // src length - dst, // dst - reg_info->byte_size, // dst length - m_reg_data.GetByteOrder())) // dst byte order - { - Mutex::Locker locker; - if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for write register.")) { - const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported(); - ProcessSP process_sp (m_thread.GetProcess()); - if (thread_suffix_supported || static_cast<ProcessGDBRemote *>(process_sp.get())->GetGDBRemote().SetCurrentThread(m_thread.GetProtocolID())) - { - StreamString packet; - StringExtractorGDBRemote response; - - if (m_read_all_at_once) - { - // Set all registers in one packet - packet.PutChar ('G'); - packet.PutBytesAsRawHex8 (m_reg_data.GetDataStart(), - m_reg_data.GetByteSize(), - endian::InlHostByteOrder(), - endian::InlHostByteOrder()); - - if (thread_suffix_supported) - packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID()); - - // Invalidate all register values - InvalidateIfNeeded (true); - - if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), - packet.GetString().size(), - response, - false) == GDBRemoteCommunication::PacketResult::Success) - { - SetAllRegisterValid (false); - if (response.IsOKResponse()) - { - return true; - } - } - } - else - { - bool success = true; - - if (reg_info->value_regs) - { - // This register is part of another register. In this case we read the actual - // register data for any "value_regs", and once all that data is read, we will - // have enough data in our register context bytes for the value of this register - - // Invalidate this composite register first. - - for (uint32_t idx = 0; success; ++idx) - { - const uint32_t reg = reg_info->value_regs[idx]; - if (reg == LLDB_INVALID_REGNUM) - break; - // We have a valid primordial register as our constituent. - // Grab the corresponding register info. - const RegisterInfo *value_reg_info = GetRegisterInfoAtIndex(reg); - if (value_reg_info == NULL) - success = false; - else - success = SetPrimordialRegister(value_reg_info, gdb_comm); - } - } - else - { - // This is an actual register, write it - success = SetPrimordialRegister(reg_info, gdb_comm); - } - - // Check if writing this register will invalidate any other register values? - // If so, invalidate them - if (reg_info->invalidate_regs) - { - for (uint32_t idx = 0, reg = reg_info->invalidate_regs[0]; - reg != LLDB_INVALID_REGNUM; - reg = reg_info->invalidate_regs[++idx]) - { - SetRegisterIsValid(reg, false); - } - } - - return success; - } - } + SetAllRegisterValid(false); + return true; } - else - { - Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_THREAD | GDBR_LOG_PACKETS)); - if (log) - { - if (log->GetVerbose()) - { - StreamString strm; - gdb_comm.DumpHistory(strm); - log->Printf("error: failed to get packet sequence mutex, not sending write register for \"%s\":\n%s", reg_info->name, strm.GetData()); - } - else - log->Printf("error: failed to get packet sequence mutex, not sending write register for \"%s\"", reg_info->name); - } + } else { + bool success = true; + + if (reg_info->value_regs) { + // This register is part of another register. In this case we read the + // actual + // register data for any "value_regs", and once all that data is read, + // we will + // have enough data in our register context bytes for the value of + // this register + + // Invalidate this composite register first. + + for (uint32_t idx = 0; success; ++idx) { + const uint32_t reg = reg_info->value_regs[idx]; + if (reg == LLDB_INVALID_REGNUM) + break; + // We have a valid primordial register as our constituent. + // Grab the corresponding register info. + const RegisterInfo *value_reg_info = GetRegisterInfoAtIndex(reg); + if (value_reg_info == NULL) + success = false; + else + success = SetPrimordialRegister(value_reg_info, gdb_comm); + } + } else { + // This is an actual register, write it + success = SetPrimordialRegister(reg_info, gdb_comm); + } + + // Check if writing this register will invalidate any other register + // values? + // If so, invalidate them + if (reg_info->invalidate_regs) { + for (uint32_t idx = 0, reg = reg_info->invalidate_regs[0]; + reg != LLDB_INVALID_REGNUM; + reg = reg_info->invalidate_regs[++idx]) { + SetRegisterIsValid(reg, false); + } } + + return success; + } + } else { + Log *log(ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(GDBR_LOG_THREAD | + GDBR_LOG_PACKETS)); + if (log) { + if (log->GetVerbose()) { + StreamString strm; + gdb_comm.DumpHistory(strm); + log->Printf("error: failed to get packet sequence mutex, not sending " + "write register for \"%s\":\n%s", + reg_info->name, strm.GetData()); + } else + log->Printf("error: failed to get packet sequence mutex, not sending " + "write register for \"%s\"", + reg_info->name); + } } + } + return false; +} + +bool GDBRemoteRegisterContext::ReadAllRegisterValues( + RegisterCheckpoint ®_checkpoint) { + ExecutionContext exe_ctx(CalculateThread()); + + Process *process = exe_ctx.GetProcessPtr(); + Thread *thread = exe_ctx.GetThreadPtr(); + if (process == NULL || thread == NULL) return false; + + GDBRemoteCommunicationClient &gdb_comm( + ((ProcessGDBRemote *)process)->GetGDBRemote()); + + uint32_t save_id = 0; + if (gdb_comm.SaveRegisterState(thread->GetProtocolID(), save_id)) { + reg_checkpoint.SetID(save_id); + reg_checkpoint.GetData().reset(); + return true; + } else { + reg_checkpoint.SetID(0); // Invalid save ID is zero + return ReadAllRegisterValues(reg_checkpoint.GetData()); + } } -bool -GDBRemoteRegisterContext::ReadAllRegisterValues (RegisterCheckpoint ®_checkpoint) -{ - ExecutionContext exe_ctx (CalculateThread()); - +bool GDBRemoteRegisterContext::WriteAllRegisterValues( + const RegisterCheckpoint ®_checkpoint) { + uint32_t save_id = reg_checkpoint.GetID(); + if (save_id != 0) { + ExecutionContext exe_ctx(CalculateThread()); + Process *process = exe_ctx.GetProcessPtr(); Thread *thread = exe_ctx.GetThreadPtr(); if (process == NULL || thread == NULL) - return false; - - GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote()); - - uint32_t save_id = 0; - if (gdb_comm.SaveRegisterState(thread->GetProtocolID(), save_id)) - { - reg_checkpoint.SetID(save_id); - reg_checkpoint.GetData().reset(); - return true; - } - else - { - reg_checkpoint.SetID(0); // Invalid save ID is zero - return ReadAllRegisterValues(reg_checkpoint.GetData()); - } -} + return false; -bool -GDBRemoteRegisterContext::WriteAllRegisterValues (const RegisterCheckpoint ®_checkpoint) -{ - uint32_t save_id = reg_checkpoint.GetID(); - if (save_id != 0) - { - ExecutionContext exe_ctx (CalculateThread()); - - Process *process = exe_ctx.GetProcessPtr(); - Thread *thread = exe_ctx.GetThreadPtr(); - if (process == NULL || thread == NULL) - return false; - - GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote()); - - return gdb_comm.RestoreRegisterState(m_thread.GetProtocolID(), save_id); - } - else - { - return WriteAllRegisterValues(reg_checkpoint.GetData()); - } + GDBRemoteCommunicationClient &gdb_comm( + ((ProcessGDBRemote *)process)->GetGDBRemote()); + + return gdb_comm.RestoreRegisterState(m_thread.GetProtocolID(), save_id); + } else { + return WriteAllRegisterValues(reg_checkpoint.GetData()); + } } -bool -GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) -{ - ExecutionContext exe_ctx (CalculateThread()); +bool GDBRemoteRegisterContext::ReadAllRegisterValues( + lldb::DataBufferSP &data_sp) { + ExecutionContext exe_ctx(CalculateThread()); - Process *process = exe_ctx.GetProcessPtr(); - Thread *thread = exe_ctx.GetThreadPtr(); - if (process == NULL || thread == NULL) - return false; + Process *process = exe_ctx.GetProcessPtr(); + Thread *thread = exe_ctx.GetThreadPtr(); + if (process == NULL || thread == NULL) + return false; - GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote()); + GDBRemoteCommunicationClient &gdb_comm( + ((ProcessGDBRemote *)process)->GetGDBRemote()); - StringExtractorGDBRemote response; + const bool use_g_packet = + gdb_comm.AvoidGPackets((ProcessGDBRemote *)process) == false; - const bool use_g_packet = gdb_comm.AvoidGPackets ((ProcessGDBRemote *)process) == false; + GDBRemoteClientBase::Lock lock(gdb_comm, false); + if (lock) { + if (gdb_comm.SyncThreadState(m_thread.GetProtocolID())) + InvalidateAllRegisters(); - Mutex::Locker locker; - if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for read all registers.")) - { - SyncThreadState(process); - - char packet[32]; - const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported(); - ProcessSP process_sp (m_thread.GetProcess()); - if (thread_suffix_supported || static_cast<ProcessGDBRemote *>(process_sp.get())->GetGDBRemote().SetCurrentThread(m_thread.GetProtocolID())) - { - int packet_len = 0; - if (thread_suffix_supported) - packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4" PRIx64, m_thread.GetProtocolID()); - else - packet_len = ::snprintf (packet, sizeof(packet), "g"); - assert (packet_len < ((int)sizeof(packet) - 1)); - - if (use_g_packet && gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false) == GDBRemoteCommunication::PacketResult::Success) - { - int packet_len = 0; - if (thread_suffix_supported) - packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4" PRIx64, m_thread.GetProtocolID()); - else - packet_len = ::snprintf (packet, sizeof(packet), "g"); - assert (packet_len < ((int)sizeof(packet) - 1)); - - if (gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false) == GDBRemoteCommunication::PacketResult::Success) - { - if (response.IsErrorResponse()) - return false; - - std::string &response_str = response.GetStringRef(); - if (isxdigit(response_str[0])) - { - response_str.insert(0, 1, 'G'); - if (thread_suffix_supported) - { - char thread_id_cstr[64]; - ::snprintf (thread_id_cstr, sizeof(thread_id_cstr), ";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID()); - response_str.append (thread_id_cstr); - } - data_sp.reset (new DataBufferHeap (response_str.c_str(), response_str.size())); - return true; - } - } - } - else - { - // For the use_g_packet == false case, we're going to read each register - // individually and store them as binary data in a buffer instead of as ascii - // characters. - const RegisterInfo *reg_info; - - // data_sp will take ownership of this DataBufferHeap pointer soon. - DataBufferSP reg_ctx(new DataBufferHeap(m_reg_info.GetRegisterDataByteSize(), 0)); - - for (uint32_t i = 0; (reg_info = GetRegisterInfoAtIndex (i)) != NULL; i++) - { - if (reg_info->value_regs) // skip registers that are slices of real registers - continue; - ReadRegisterBytes (reg_info, m_reg_data); - // ReadRegisterBytes saves the contents of the register in to the m_reg_data buffer - } - memcpy (reg_ctx->GetBytes(), m_reg_data.GetDataStart(), m_reg_info.GetRegisterDataByteSize()); - - data_sp = reg_ctx; - return true; - } - } - } - else - { + if (use_g_packet && + (data_sp = gdb_comm.ReadAllRegisters(m_thread.GetProtocolID()))) + return true; - Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_THREAD | GDBR_LOG_PACKETS)); - if (log) - { - if (log->GetVerbose()) - { - StreamString strm; - gdb_comm.DumpHistory(strm); - log->Printf("error: failed to get packet sequence mutex, not sending read all registers:\n%s", strm.GetData()); - } - else - log->Printf("error: failed to get packet sequence mutex, not sending read all registers"); - } + // We're going to read each register + // individually and store them as binary data in a buffer. + const RegisterInfo *reg_info; + + for (uint32_t i = 0; (reg_info = GetRegisterInfoAtIndex(i)) != NULL; i++) { + if (reg_info + ->value_regs) // skip registers that are slices of real registers + continue; + ReadRegisterBytes(reg_info, m_reg_data); + // ReadRegisterBytes saves the contents of the register in to the + // m_reg_data buffer } + data_sp.reset(new DataBufferHeap(m_reg_data.GetDataStart(), + m_reg_info.GetRegisterDataByteSize())); + return true; + } else { + + Log *log(ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(GDBR_LOG_THREAD | + GDBR_LOG_PACKETS)); + if (log) { + if (log->GetVerbose()) { + StreamString strm; + gdb_comm.DumpHistory(strm); + log->Printf("error: failed to get packet sequence mutex, not sending " + "read all registers:\n%s", + strm.GetData()); + } else + log->Printf("error: failed to get packet sequence mutex, not sending " + "read all registers"); + } + } - data_sp.reset(); - return false; + data_sp.reset(); + return false; } -bool -GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) -{ - if (!data_sp || data_sp->GetBytes() == NULL || data_sp->GetByteSize() == 0) - return false; +bool GDBRemoteRegisterContext::WriteAllRegisterValues( + const lldb::DataBufferSP &data_sp) { + if (!data_sp || data_sp->GetBytes() == NULL || data_sp->GetByteSize() == 0) + return false; - ExecutionContext exe_ctx (CalculateThread()); + ExecutionContext exe_ctx(CalculateThread()); - Process *process = exe_ctx.GetProcessPtr(); - Thread *thread = exe_ctx.GetThreadPtr(); - if (process == NULL || thread == NULL) - return false; + Process *process = exe_ctx.GetProcessPtr(); + Thread *thread = exe_ctx.GetThreadPtr(); + if (process == NULL || thread == NULL) + return false; - GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote()); + GDBRemoteCommunicationClient &gdb_comm( + ((ProcessGDBRemote *)process)->GetGDBRemote()); - const bool use_g_packet = gdb_comm.AvoidGPackets ((ProcessGDBRemote *)process) == false; + const bool use_g_packet = + gdb_comm.AvoidGPackets((ProcessGDBRemote *)process) == false; - StringExtractorGDBRemote response; - Mutex::Locker locker; - if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for write all registers.")) - { - const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported(); - ProcessSP process_sp (m_thread.GetProcess()); - if (thread_suffix_supported || static_cast<ProcessGDBRemote *>(process_sp.get())->GetGDBRemote().SetCurrentThread(m_thread.GetProtocolID())) - { - // The data_sp contains the entire G response packet including the - // G, and if the thread suffix is supported, it has the thread suffix - // as well. - const char *G_packet = (const char *)data_sp->GetBytes(); - size_t G_packet_len = data_sp->GetByteSize(); - if (use_g_packet - && gdb_comm.SendPacketAndWaitForResponse (G_packet, - G_packet_len, - response, - false) == GDBRemoteCommunication::PacketResult::Success) - { - // The data_sp contains the entire G response packet including the - // G, and if the thread suffix is supported, it has the thread suffix - // as well. - const char *G_packet = (const char *)data_sp->GetBytes(); - size_t G_packet_len = data_sp->GetByteSize(); - if (gdb_comm.SendPacketAndWaitForResponse (G_packet, - G_packet_len, - response, - false) == GDBRemoteCommunication::PacketResult::Success) - { - if (response.IsOKResponse()) - return true; - else if (response.IsErrorResponse()) - { - uint32_t num_restored = 0; - // We need to manually go through all of the registers and - // restore them manually - - response.GetStringRef().assign (G_packet, G_packet_len); - response.SetFilePos(1); // Skip the leading 'G' - - // G_packet_len is hex-ascii characters plus prefix 'G' plus suffix thread specifier. - // This means buffer will be a little more than 2x larger than necessary but we resize - // it down once we've extracted all hex ascii chars from the packet. - DataBufferHeap buffer (G_packet_len, 0); - - const uint32_t bytes_extracted = response.GetHexBytes (buffer.GetBytes(), - buffer.GetByteSize(), - '\xcc'); - - DataExtractor restore_data (buffer.GetBytes(), - buffer.GetByteSize(), - m_reg_data.GetByteOrder(), - m_reg_data.GetAddressByteSize()); - - if (bytes_extracted < restore_data.GetByteSize()) - restore_data.SetData(restore_data.GetDataStart(), bytes_extracted, m_reg_data.GetByteOrder()); - - const RegisterInfo *reg_info; - - // The g packet contents may either include the slice registers (registers defined in - // terms of other registers, e.g. eax is a subset of rax) or not. The slice registers - // should NOT be in the g packet, but some implementations may incorrectly include them. - // - // If the slice registers are included in the packet, we must step over the slice registers - // when parsing the packet -- relying on the RegisterInfo byte_offset field would be incorrect. - // If the slice registers are not included, then using the byte_offset values into the - // data buffer is the best way to find individual register values. - - uint64_t size_including_slice_registers = 0; - uint64_t size_not_including_slice_registers = 0; - uint64_t size_by_highest_offset = 0; - - for (uint32_t reg_idx=0; (reg_info = GetRegisterInfoAtIndex (reg_idx)) != NULL; ++reg_idx) - { - size_including_slice_registers += reg_info->byte_size; - if (reg_info->value_regs == NULL) - size_not_including_slice_registers += reg_info->byte_size; - if (reg_info->byte_offset >= size_by_highest_offset) - size_by_highest_offset = reg_info->byte_offset + reg_info->byte_size; - } - - bool use_byte_offset_into_buffer; - if (size_by_highest_offset == restore_data.GetByteSize()) - { - // The size of the packet agrees with the highest offset: + size in the register file - use_byte_offset_into_buffer = true; - } - else if (size_not_including_slice_registers == restore_data.GetByteSize()) - { - // The size of the packet is the same as concatenating all of the registers sequentially, - // skipping the slice registers - use_byte_offset_into_buffer = true; - } - else if (size_including_slice_registers == restore_data.GetByteSize()) - { - // The slice registers are present in the packet (when they shouldn't be). - // Don't try to use the RegisterInfo byte_offset into the restore_data, it will - // point to the wrong place. - use_byte_offset_into_buffer = false; - } - else { - // None of our expected sizes match the actual g packet data we're looking at. - // The most conservative approach here is to use the running total byte offset. - use_byte_offset_into_buffer = false; - } - - // In case our register definitions don't include the correct offsets, - // keep track of the size of each reg & compute offset based on that. - uint32_t running_byte_offset = 0; - for (uint32_t reg_idx=0; (reg_info = GetRegisterInfoAtIndex (reg_idx)) != NULL; ++reg_idx, running_byte_offset += reg_info->byte_size) - { - // Skip composite aka slice registers (e.g. eax is a slice of rax). - if (reg_info->value_regs) - continue; - - const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - - uint32_t register_offset; - if (use_byte_offset_into_buffer) - { - register_offset = reg_info->byte_offset; - } - else - { - register_offset = running_byte_offset; - } - - // Only write down the registers that need to be written - // if we are going to be doing registers individually. - bool write_reg = true; - const uint32_t reg_byte_size = reg_info->byte_size; - - const char *restore_src = (const char *)restore_data.PeekData(register_offset, reg_byte_size); - if (restore_src) - { - StreamString packet; - packet.Printf ("P%x=", reg_info->kinds[eRegisterKindProcessPlugin]); - packet.PutBytesAsRawHex8 (restore_src, - reg_byte_size, - endian::InlHostByteOrder(), - endian::InlHostByteOrder()); - - if (thread_suffix_supported) - packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID()); - - SetRegisterIsValid(reg, false); - if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), - packet.GetString().size(), - response, - false) == GDBRemoteCommunication::PacketResult::Success) - { - const char *current_src = (const char *)m_reg_data.PeekData(register_offset, reg_byte_size); - if (current_src) - write_reg = memcmp (current_src, restore_src, reg_byte_size) != 0; - } - - if (write_reg) - { - StreamString packet; - packet.Printf ("P%x=", reg_info->kinds[eRegisterKindProcessPlugin]); - packet.PutBytesAsRawHex8 (restore_src, - reg_byte_size, - endian::InlHostByteOrder(), - endian::InlHostByteOrder()); - - if (thread_suffix_supported) - packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID()); - - SetRegisterIsValid(reg, false); - if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), - packet.GetString().size(), - response, - false) == GDBRemoteCommunication::PacketResult::Success) - { - if (response.IsOKResponse()) - ++num_restored; - } - } - } - } - return num_restored > 0; - } - } - } - else - { - // For the use_g_packet == false case, we're going to write each register - // individually. The data buffer is binary data in this case, instead of - // ascii characters. - - bool arm64_debugserver = false; - if (m_thread.GetProcess().get()) - { - const ArchSpec &arch = m_thread.GetProcess()->GetTarget().GetArchitecture(); - if (arch.IsValid() - && arch.GetMachine() == llvm::Triple::aarch64 - && arch.GetTriple().getVendor() == llvm::Triple::Apple - && arch.GetTriple().getOS() == llvm::Triple::IOS) - { - arm64_debugserver = true; - } - } - uint32_t num_restored = 0; - const RegisterInfo *reg_info; - for (uint32_t i = 0; (reg_info = GetRegisterInfoAtIndex (i)) != NULL; i++) - { - if (reg_info->value_regs) // skip registers that are slices of real registers - continue; - // Skip the fpsr and fpcr floating point status/control register writing to - // work around a bug in an older version of debugserver that would lead to - // register context corruption when writing fpsr/fpcr. - if (arm64_debugserver && - (strcmp (reg_info->name, "fpsr") == 0 || strcmp (reg_info->name, "fpcr") == 0)) - { - continue; - } - StreamString packet; - packet.Printf ("P%x=", reg_info->kinds[eRegisterKindProcessPlugin]); - packet.PutBytesAsRawHex8 (data_sp->GetBytes() + reg_info->byte_offset, reg_info->byte_size, endian::InlHostByteOrder(), endian::InlHostByteOrder()); - if (thread_suffix_supported) - packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID()); - - SetRegisterIsValid(reg_info, false); - if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), - packet.GetString().size(), - response, - false) == GDBRemoteCommunication::PacketResult::Success) - { - if (response.IsOKResponse()) - ++num_restored; - } - } - return num_restored > 0; - } + GDBRemoteClientBase::Lock lock(gdb_comm, false); + if (lock) { + // The data_sp contains the G response packet. + if (use_g_packet) { + if (gdb_comm.WriteAllRegisters( + m_thread.GetProtocolID(), + {data_sp->GetBytes(), size_t(data_sp->GetByteSize())})) + return true; + + uint32_t num_restored = 0; + // We need to manually go through all of the registers and + // restore them manually + DataExtractor restore_data(data_sp, m_reg_data.GetByteOrder(), + m_reg_data.GetAddressByteSize()); + + const RegisterInfo *reg_info; + + // The g packet contents may either include the slice registers (registers + // defined in + // terms of other registers, e.g. eax is a subset of rax) or not. The + // slice registers + // should NOT be in the g packet, but some implementations may incorrectly + // include them. + // + // If the slice registers are included in the packet, we must step over + // the slice registers + // when parsing the packet -- relying on the RegisterInfo byte_offset + // field would be incorrect. + // If the slice registers are not included, then using the byte_offset + // values into the + // data buffer is the best way to find individual register values. + + uint64_t size_including_slice_registers = 0; + uint64_t size_not_including_slice_registers = 0; + uint64_t size_by_highest_offset = 0; + + for (uint32_t reg_idx = 0; + (reg_info = GetRegisterInfoAtIndex(reg_idx)) != NULL; ++reg_idx) { + size_including_slice_registers += reg_info->byte_size; + if (reg_info->value_regs == NULL) + size_not_including_slice_registers += reg_info->byte_size; + if (reg_info->byte_offset >= size_by_highest_offset) + size_by_highest_offset = reg_info->byte_offset + reg_info->byte_size; + } + + bool use_byte_offset_into_buffer; + if (size_by_highest_offset == restore_data.GetByteSize()) { + // The size of the packet agrees with the highest offset: + size in the + // register file + use_byte_offset_into_buffer = true; + } else if (size_not_including_slice_registers == + restore_data.GetByteSize()) { + // The size of the packet is the same as concatenating all of the + // registers sequentially, + // skipping the slice registers + use_byte_offset_into_buffer = true; + } else if (size_including_slice_registers == restore_data.GetByteSize()) { + // The slice registers are present in the packet (when they shouldn't + // be). + // Don't try to use the RegisterInfo byte_offset into the restore_data, + // it will + // point to the wrong place. + use_byte_offset_into_buffer = false; + } else { + // None of our expected sizes match the actual g packet data we're + // looking at. + // The most conservative approach here is to use the running total byte + // offset. + use_byte_offset_into_buffer = false; + } + + // In case our register definitions don't include the correct offsets, + // keep track of the size of each reg & compute offset based on that. + uint32_t running_byte_offset = 0; + for (uint32_t reg_idx = 0; + (reg_info = GetRegisterInfoAtIndex(reg_idx)) != NULL; + ++reg_idx, running_byte_offset += reg_info->byte_size) { + // Skip composite aka slice registers (e.g. eax is a slice of rax). + if (reg_info->value_regs) + continue; + + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + + uint32_t register_offset; + if (use_byte_offset_into_buffer) { + register_offset = reg_info->byte_offset; + } else { + register_offset = running_byte_offset; } - } - else - { - Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_THREAD | GDBR_LOG_PACKETS)); - if (log) - { - if (log->GetVerbose()) - { - StreamString strm; - gdb_comm.DumpHistory(strm); - log->Printf("error: failed to get packet sequence mutex, not sending write all registers:\n%s", strm.GetData()); - } - else - log->Printf("error: failed to get packet sequence mutex, not sending write all registers"); + + const uint32_t reg_byte_size = reg_info->byte_size; + + const uint8_t *restore_src = + restore_data.PeekData(register_offset, reg_byte_size); + if (restore_src) { + SetRegisterIsValid(reg, false); + if (gdb_comm.WriteRegister( + m_thread.GetProtocolID(), + reg_info->kinds[eRegisterKindProcessPlugin], + {restore_src, reg_byte_size})) + ++num_restored; + } + } + return num_restored > 0; + } else { + // For the use_g_packet == false case, we're going to write each register + // individually. The data buffer is binary data in this case, instead of + // ascii characters. + + bool arm64_debugserver = false; + if (m_thread.GetProcess().get()) { + const ArchSpec &arch = + m_thread.GetProcess()->GetTarget().GetArchitecture(); + if (arch.IsValid() && arch.GetMachine() == llvm::Triple::aarch64 && + arch.GetTriple().getVendor() == llvm::Triple::Apple && + arch.GetTriple().getOS() == llvm::Triple::IOS) { + arm64_debugserver = true; } + } + uint32_t num_restored = 0; + const RegisterInfo *reg_info; + for (uint32_t i = 0; (reg_info = GetRegisterInfoAtIndex(i)) != NULL; + i++) { + if (reg_info->value_regs) // skip registers that are slices of real + // registers + continue; + // Skip the fpsr and fpcr floating point status/control register writing + // to + // work around a bug in an older version of debugserver that would lead + // to + // register context corruption when writing fpsr/fpcr. + if (arm64_debugserver && (strcmp(reg_info->name, "fpsr") == 0 || + strcmp(reg_info->name, "fpcr") == 0)) { + continue; + } + + SetRegisterIsValid(reg_info, false); + if (gdb_comm.WriteRegister(m_thread.GetProtocolID(), + reg_info->kinds[eRegisterKindProcessPlugin], + {data_sp->GetBytes() + reg_info->byte_offset, + reg_info->byte_size})) + ++num_restored; + } + return num_restored > 0; } - return false; + } else { + Log *log(ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(GDBR_LOG_THREAD | + GDBR_LOG_PACKETS)); + if (log) { + if (log->GetVerbose()) { + StreamString strm; + gdb_comm.DumpHistory(strm); + log->Printf("error: failed to get packet sequence mutex, not sending " + "write all registers:\n%s", + strm.GetData()); + } else + log->Printf("error: failed to get packet sequence mutex, not sending " + "write all registers"); + } + } + return false; } - -uint32_t -GDBRemoteRegisterContext::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num) -{ - return m_reg_info.ConvertRegisterKindToRegisterNumber (kind, num); +uint32_t GDBRemoteRegisterContext::ConvertRegisterKindToRegisterNumber( + lldb::RegisterKind kind, uint32_t num) { + return m_reg_info.ConvertRegisterKindToRegisterNumber(kind, num); } - -void -GDBRemoteDynamicRegisterInfo::HardcodeARMRegisters(bool from_scratch) -{ - // For Advanced SIMD and VFP register mapping. - static uint32_t g_d0_regs[] = { 26, 27, LLDB_INVALID_REGNUM }; // (s0, s1) - static uint32_t g_d1_regs[] = { 28, 29, LLDB_INVALID_REGNUM }; // (s2, s3) - static uint32_t g_d2_regs[] = { 30, 31, LLDB_INVALID_REGNUM }; // (s4, s5) - static uint32_t g_d3_regs[] = { 32, 33, LLDB_INVALID_REGNUM }; // (s6, s7) - static uint32_t g_d4_regs[] = { 34, 35, LLDB_INVALID_REGNUM }; // (s8, s9) - static uint32_t g_d5_regs[] = { 36, 37, LLDB_INVALID_REGNUM }; // (s10, s11) - static uint32_t g_d6_regs[] = { 38, 39, LLDB_INVALID_REGNUM }; // (s12, s13) - static uint32_t g_d7_regs[] = { 40, 41, LLDB_INVALID_REGNUM }; // (s14, s15) - static uint32_t g_d8_regs[] = { 42, 43, LLDB_INVALID_REGNUM }; // (s16, s17) - static uint32_t g_d9_regs[] = { 44, 45, LLDB_INVALID_REGNUM }; // (s18, s19) - static uint32_t g_d10_regs[] = { 46, 47, LLDB_INVALID_REGNUM }; // (s20, s21) - static uint32_t g_d11_regs[] = { 48, 49, LLDB_INVALID_REGNUM }; // (s22, s23) - static uint32_t g_d12_regs[] = { 50, 51, LLDB_INVALID_REGNUM }; // (s24, s25) - static uint32_t g_d13_regs[] = { 52, 53, LLDB_INVALID_REGNUM }; // (s26, s27) - static uint32_t g_d14_regs[] = { 54, 55, LLDB_INVALID_REGNUM }; // (s28, s29) - static uint32_t g_d15_regs[] = { 56, 57, LLDB_INVALID_REGNUM }; // (s30, s31) - static uint32_t g_q0_regs[] = { 26, 27, 28, 29, LLDB_INVALID_REGNUM }; // (d0, d1) -> (s0, s1, s2, s3) - static uint32_t g_q1_regs[] = { 30, 31, 32, 33, LLDB_INVALID_REGNUM }; // (d2, d3) -> (s4, s5, s6, s7) - static uint32_t g_q2_regs[] = { 34, 35, 36, 37, LLDB_INVALID_REGNUM }; // (d4, d5) -> (s8, s9, s10, s11) - static uint32_t g_q3_regs[] = { 38, 39, 40, 41, LLDB_INVALID_REGNUM }; // (d6, d7) -> (s12, s13, s14, s15) - static uint32_t g_q4_regs[] = { 42, 43, 44, 45, LLDB_INVALID_REGNUM }; // (d8, d9) -> (s16, s17, s18, s19) - static uint32_t g_q5_regs[] = { 46, 47, 48, 49, LLDB_INVALID_REGNUM }; // (d10, d11) -> (s20, s21, s22, s23) - static uint32_t g_q6_regs[] = { 50, 51, 52, 53, LLDB_INVALID_REGNUM }; // (d12, d13) -> (s24, s25, s26, s27) - static uint32_t g_q7_regs[] = { 54, 55, 56, 57, LLDB_INVALID_REGNUM }; // (d14, d15) -> (s28, s29, s30, s31) - static uint32_t g_q8_regs[] = { 59, 60, LLDB_INVALID_REGNUM }; // (d16, d17) - static uint32_t g_q9_regs[] = { 61, 62, LLDB_INVALID_REGNUM }; // (d18, d19) - static uint32_t g_q10_regs[] = { 63, 64, LLDB_INVALID_REGNUM }; // (d20, d21) - static uint32_t g_q11_regs[] = { 65, 66, LLDB_INVALID_REGNUM }; // (d22, d23) - static uint32_t g_q12_regs[] = { 67, 68, LLDB_INVALID_REGNUM }; // (d24, d25) - static uint32_t g_q13_regs[] = { 69, 70, LLDB_INVALID_REGNUM }; // (d26, d27) - static uint32_t g_q14_regs[] = { 71, 72, LLDB_INVALID_REGNUM }; // (d28, d29) - static uint32_t g_q15_regs[] = { 73, 74, LLDB_INVALID_REGNUM }; // (d30, d31) - - // This is our array of composite registers, with each element coming from the above register mappings. - static uint32_t *g_composites[] = { - g_d0_regs, g_d1_regs, g_d2_regs, g_d3_regs, g_d4_regs, g_d5_regs, g_d6_regs, g_d7_regs, - g_d8_regs, g_d9_regs, g_d10_regs, g_d11_regs, g_d12_regs, g_d13_regs, g_d14_regs, g_d15_regs, - g_q0_regs, g_q1_regs, g_q2_regs, g_q3_regs, g_q4_regs, g_q5_regs, g_q6_regs, g_q7_regs, - g_q8_regs, g_q9_regs, g_q10_regs, g_q11_regs, g_q12_regs, g_q13_regs, g_q14_regs, g_q15_regs - }; - +void GDBRemoteDynamicRegisterInfo::HardcodeARMRegisters(bool from_scratch) { + // For Advanced SIMD and VFP register mapping. + static uint32_t g_d0_regs[] = {26, 27, LLDB_INVALID_REGNUM}; // (s0, s1) + static uint32_t g_d1_regs[] = {28, 29, LLDB_INVALID_REGNUM}; // (s2, s3) + static uint32_t g_d2_regs[] = {30, 31, LLDB_INVALID_REGNUM}; // (s4, s5) + static uint32_t g_d3_regs[] = {32, 33, LLDB_INVALID_REGNUM}; // (s6, s7) + static uint32_t g_d4_regs[] = {34, 35, LLDB_INVALID_REGNUM}; // (s8, s9) + static uint32_t g_d5_regs[] = {36, 37, LLDB_INVALID_REGNUM}; // (s10, s11) + static uint32_t g_d6_regs[] = {38, 39, LLDB_INVALID_REGNUM}; // (s12, s13) + static uint32_t g_d7_regs[] = {40, 41, LLDB_INVALID_REGNUM}; // (s14, s15) + static uint32_t g_d8_regs[] = {42, 43, LLDB_INVALID_REGNUM}; // (s16, s17) + static uint32_t g_d9_regs[] = {44, 45, LLDB_INVALID_REGNUM}; // (s18, s19) + static uint32_t g_d10_regs[] = {46, 47, LLDB_INVALID_REGNUM}; // (s20, s21) + static uint32_t g_d11_regs[] = {48, 49, LLDB_INVALID_REGNUM}; // (s22, s23) + static uint32_t g_d12_regs[] = {50, 51, LLDB_INVALID_REGNUM}; // (s24, s25) + static uint32_t g_d13_regs[] = {52, 53, LLDB_INVALID_REGNUM}; // (s26, s27) + static uint32_t g_d14_regs[] = {54, 55, LLDB_INVALID_REGNUM}; // (s28, s29) + static uint32_t g_d15_regs[] = {56, 57, LLDB_INVALID_REGNUM}; // (s30, s31) + static uint32_t g_q0_regs[] = { + 26, 27, 28, 29, LLDB_INVALID_REGNUM}; // (d0, d1) -> (s0, s1, s2, s3) + static uint32_t g_q1_regs[] = { + 30, 31, 32, 33, LLDB_INVALID_REGNUM}; // (d2, d3) -> (s4, s5, s6, s7) + static uint32_t g_q2_regs[] = { + 34, 35, 36, 37, LLDB_INVALID_REGNUM}; // (d4, d5) -> (s8, s9, s10, s11) + static uint32_t g_q3_regs[] = { + 38, 39, 40, 41, LLDB_INVALID_REGNUM}; // (d6, d7) -> (s12, s13, s14, s15) + static uint32_t g_q4_regs[] = { + 42, 43, 44, 45, LLDB_INVALID_REGNUM}; // (d8, d9) -> (s16, s17, s18, s19) + static uint32_t g_q5_regs[] = { + 46, 47, 48, 49, + LLDB_INVALID_REGNUM}; // (d10, d11) -> (s20, s21, s22, s23) + static uint32_t g_q6_regs[] = { + 50, 51, 52, 53, + LLDB_INVALID_REGNUM}; // (d12, d13) -> (s24, s25, s26, s27) + static uint32_t g_q7_regs[] = { + 54, 55, 56, 57, + LLDB_INVALID_REGNUM}; // (d14, d15) -> (s28, s29, s30, s31) + static uint32_t g_q8_regs[] = {59, 60, LLDB_INVALID_REGNUM}; // (d16, d17) + static uint32_t g_q9_regs[] = {61, 62, LLDB_INVALID_REGNUM}; // (d18, d19) + static uint32_t g_q10_regs[] = {63, 64, LLDB_INVALID_REGNUM}; // (d20, d21) + static uint32_t g_q11_regs[] = {65, 66, LLDB_INVALID_REGNUM}; // (d22, d23) + static uint32_t g_q12_regs[] = {67, 68, LLDB_INVALID_REGNUM}; // (d24, d25) + static uint32_t g_q13_regs[] = {69, 70, LLDB_INVALID_REGNUM}; // (d26, d27) + static uint32_t g_q14_regs[] = {71, 72, LLDB_INVALID_REGNUM}; // (d28, d29) + static uint32_t g_q15_regs[] = {73, 74, LLDB_INVALID_REGNUM}; // (d30, d31) + + // This is our array of composite registers, with each element coming from the + // above register mappings. + static uint32_t *g_composites[] = { + g_d0_regs, g_d1_regs, g_d2_regs, g_d3_regs, g_d4_regs, g_d5_regs, + g_d6_regs, g_d7_regs, g_d8_regs, g_d9_regs, g_d10_regs, g_d11_regs, + g_d12_regs, g_d13_regs, g_d14_regs, g_d15_regs, g_q0_regs, g_q1_regs, + g_q2_regs, g_q3_regs, g_q4_regs, g_q5_regs, g_q6_regs, g_q7_regs, + g_q8_regs, g_q9_regs, g_q10_regs, g_q11_regs, g_q12_regs, g_q13_regs, + g_q14_regs, g_q15_regs}; + + // clang-format off static RegisterInfo g_register_infos[] = { -// NAME ALT SZ OFF ENCODING FORMAT EH_FRAME DWARF GENERIC PROCESS PLUGIN LLDB VALUE REGS INVALIDATE REGS -// ====== ====== === === ============= ============ =================== =================== ====================== ============= ==== ========== =============== - { "r0", "arg1", 4, 0, eEncodingUint, eFormatHex, { ehframe_r0, dwarf_r0, LLDB_REGNUM_GENERIC_ARG1,0, 0 }, NULL, NULL}, - { "r1", "arg2", 4, 0, eEncodingUint, eFormatHex, { ehframe_r1, dwarf_r1, LLDB_REGNUM_GENERIC_ARG2,1, 1 }, NULL, NULL}, - { "r2", "arg3", 4, 0, eEncodingUint, eFormatHex, { ehframe_r2, dwarf_r2, LLDB_REGNUM_GENERIC_ARG3,2, 2 }, NULL, NULL}, - { "r3", "arg4", 4, 0, eEncodingUint, eFormatHex, { ehframe_r3, dwarf_r3, LLDB_REGNUM_GENERIC_ARG4,3, 3 }, NULL, NULL}, - { "r4", NULL, 4, 0, eEncodingUint, eFormatHex, { ehframe_r4, dwarf_r4, LLDB_INVALID_REGNUM, 4, 4 }, NULL, NULL}, - { "r5", NULL, 4, 0, eEncodingUint, eFormatHex, { ehframe_r5, dwarf_r5, LLDB_INVALID_REGNUM, 5, 5 }, NULL, NULL}, - { "r6", NULL, 4, 0, eEncodingUint, eFormatHex, { ehframe_r6, dwarf_r6, LLDB_INVALID_REGNUM, 6, 6 }, NULL, NULL}, - { "r7", "fp", 4, 0, eEncodingUint, eFormatHex, { ehframe_r7, dwarf_r7, LLDB_REGNUM_GENERIC_FP, 7, 7 }, NULL, NULL}, - { "r8", NULL, 4, 0, eEncodingUint, eFormatHex, { ehframe_r8, dwarf_r8, LLDB_INVALID_REGNUM, 8, 8 }, NULL, NULL}, - { "r9", NULL, 4, 0, eEncodingUint, eFormatHex, { ehframe_r9, dwarf_r9, LLDB_INVALID_REGNUM, 9, 9 }, NULL, NULL}, - { "r10", NULL, 4, 0, eEncodingUint, eFormatHex, { ehframe_r10, dwarf_r10, LLDB_INVALID_REGNUM, 10, 10 }, NULL, NULL}, - { "r11", NULL, 4, 0, eEncodingUint, eFormatHex, { ehframe_r11, dwarf_r11, LLDB_INVALID_REGNUM, 11, 11 }, NULL, NULL}, - { "r12", NULL, 4, 0, eEncodingUint, eFormatHex, { ehframe_r12, dwarf_r12, LLDB_INVALID_REGNUM, 12, 12 }, NULL, NULL}, - { "sp", "r13", 4, 0, eEncodingUint, eFormatHex, { ehframe_sp, dwarf_sp, LLDB_REGNUM_GENERIC_SP, 13, 13 }, NULL, NULL}, - { "lr", "r14", 4, 0, eEncodingUint, eFormatHex, { ehframe_lr, dwarf_lr, LLDB_REGNUM_GENERIC_RA, 14, 14 }, NULL, NULL}, - { "pc", "r15", 4, 0, eEncodingUint, eFormatHex, { ehframe_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, 15, 15 }, NULL, NULL}, - { "f0", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 16, 16 }, NULL, NULL}, - { "f1", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 17, 17 }, NULL, NULL}, - { "f2", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 18, 18 }, NULL, NULL}, - { "f3", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 19, 19 }, NULL, NULL}, - { "f4", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 20, 20 }, NULL, NULL}, - { "f5", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 21, 21 }, NULL, NULL}, - { "f6", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 22, 22 }, NULL, NULL}, - { "f7", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 23, 23 }, NULL, NULL}, - { "fps", NULL, 4, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 24, 24 }, NULL, NULL}, - { "cpsr","flags", 4, 0, eEncodingUint, eFormatHex, { ehframe_cpsr, dwarf_cpsr, LLDB_INVALID_REGNUM, 25, 25 }, NULL, NULL}, - { "s0", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s0, LLDB_INVALID_REGNUM, 26, 26 }, NULL, NULL}, - { "s1", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s1, LLDB_INVALID_REGNUM, 27, 27 }, NULL, NULL}, - { "s2", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s2, LLDB_INVALID_REGNUM, 28, 28 }, NULL, NULL}, - { "s3", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s3, LLDB_INVALID_REGNUM, 29, 29 }, NULL, NULL}, - { "s4", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s4, LLDB_INVALID_REGNUM, 30, 30 }, NULL, NULL}, - { "s5", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s5, LLDB_INVALID_REGNUM, 31, 31 }, NULL, NULL}, - { "s6", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s6, LLDB_INVALID_REGNUM, 32, 32 }, NULL, NULL}, - { "s7", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s7, LLDB_INVALID_REGNUM, 33, 33 }, NULL, NULL}, - { "s8", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s8, LLDB_INVALID_REGNUM, 34, 34 }, NULL, NULL}, - { "s9", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s9, LLDB_INVALID_REGNUM, 35, 35 }, NULL, NULL}, - { "s10", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s10, LLDB_INVALID_REGNUM, 36, 36 }, NULL, NULL}, - { "s11", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s11, LLDB_INVALID_REGNUM, 37, 37 }, NULL, NULL}, - { "s12", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s12, LLDB_INVALID_REGNUM, 38, 38 }, NULL, NULL}, - { "s13", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s13, LLDB_INVALID_REGNUM, 39, 39 }, NULL, NULL}, - { "s14", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s14, LLDB_INVALID_REGNUM, 40, 40 }, NULL, NULL}, - { "s15", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s15, LLDB_INVALID_REGNUM, 41, 41 }, NULL, NULL}, - { "s16", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s16, LLDB_INVALID_REGNUM, 42, 42 }, NULL, NULL}, - { "s17", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s17, LLDB_INVALID_REGNUM, 43, 43 }, NULL, NULL}, - { "s18", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s18, LLDB_INVALID_REGNUM, 44, 44 }, NULL, NULL}, - { "s19", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s19, LLDB_INVALID_REGNUM, 45, 45 }, NULL, NULL}, - { "s20", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s20, LLDB_INVALID_REGNUM, 46, 46 }, NULL, NULL}, - { "s21", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s21, LLDB_INVALID_REGNUM, 47, 47 }, NULL, NULL}, - { "s22", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s22, LLDB_INVALID_REGNUM, 48, 48 }, NULL, NULL}, - { "s23", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s23, LLDB_INVALID_REGNUM, 49, 49 }, NULL, NULL}, - { "s24", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s24, LLDB_INVALID_REGNUM, 50, 50 }, NULL, NULL}, - { "s25", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s25, LLDB_INVALID_REGNUM, 51, 51 }, NULL, NULL}, - { "s26", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s26, LLDB_INVALID_REGNUM, 52, 52 }, NULL, NULL}, - { "s27", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s27, LLDB_INVALID_REGNUM, 53, 53 }, NULL, NULL}, - { "s28", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s28, LLDB_INVALID_REGNUM, 54, 54 }, NULL, NULL}, - { "s29", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s29, LLDB_INVALID_REGNUM, 55, 55 }, NULL, NULL}, - { "s30", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s30, LLDB_INVALID_REGNUM, 56, 56 }, NULL, NULL}, - { "s31", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s31, LLDB_INVALID_REGNUM, 57, 57 }, NULL, NULL}, - { "fpscr",NULL, 4, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 58, 58 }, NULL, NULL}, - { "d16", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d16, LLDB_INVALID_REGNUM, 59, 59 }, NULL, NULL}, - { "d17", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d17, LLDB_INVALID_REGNUM, 60, 60 }, NULL, NULL}, - { "d18", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d18, LLDB_INVALID_REGNUM, 61, 61 }, NULL, NULL}, - { "d19", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d19, LLDB_INVALID_REGNUM, 62, 62 }, NULL, NULL}, - { "d20", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d20, LLDB_INVALID_REGNUM, 63, 63 }, NULL, NULL}, - { "d21", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d21, LLDB_INVALID_REGNUM, 64, 64 }, NULL, NULL}, - { "d22", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d22, LLDB_INVALID_REGNUM, 65, 65 }, NULL, NULL}, - { "d23", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d23, LLDB_INVALID_REGNUM, 66, 66 }, NULL, NULL}, - { "d24", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d24, LLDB_INVALID_REGNUM, 67, 67 }, NULL, NULL}, - { "d25", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d25, LLDB_INVALID_REGNUM, 68, 68 }, NULL, NULL}, - { "d26", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d26, LLDB_INVALID_REGNUM, 69, 69 }, NULL, NULL}, - { "d27", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d27, LLDB_INVALID_REGNUM, 70, 70 }, NULL, NULL}, - { "d28", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d28, LLDB_INVALID_REGNUM, 71, 71 }, NULL, NULL}, - { "d29", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d29, LLDB_INVALID_REGNUM, 72, 72 }, NULL, NULL}, - { "d30", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d30, LLDB_INVALID_REGNUM, 73, 73 }, NULL, NULL}, - { "d31", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d31, LLDB_INVALID_REGNUM, 74, 74 }, NULL, NULL}, - { "d0", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d0, LLDB_INVALID_REGNUM, 75, 75 }, g_d0_regs, NULL}, - { "d1", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d1, LLDB_INVALID_REGNUM, 76, 76 }, g_d1_regs, NULL}, - { "d2", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d2, LLDB_INVALID_REGNUM, 77, 77 }, g_d2_regs, NULL}, - { "d3", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d3, LLDB_INVALID_REGNUM, 78, 78 }, g_d3_regs, NULL}, - { "d4", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d4, LLDB_INVALID_REGNUM, 79, 79 }, g_d4_regs, NULL}, - { "d5", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d5, LLDB_INVALID_REGNUM, 80, 80 }, g_d5_regs, NULL}, - { "d6", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d6, LLDB_INVALID_REGNUM, 81, 81 }, g_d6_regs, NULL}, - { "d7", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d7, LLDB_INVALID_REGNUM, 82, 82 }, g_d7_regs, NULL}, - { "d8", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d8, LLDB_INVALID_REGNUM, 83, 83 }, g_d8_regs, NULL}, - { "d9", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d9, LLDB_INVALID_REGNUM, 84, 84 }, g_d9_regs, NULL}, - { "d10", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d10, LLDB_INVALID_REGNUM, 85, 85 }, g_d10_regs, NULL}, - { "d11", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d11, LLDB_INVALID_REGNUM, 86, 86 }, g_d11_regs, NULL}, - { "d12", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d12, LLDB_INVALID_REGNUM, 87, 87 }, g_d12_regs, NULL}, - { "d13", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d13, LLDB_INVALID_REGNUM, 88, 88 }, g_d13_regs, NULL}, - { "d14", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d14, LLDB_INVALID_REGNUM, 89, 89 }, g_d14_regs, NULL}, - { "d15", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d15, LLDB_INVALID_REGNUM, 90, 90 }, g_d15_regs, NULL}, - { "q0", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q0, LLDB_INVALID_REGNUM, 91, 91 }, g_q0_regs, NULL}, - { "q1", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q1, LLDB_INVALID_REGNUM, 92, 92 }, g_q1_regs, NULL}, - { "q2", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q2, LLDB_INVALID_REGNUM, 93, 93 }, g_q2_regs, NULL}, - { "q3", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q3, LLDB_INVALID_REGNUM, 94, 94 }, g_q3_regs, NULL}, - { "q4", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q4, LLDB_INVALID_REGNUM, 95, 95 }, g_q4_regs, NULL}, - { "q5", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q5, LLDB_INVALID_REGNUM, 96, 96 }, g_q5_regs, NULL}, - { "q6", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q6, LLDB_INVALID_REGNUM, 97, 97 }, g_q6_regs, NULL}, - { "q7", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q7, LLDB_INVALID_REGNUM, 98, 98 }, g_q7_regs, NULL}, - { "q8", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q8, LLDB_INVALID_REGNUM, 99, 99 }, g_q8_regs, NULL}, - { "q9", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q9, LLDB_INVALID_REGNUM, 100, 100 }, g_q9_regs, NULL}, - { "q10", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q10, LLDB_INVALID_REGNUM, 101, 101 }, g_q10_regs, NULL}, - { "q11", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q11, LLDB_INVALID_REGNUM, 102, 102 }, g_q11_regs, NULL}, - { "q12", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q12, LLDB_INVALID_REGNUM, 103, 103 }, g_q12_regs, NULL}, - { "q13", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q13, LLDB_INVALID_REGNUM, 104, 104 }, g_q13_regs, NULL}, - { "q14", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q14, LLDB_INVALID_REGNUM, 105, 105 }, g_q14_regs, NULL}, - { "q15", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q15, LLDB_INVALID_REGNUM, 106, 106 }, g_q15_regs, NULL} +// NAME ALT SZ OFF ENCODING FORMAT EH_FRAME DWARF GENERIC PROCESS PLUGIN LLDB VALUE REGS INVALIDATE REGS SIZE EXPR SIZE LEN +// ====== ====== === === ============= ========== =================== =================== ====================== ============= ==== ========== =============== ========= ======== + { "r0", "arg1", 4, 0, eEncodingUint, eFormatHex, { ehframe_r0, dwarf_r0, LLDB_REGNUM_GENERIC_ARG1,0, 0 }, nullptr, nullptr, nullptr, 0 }, + { "r1", "arg2", 4, 0, eEncodingUint, eFormatHex, { ehframe_r1, dwarf_r1, LLDB_REGNUM_GENERIC_ARG2,1, 1 }, nullptr, nullptr, nullptr, 0 }, + { "r2", "arg3", 4, 0, eEncodingUint, eFormatHex, { ehframe_r2, dwarf_r2, LLDB_REGNUM_GENERIC_ARG3,2, 2 }, nullptr, nullptr, nullptr, 0 }, + { "r3", "arg4", 4, 0, eEncodingUint, eFormatHex, { ehframe_r3, dwarf_r3, LLDB_REGNUM_GENERIC_ARG4,3, 3 }, nullptr, nullptr, nullptr, 0 }, + { "r4", nullptr, 4, 0, eEncodingUint, eFormatHex, { ehframe_r4, dwarf_r4, LLDB_INVALID_REGNUM, 4, 4 }, nullptr, nullptr, nullptr, 0 }, + { "r5", nullptr, 4, 0, eEncodingUint, eFormatHex, { ehframe_r5, dwarf_r5, LLDB_INVALID_REGNUM, 5, 5 }, nullptr, nullptr, nullptr, 0 }, + { "r6", nullptr, 4, 0, eEncodingUint, eFormatHex, { ehframe_r6, dwarf_r6, LLDB_INVALID_REGNUM, 6, 6 }, nullptr, nullptr, nullptr, 0 }, + { "r7", "fp", 4, 0, eEncodingUint, eFormatHex, { ehframe_r7, dwarf_r7, LLDB_REGNUM_GENERIC_FP, 7, 7 }, nullptr, nullptr, nullptr, 0 }, + { "r8", nullptr, 4, 0, eEncodingUint, eFormatHex, { ehframe_r8, dwarf_r8, LLDB_INVALID_REGNUM, 8, 8 }, nullptr, nullptr, nullptr, 0 }, + { "r9", nullptr, 4, 0, eEncodingUint, eFormatHex, { ehframe_r9, dwarf_r9, LLDB_INVALID_REGNUM, 9, 9 }, nullptr, nullptr, nullptr, 0 }, + { "r10", nullptr, 4, 0, eEncodingUint, eFormatHex, { ehframe_r10, dwarf_r10, LLDB_INVALID_REGNUM, 10, 10 }, nullptr, nullptr, nullptr, 0 }, + { "r11", nullptr, 4, 0, eEncodingUint, eFormatHex, { ehframe_r11, dwarf_r11, LLDB_INVALID_REGNUM, 11, 11 }, nullptr, nullptr, nullptr, 0 }, + { "r12", nullptr, 4, 0, eEncodingUint, eFormatHex, { ehframe_r12, dwarf_r12, LLDB_INVALID_REGNUM, 12, 12 }, nullptr, nullptr, nullptr, 0 }, + { "sp", "r13", 4, 0, eEncodingUint, eFormatHex, { ehframe_sp, dwarf_sp, LLDB_REGNUM_GENERIC_SP, 13, 13 }, nullptr, nullptr, nullptr, 0 }, + { "lr", "r14", 4, 0, eEncodingUint, eFormatHex, { ehframe_lr, dwarf_lr, LLDB_REGNUM_GENERIC_RA, 14, 14 }, nullptr, nullptr, nullptr, 0 }, + { "pc", "r15", 4, 0, eEncodingUint, eFormatHex, { ehframe_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, 15, 15 }, nullptr, nullptr, nullptr, 0 }, + { "f0", nullptr, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 16, 16 }, nullptr, nullptr, nullptr, 0 }, + { "f1", nullptr, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 17, 17 }, nullptr, nullptr, nullptr, 0 }, + { "f2", nullptr, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 18, 18 }, nullptr, nullptr, nullptr, 0 }, + { "f3", nullptr, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 19, 19 }, nullptr, nullptr, nullptr, 0 }, + { "f4", nullptr, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 20, 20 }, nullptr, nullptr, nullptr, 0 }, + { "f5", nullptr, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 21, 21 }, nullptr, nullptr, nullptr, 0 }, + { "f6", nullptr, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 22, 22 }, nullptr, nullptr, nullptr, 0 }, + { "f7", nullptr, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 23, 23 }, nullptr, nullptr, nullptr, 0 }, + { "fps", nullptr, 4, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 24, 24 }, nullptr, nullptr, nullptr, 0 }, + { "cpsr","flags", 4, 0, eEncodingUint, eFormatHex, { ehframe_cpsr, dwarf_cpsr, LLDB_INVALID_REGNUM, 25, 25 }, nullptr, nullptr, nullptr, 0 }, + { "s0", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s0, LLDB_INVALID_REGNUM, 26, 26 }, nullptr, nullptr, nullptr, 0 }, + { "s1", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s1, LLDB_INVALID_REGNUM, 27, 27 }, nullptr, nullptr, nullptr, 0 }, + { "s2", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s2, LLDB_INVALID_REGNUM, 28, 28 }, nullptr, nullptr, nullptr, 0 }, + { "s3", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s3, LLDB_INVALID_REGNUM, 29, 29 }, nullptr, nullptr, nullptr, 0 }, + { "s4", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s4, LLDB_INVALID_REGNUM, 30, 30 }, nullptr, nullptr, nullptr, 0 }, + { "s5", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s5, LLDB_INVALID_REGNUM, 31, 31 }, nullptr, nullptr, nullptr, 0 }, + { "s6", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s6, LLDB_INVALID_REGNUM, 32, 32 }, nullptr, nullptr, nullptr, 0 }, + { "s7", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s7, LLDB_INVALID_REGNUM, 33, 33 }, nullptr, nullptr, nullptr, 0 }, + { "s8", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s8, LLDB_INVALID_REGNUM, 34, 34 }, nullptr, nullptr, nullptr, 0 }, + { "s9", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s9, LLDB_INVALID_REGNUM, 35, 35 }, nullptr, nullptr, nullptr, 0 }, + { "s10", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s10, LLDB_INVALID_REGNUM, 36, 36 }, nullptr, nullptr, nullptr, 0 }, + { "s11", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s11, LLDB_INVALID_REGNUM, 37, 37 }, nullptr, nullptr, nullptr, 0 }, + { "s12", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s12, LLDB_INVALID_REGNUM, 38, 38 }, nullptr, nullptr, nullptr, 0 }, + { "s13", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s13, LLDB_INVALID_REGNUM, 39, 39 }, nullptr, nullptr, nullptr, 0 }, + { "s14", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s14, LLDB_INVALID_REGNUM, 40, 40 }, nullptr, nullptr, nullptr, 0 }, + { "s15", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s15, LLDB_INVALID_REGNUM, 41, 41 }, nullptr, nullptr, nullptr, 0 }, + { "s16", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s16, LLDB_INVALID_REGNUM, 42, 42 }, nullptr, nullptr, nullptr, 0 }, + { "s17", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s17, LLDB_INVALID_REGNUM, 43, 43 }, nullptr, nullptr, nullptr, 0 }, + { "s18", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s18, LLDB_INVALID_REGNUM, 44, 44 }, nullptr, nullptr, nullptr, 0 }, + { "s19", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s19, LLDB_INVALID_REGNUM, 45, 45 }, nullptr, nullptr, nullptr, 0 }, + { "s20", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s20, LLDB_INVALID_REGNUM, 46, 46 }, nullptr, nullptr, nullptr, 0 }, + { "s21", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s21, LLDB_INVALID_REGNUM, 47, 47 }, nullptr, nullptr, nullptr, 0 }, + { "s22", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s22, LLDB_INVALID_REGNUM, 48, 48 }, nullptr, nullptr, nullptr, 0 }, + { "s23", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s23, LLDB_INVALID_REGNUM, 49, 49 }, nullptr, nullptr, nullptr, 0 }, + { "s24", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s24, LLDB_INVALID_REGNUM, 50, 50 }, nullptr, nullptr, nullptr, 0 }, + { "s25", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s25, LLDB_INVALID_REGNUM, 51, 51 }, nullptr, nullptr, nullptr, 0 }, + { "s26", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s26, LLDB_INVALID_REGNUM, 52, 52 }, nullptr, nullptr, nullptr, 0 }, + { "s27", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s27, LLDB_INVALID_REGNUM, 53, 53 }, nullptr, nullptr, nullptr, 0 }, + { "s28", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s28, LLDB_INVALID_REGNUM, 54, 54 }, nullptr, nullptr, nullptr, 0 }, + { "s29", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s29, LLDB_INVALID_REGNUM, 55, 55 }, nullptr, nullptr, nullptr, 0 }, + { "s30", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s30, LLDB_INVALID_REGNUM, 56, 56 }, nullptr, nullptr, nullptr, 0 }, + { "s31", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s31, LLDB_INVALID_REGNUM, 57, 57 }, nullptr, nullptr, nullptr, 0 }, + { "fpscr",nullptr, 4, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 58, 58 }, nullptr, nullptr, nullptr, 0 }, + { "d16", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d16, LLDB_INVALID_REGNUM, 59, 59 }, nullptr, nullptr, nullptr, 0 }, + { "d17", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d17, LLDB_INVALID_REGNUM, 60, 60 }, nullptr, nullptr, nullptr, 0 }, + { "d18", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d18, LLDB_INVALID_REGNUM, 61, 61 }, nullptr, nullptr, nullptr, 0 }, + { "d19", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d19, LLDB_INVALID_REGNUM, 62, 62 }, nullptr, nullptr, nullptr, 0 }, + { "d20", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d20, LLDB_INVALID_REGNUM, 63, 63 }, nullptr, nullptr, nullptr, 0 }, + { "d21", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d21, LLDB_INVALID_REGNUM, 64, 64 }, nullptr, nullptr, nullptr, 0 }, + { "d22", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d22, LLDB_INVALID_REGNUM, 65, 65 }, nullptr, nullptr, nullptr, 0 }, + { "d23", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d23, LLDB_INVALID_REGNUM, 66, 66 }, nullptr, nullptr, nullptr, 0 }, + { "d24", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d24, LLDB_INVALID_REGNUM, 67, 67 }, nullptr, nullptr, nullptr, 0 }, + { "d25", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d25, LLDB_INVALID_REGNUM, 68, 68 }, nullptr, nullptr, nullptr, 0 }, + { "d26", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d26, LLDB_INVALID_REGNUM, 69, 69 }, nullptr, nullptr, nullptr, 0 }, + { "d27", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d27, LLDB_INVALID_REGNUM, 70, 70 }, nullptr, nullptr, nullptr, 0 }, + { "d28", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d28, LLDB_INVALID_REGNUM, 71, 71 }, nullptr, nullptr, nullptr, 0 }, + { "d29", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d29, LLDB_INVALID_REGNUM, 72, 72 }, nullptr, nullptr, nullptr, 0 }, + { "d30", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d30, LLDB_INVALID_REGNUM, 73, 73 }, nullptr, nullptr, nullptr, 0 }, + { "d31", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d31, LLDB_INVALID_REGNUM, 74, 74 }, nullptr, nullptr, nullptr, 0 }, + { "d0", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d0, LLDB_INVALID_REGNUM, 75, 75 }, g_d0_regs, nullptr, nullptr, 0 }, + { "d1", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d1, LLDB_INVALID_REGNUM, 76, 76 }, g_d1_regs, nullptr, nullptr, 0 }, + { "d2", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d2, LLDB_INVALID_REGNUM, 77, 77 }, g_d2_regs, nullptr, nullptr, 0 }, + { "d3", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d3, LLDB_INVALID_REGNUM, 78, 78 }, g_d3_regs, nullptr, nullptr, 0 }, + { "d4", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d4, LLDB_INVALID_REGNUM, 79, 79 }, g_d4_regs, nullptr, nullptr, 0 }, + { "d5", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d5, LLDB_INVALID_REGNUM, 80, 80 }, g_d5_regs, nullptr, nullptr, 0 }, + { "d6", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d6, LLDB_INVALID_REGNUM, 81, 81 }, g_d6_regs, nullptr, nullptr, 0 }, + { "d7", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d7, LLDB_INVALID_REGNUM, 82, 82 }, g_d7_regs, nullptr, nullptr, 0 }, + { "d8", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d8, LLDB_INVALID_REGNUM, 83, 83 }, g_d8_regs, nullptr, nullptr, 0 }, + { "d9", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d9, LLDB_INVALID_REGNUM, 84, 84 }, g_d9_regs, nullptr, nullptr, 0 }, + { "d10", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d10, LLDB_INVALID_REGNUM, 85, 85 }, g_d10_regs, nullptr, nullptr, 0 }, + { "d11", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d11, LLDB_INVALID_REGNUM, 86, 86 }, g_d11_regs, nullptr, nullptr, 0 }, + { "d12", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d12, LLDB_INVALID_REGNUM, 87, 87 }, g_d12_regs, nullptr, nullptr, 0 }, + { "d13", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d13, LLDB_INVALID_REGNUM, 88, 88 }, g_d13_regs, nullptr, nullptr, 0 }, + { "d14", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d14, LLDB_INVALID_REGNUM, 89, 89 }, g_d14_regs, nullptr, nullptr, 0 }, + { "d15", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d15, LLDB_INVALID_REGNUM, 90, 90 }, g_d15_regs, nullptr, nullptr, 0 }, + { "q0", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q0, LLDB_INVALID_REGNUM, 91, 91 }, g_q0_regs, nullptr, nullptr, 0 }, + { "q1", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q1, LLDB_INVALID_REGNUM, 92, 92 }, g_q1_regs, nullptr, nullptr, 0 }, + { "q2", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q2, LLDB_INVALID_REGNUM, 93, 93 }, g_q2_regs, nullptr, nullptr, 0 }, + { "q3", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q3, LLDB_INVALID_REGNUM, 94, 94 }, g_q3_regs, nullptr, nullptr, 0 }, + { "q4", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q4, LLDB_INVALID_REGNUM, 95, 95 }, g_q4_regs, nullptr, nullptr, 0 }, + { "q5", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q5, LLDB_INVALID_REGNUM, 96, 96 }, g_q5_regs, nullptr, nullptr, 0 }, + { "q6", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q6, LLDB_INVALID_REGNUM, 97, 97 }, g_q6_regs, nullptr, nullptr, 0 }, + { "q7", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q7, LLDB_INVALID_REGNUM, 98, 98 }, g_q7_regs, nullptr, nullptr, 0 }, + { "q8", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q8, LLDB_INVALID_REGNUM, 99, 99 }, g_q8_regs, nullptr, nullptr, 0 }, + { "q9", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q9, LLDB_INVALID_REGNUM, 100, 100 }, g_q9_regs, nullptr, nullptr, 0 }, + { "q10", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q10, LLDB_INVALID_REGNUM, 101, 101 }, g_q10_regs, nullptr, nullptr, 0 }, + { "q11", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q11, LLDB_INVALID_REGNUM, 102, 102 }, g_q11_regs, nullptr, nullptr, 0 }, + { "q12", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q12, LLDB_INVALID_REGNUM, 103, 103 }, g_q12_regs, nullptr, nullptr, 0 }, + { "q13", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q13, LLDB_INVALID_REGNUM, 104, 104 }, g_q13_regs, nullptr, nullptr, 0 }, + { "q14", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q14, LLDB_INVALID_REGNUM, 105, 105 }, g_q14_regs, nullptr, nullptr, 0 }, + { "q15", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q15, LLDB_INVALID_REGNUM, 106, 106 }, g_q15_regs, nullptr, nullptr, 0 } }; - - static const uint32_t num_registers = llvm::array_lengthof(g_register_infos); - static ConstString gpr_reg_set ("General Purpose Registers"); - static ConstString sfp_reg_set ("Software Floating Point Registers"); - static ConstString vfp_reg_set ("Floating Point Registers"); - size_t i; - if (from_scratch) - { - // Calculate the offsets of the registers - // Note that the layout of the "composite" registers (d0-d15 and q0-q15) which comes after the - // "primordial" registers is important. This enables us to calculate the offset of the composite - // register by using the offset of its first primordial register. For example, to calculate the - // offset of q0, use s0's offset. - if (g_register_infos[2].byte_offset == 0) - { - uint32_t byte_offset = 0; - for (i=0; i<num_registers; ++i) - { - // For primordial registers, increment the byte_offset by the byte_size to arrive at the - // byte_offset for the next register. Otherwise, we have a composite register whose - // offset can be calculated by consulting the offset of its first primordial register. - if (!g_register_infos[i].value_regs) - { - g_register_infos[i].byte_offset = byte_offset; - byte_offset += g_register_infos[i].byte_size; - } - else - { - const uint32_t first_primordial_reg = g_register_infos[i].value_regs[0]; - g_register_infos[i].byte_offset = g_register_infos[first_primordial_reg].byte_offset; - } - } - } - for (i=0; i<num_registers; ++i) - { - ConstString name; - ConstString alt_name; - if (g_register_infos[i].name && g_register_infos[i].name[0]) - name.SetCString(g_register_infos[i].name); - if (g_register_infos[i].alt_name && g_register_infos[i].alt_name[0]) - alt_name.SetCString(g_register_infos[i].alt_name); - - if (i <= 15 || i == 25) - AddRegister (g_register_infos[i], name, alt_name, gpr_reg_set); - else if (i <= 24) - AddRegister (g_register_infos[i], name, alt_name, sfp_reg_set); - else - AddRegister (g_register_infos[i], name, alt_name, vfp_reg_set); + // clang-format on + + static const uint32_t num_registers = llvm::array_lengthof(g_register_infos); + static ConstString gpr_reg_set("General Purpose Registers"); + static ConstString sfp_reg_set("Software Floating Point Registers"); + static ConstString vfp_reg_set("Floating Point Registers"); + size_t i; + if (from_scratch) { + // Calculate the offsets of the registers + // Note that the layout of the "composite" registers (d0-d15 and q0-q15) + // which comes after the + // "primordial" registers is important. This enables us to calculate the + // offset of the composite + // register by using the offset of its first primordial register. For + // example, to calculate the + // offset of q0, use s0's offset. + if (g_register_infos[2].byte_offset == 0) { + uint32_t byte_offset = 0; + for (i = 0; i < num_registers; ++i) { + // For primordial registers, increment the byte_offset by the byte_size + // to arrive at the + // byte_offset for the next register. Otherwise, we have a composite + // register whose + // offset can be calculated by consulting the offset of its first + // primordial register. + if (!g_register_infos[i].value_regs) { + g_register_infos[i].byte_offset = byte_offset; + byte_offset += g_register_infos[i].byte_size; + } else { + const uint32_t first_primordial_reg = + g_register_infos[i].value_regs[0]; + g_register_infos[i].byte_offset = + g_register_infos[first_primordial_reg].byte_offset; } + } } - else - { - // Add composite registers to our primordial registers, then. - const size_t num_composites = llvm::array_lengthof(g_composites); - const size_t num_dynamic_regs = GetNumRegisters(); - const size_t num_common_regs = num_registers - num_composites; - RegisterInfo *g_comp_register_infos = g_register_infos + num_common_regs; - - // First we need to validate that all registers that we already have match the non composite regs. - // If so, then we can add the registers, else we need to bail - bool match = true; - if (num_dynamic_regs == num_common_regs) - { - for (i=0; match && i<num_dynamic_regs; ++i) - { - // Make sure all register names match - if (m_regs[i].name && g_register_infos[i].name) - { - if (strcmp(m_regs[i].name, g_register_infos[i].name)) - { - match = false; - break; - } - } - - // Make sure all register byte sizes match - if (m_regs[i].byte_size != g_register_infos[i].byte_size) - { - match = false; - break; - } - } - } - else - { - // Wrong number of registers. + for (i = 0; i < num_registers; ++i) { + ConstString name; + ConstString alt_name; + if (g_register_infos[i].name && g_register_infos[i].name[0]) + name.SetCString(g_register_infos[i].name); + if (g_register_infos[i].alt_name && g_register_infos[i].alt_name[0]) + alt_name.SetCString(g_register_infos[i].alt_name); + + if (i <= 15 || i == 25) + AddRegister(g_register_infos[i], name, alt_name, gpr_reg_set); + else if (i <= 24) + AddRegister(g_register_infos[i], name, alt_name, sfp_reg_set); + else + AddRegister(g_register_infos[i], name, alt_name, vfp_reg_set); + } + } else { + // Add composite registers to our primordial registers, then. + const size_t num_composites = llvm::array_lengthof(g_composites); + const size_t num_dynamic_regs = GetNumRegisters(); + const size_t num_common_regs = num_registers - num_composites; + RegisterInfo *g_comp_register_infos = g_register_infos + num_common_regs; + + // First we need to validate that all registers that we already have match + // the non composite regs. + // If so, then we can add the registers, else we need to bail + bool match = true; + if (num_dynamic_regs == num_common_regs) { + for (i = 0; match && i < num_dynamic_regs; ++i) { + // Make sure all register names match + if (m_regs[i].name && g_register_infos[i].name) { + if (strcmp(m_regs[i].name, g_register_infos[i].name)) { match = false; + break; + } } - // If "match" is true, then we can add extra registers. - if (match) - { - for (i=0; i<num_composites; ++i) - { - ConstString name; - ConstString alt_name; - const uint32_t first_primordial_reg = g_comp_register_infos[i].value_regs[0]; - const char *reg_name = g_register_infos[first_primordial_reg].name; - if (reg_name && reg_name[0]) - { - for (uint32_t j = 0; j < num_dynamic_regs; ++j) - { - const RegisterInfo *reg_info = GetRegisterInfoAtIndex(j); - // Find a matching primordial register info entry. - if (reg_info && reg_info->name && ::strcasecmp(reg_info->name, reg_name) == 0) - { - // The name matches the existing primordial entry. - // Find and assign the offset, and then add this composite register entry. - g_comp_register_infos[i].byte_offset = reg_info->byte_offset; - name.SetCString(g_comp_register_infos[i].name); - AddRegister(g_comp_register_infos[i], name, alt_name, vfp_reg_set); - } - } - } + + // Make sure all register byte sizes match + if (m_regs[i].byte_size != g_register_infos[i].byte_size) { + match = false; + break; + } + } + } else { + // Wrong number of registers. + match = false; + } + // If "match" is true, then we can add extra registers. + if (match) { + for (i = 0; i < num_composites; ++i) { + ConstString name; + ConstString alt_name; + const uint32_t first_primordial_reg = + g_comp_register_infos[i].value_regs[0]; + const char *reg_name = g_register_infos[first_primordial_reg].name; + if (reg_name && reg_name[0]) { + for (uint32_t j = 0; j < num_dynamic_regs; ++j) { + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(j); + // Find a matching primordial register info entry. + if (reg_info && reg_info->name && + ::strcasecmp(reg_info->name, reg_name) == 0) { + // The name matches the existing primordial entry. + // Find and assign the offset, and then add this composite + // register entry. + g_comp_register_infos[i].byte_offset = reg_info->byte_offset; + name.SetCString(g_comp_register_infos[i].name); + AddRegister(g_comp_register_infos[i], name, alt_name, + vfp_reg_set); } + } } + } } + } } diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h index 0e26c69..5b3e04e 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h @@ -16,12 +16,12 @@ // Other libraries and framework includes // Project includes -#include "lldb/lldb-private.h" -#include "lldb/lldb-enumerations.h" +#include "Plugins/Process/Utility/DynamicRegisterInfo.h" #include "lldb/Core/ConstString.h" #include "lldb/Core/DataExtractor.h" #include "lldb/Target/RegisterContext.h" -#include "Plugins/Process/Utility/DynamicRegisterInfo.h" +#include "lldb/lldb-enumerations.h" +#include "lldb/lldb-private.h" #include "GDBRemoteCommunicationClient.h" @@ -33,133 +33,102 @@ namespace process_gdb_remote { class ThreadGDBRemote; class ProcessGDBRemote; -class GDBRemoteDynamicRegisterInfo : - public DynamicRegisterInfo -{ +class GDBRemoteDynamicRegisterInfo : public DynamicRegisterInfo { public: - GDBRemoteDynamicRegisterInfo () : - DynamicRegisterInfo() - { - } + GDBRemoteDynamicRegisterInfo() : DynamicRegisterInfo() {} - ~GDBRemoteDynamicRegisterInfo() override = default; + ~GDBRemoteDynamicRegisterInfo() override = default; - void - HardcodeARMRegisters(bool from_scratch); + void HardcodeARMRegisters(bool from_scratch); }; -class GDBRemoteRegisterContext : public RegisterContext -{ +class GDBRemoteRegisterContext : public RegisterContext { public: - GDBRemoteRegisterContext (ThreadGDBRemote &thread, - uint32_t concrete_frame_idx, - GDBRemoteDynamicRegisterInfo ®_info, - bool read_all_at_once); + GDBRemoteRegisterContext(ThreadGDBRemote &thread, uint32_t concrete_frame_idx, + GDBRemoteDynamicRegisterInfo ®_info, + bool read_all_at_once); + + ~GDBRemoteRegisterContext() override; - ~GDBRemoteRegisterContext() override; + void InvalidateAllRegisters() override; - void - InvalidateAllRegisters () override; + size_t GetRegisterCount() override; - size_t - GetRegisterCount () override; + const RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override; - const RegisterInfo * - GetRegisterInfoAtIndex (size_t reg) override; + size_t GetRegisterSetCount() override; - size_t - GetRegisterSetCount () override; + const RegisterSet *GetRegisterSet(size_t reg_set) override; - const RegisterSet * - GetRegisterSet (size_t reg_set) override; + bool ReadRegister(const RegisterInfo *reg_info, + RegisterValue &value) override; - bool - ReadRegister (const RegisterInfo *reg_info, RegisterValue &value) override; + bool WriteRegister(const RegisterInfo *reg_info, + const RegisterValue &value) override; - bool - WriteRegister (const RegisterInfo *reg_info, const RegisterValue &value) override; - - bool - ReadAllRegisterValues (lldb::DataBufferSP &data_sp) override; + bool ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override; - bool - WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) override; + bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override; - bool - ReadAllRegisterValues (RegisterCheckpoint ®_checkpoint) override; + bool ReadAllRegisterValues(RegisterCheckpoint ®_checkpoint) override; - bool - WriteAllRegisterValues (const RegisterCheckpoint ®_checkpoint) override; + bool + WriteAllRegisterValues(const RegisterCheckpoint ®_checkpoint) override; - uint32_t - ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num) override; + uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, + uint32_t num) override; protected: - friend class ThreadGDBRemote; - - bool - ReadRegisterBytes (const RegisterInfo *reg_info, - DataExtractor &data); - - bool - WriteRegisterBytes (const RegisterInfo *reg_info, - DataExtractor &data, - uint32_t data_offset); - - bool - PrivateSetRegisterValue (uint32_t reg, StringExtractor &response); - - bool - PrivateSetRegisterValue (uint32_t reg, uint64_t val); - - void - SetAllRegisterValid (bool b); - - bool - GetRegisterIsValid (uint32_t reg) const - { -#if defined (LLDB_CONFIGURATION_DEBUG) - assert (reg < m_reg_valid.size()); + friend class ThreadGDBRemote; + + bool ReadRegisterBytes(const RegisterInfo *reg_info, DataExtractor &data); + + bool WriteRegisterBytes(const RegisterInfo *reg_info, DataExtractor &data, + uint32_t data_offset); + + bool PrivateSetRegisterValue(uint32_t reg, llvm::ArrayRef<uint8_t> data); + + bool PrivateSetRegisterValue(uint32_t reg, uint64_t val); + + void SetAllRegisterValid(bool b); + + bool GetRegisterIsValid(uint32_t reg) const { +#if defined(LLDB_CONFIGURATION_DEBUG) + assert(reg < m_reg_valid.size()); #endif - if (reg < m_reg_valid.size()) - return m_reg_valid[reg]; - return false; - } - - void - SetRegisterIsValid (const RegisterInfo *reg_info, bool valid) - { - if (reg_info) - return SetRegisterIsValid (reg_info->kinds[lldb::eRegisterKindLLDB], valid); - } - - void - SetRegisterIsValid (uint32_t reg, bool valid) - { -#if defined (LLDB_CONFIGURATION_DEBUG) - assert (reg < m_reg_valid.size()); + if (reg < m_reg_valid.size()) + return m_reg_valid[reg]; + return false; + } + + void SetRegisterIsValid(const RegisterInfo *reg_info, bool valid) { + if (reg_info) + return SetRegisterIsValid(reg_info->kinds[lldb::eRegisterKindLLDB], + valid); + } + + void SetRegisterIsValid(uint32_t reg, bool valid) { +#if defined(LLDB_CONFIGURATION_DEBUG) + assert(reg < m_reg_valid.size()); #endif - if (reg < m_reg_valid.size()) - m_reg_valid[reg] = valid; - } - - void - SyncThreadState(Process *process); // Assumes the sequence mutex has already been acquired. - - GDBRemoteDynamicRegisterInfo &m_reg_info; - std::vector<bool> m_reg_valid; - DataExtractor m_reg_data; - bool m_read_all_at_once; + if (reg < m_reg_valid.size()) + m_reg_valid[reg] = valid; + } + + GDBRemoteDynamicRegisterInfo &m_reg_info; + std::vector<bool> m_reg_valid; + DataExtractor m_reg_data; + bool m_read_all_at_once; private: - // Helper function for ReadRegisterBytes(). - bool GetPrimordialRegister(const RegisterInfo *reg_info, - GDBRemoteCommunicationClient &gdb_comm); - // Helper function for WriteRegisterBytes(). - bool SetPrimordialRegister(const RegisterInfo *reg_info, - GDBRemoteCommunicationClient &gdb_comm); - - DISALLOW_COPY_AND_ASSIGN (GDBRemoteRegisterContext); + // Helper function for ReadRegisterBytes(). + bool GetPrimordialRegister(const RegisterInfo *reg_info, + GDBRemoteCommunicationClient &gdb_comm); + // Helper function for WriteRegisterBytes(). + bool SetPrimordialRegister(const RegisterInfo *reg_info, + GDBRemoteCommunicationClient &gdb_comm); + + DISALLOW_COPY_AND_ASSIGN(GDBRemoteRegisterContext); }; } // namespace process_gdb_remote diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index f53d4c6..4b4d62d 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -14,7 +14,8 @@ #include <stdlib.h> #ifndef LLDB_DISABLE_POSIX #include <netinet/in.h> -#include <sys/mman.h> // for mmap +#include <sys/mman.h> // for mmap +#include <sys/socket.h> #endif #include <sys/stat.h> #include <sys/types.h> @@ -24,13 +25,11 @@ #include <algorithm> #include <map> #include <mutex> +#include <sstream> #include "lldb/Breakpoint/Watchpoint.h" -#include "lldb/Interpreter/Args.h" #include "lldb/Core/ArchSpec.h" #include "lldb/Core/Debugger.h" -#include "lldb/Host/ConnectionFileDescriptor.h" -#include "lldb/Host/FileSpec.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" @@ -40,136 +39,119 @@ #include "lldb/Core/Timer.h" #include "lldb/Core/Value.h" #include "lldb/DataFormatters/FormatManager.h" +#include "lldb/Host/ConnectionFileDescriptor.h" +#include "lldb/Host/FileSpec.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/HostThread.h" #include "lldb/Host/StringConvert.h" #include "lldb/Host/Symbols.h" #include "lldb/Host/ThreadLauncher.h" -#include "lldb/Host/TimeValue.h" #include "lldb/Host/XML.h" +#include "lldb/Interpreter/Args.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandObject.h" #include "lldb/Interpreter/CommandObjectMultiword.h" #include "lldb/Interpreter/CommandReturnObject.h" -#include "lldb/Interpreter/OptionValueProperties.h" -#include "lldb/Interpreter/Options.h" #include "lldb/Interpreter/OptionGroupBoolean.h" #include "lldb/Interpreter/OptionGroupUInt64.h" +#include "lldb/Interpreter/OptionValueProperties.h" +#include "lldb/Interpreter/Options.h" #include "lldb/Interpreter/Property.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/ABI.h" #include "lldb/Target/DynamicLoader.h" +#include "lldb/Target/SystemRuntime.h" #include "lldb/Target/Target.h" #include "lldb/Target/TargetList.h" #include "lldb/Target/ThreadPlanCallFunction.h" -#include "lldb/Target/SystemRuntime.h" +#include "lldb/Utility/CleanUp.h" #include "lldb/Utility/PseudoTerminal.h" // Project includes -#include "lldb/Host/Host.h" +#include "GDBRemoteRegisterContext.h" +//#include "Plugins/Platform/MacOSX/PlatformRemoteiOS.h" #include "Plugins/Process/Utility/GDBRemoteSignals.h" #include "Plugins/Process/Utility/InferiorCallPOSIX.h" #include "Plugins/Process/Utility/StopInfoMachException.h" -//#include "Plugins/Platform/MacOSX/PlatformRemoteiOS.h" -#include "Utility/StringExtractorGDBRemote.h" -#include "GDBRemoteRegisterContext.h" #include "ProcessGDBRemote.h" #include "ProcessGDBRemoteLog.h" #include "ThreadGDBRemote.h" +#include "Utility/StringExtractorGDBRemote.h" +#include "lldb/Host/Host.h" -#define DEBUGSERVER_BASENAME "debugserver" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/raw_ostream.h" + +#define DEBUGSERVER_BASENAME "debugserver" using namespace lldb; using namespace lldb_private; using namespace lldb_private::process_gdb_remote; -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) - { - StreamFile strm; - Error error (strm.GetFile().Open(path, File::eOpenOptionWrite | File::eOpenOptionCanCreate)); - if (error.Success()) - ((ProcessGDBRemote *)p)->GetGDBRemote().DumpHistory (strm); - } +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) { + StreamFile strm; + Error error(strm.GetFile().Open(path, File::eOpenOptionWrite | + File::eOpenOptionCanCreate)); + if (error.Success()) + ((ProcessGDBRemote *)p)->GetGDBRemote().DumpHistory(strm); +} } namespace { - static PropertyDefinition - g_properties[] = - { - { "packet-timeout" , OptionValue::eTypeUInt64 , true , 1, NULL, 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 } - }; - - enum - { - ePropertyPacketTimeout, - ePropertyTargetDefinitionFile - }; +static PropertyDefinition g_properties[] = { + {"packet-timeout", OptionValue::eTypeUInt64, true, 1, NULL, 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}}; - class PluginProperties : public Properties - { - public: - - static ConstString - GetSettingName () - { - return ProcessGDBRemote::GetPluginNameStatic(); - } - - PluginProperties() : - Properties () - { - m_collection_sp.reset (new OptionValueProperties(GetSettingName())); - m_collection_sp->Initialize(g_properties); - } - - virtual - ~PluginProperties() - { - } - - uint64_t - GetPacketTimeout() - { - const uint32_t idx = ePropertyPacketTimeout; - return m_collection_sp->GetPropertyAtIndexAsUInt64(NULL, idx, g_properties[idx].default_uint_value); - } - - bool - SetPacketTimeout(uint64_t timeout) - { - const uint32_t idx = ePropertyPacketTimeout; - return m_collection_sp->SetPropertyAtIndexAsUInt64(NULL, idx, timeout); - } +enum { ePropertyPacketTimeout, ePropertyTargetDefinitionFile }; - FileSpec - GetTargetDefinitionFile () const - { - const uint32_t idx = ePropertyTargetDefinitionFile; - return m_collection_sp->GetPropertyAtIndexAsFileSpec (NULL, idx); - } - }; +class PluginProperties : public Properties { +public: + static ConstString GetSettingName() { + return ProcessGDBRemote::GetPluginNameStatic(); + } + + PluginProperties() : Properties() { + m_collection_sp.reset(new OptionValueProperties(GetSettingName())); + m_collection_sp->Initialize(g_properties); + } + + virtual ~PluginProperties() {} + + uint64_t GetPacketTimeout() { + const uint32_t idx = ePropertyPacketTimeout; + return m_collection_sp->GetPropertyAtIndexAsUInt64( + NULL, idx, g_properties[idx].default_uint_value); + } + + bool SetPacketTimeout(uint64_t timeout) { + const uint32_t idx = ePropertyPacketTimeout; + return m_collection_sp->SetPropertyAtIndexAsUInt64(NULL, idx, timeout); + } + + FileSpec GetTargetDefinitionFile() const { + const uint32_t idx = ePropertyTargetDefinitionFile; + return m_collection_sp->GetPropertyAtIndexAsFileSpec(NULL, idx); + } +}; - typedef std::shared_ptr<PluginProperties> ProcessKDPPropertiesSP; +typedef std::shared_ptr<PluginProperties> ProcessKDPPropertiesSP; - static const ProcessKDPPropertiesSP & - GetGlobalPluginProperties() - { - static ProcessKDPPropertiesSP g_settings_sp; - if (!g_settings_sp) - g_settings_sp.reset (new PluginProperties ()); - return g_settings_sp; - } +static const ProcessKDPPropertiesSP &GetGlobalPluginProperties() { + static ProcessKDPPropertiesSP g_settings_sp; + if (!g_settings_sp) + g_settings_sp.reset(new PluginProperties()); + return g_settings_sp; +} } // anonymous namespace end @@ -177,3887 +159,3564 @@ namespace { // ephemeral port from the kernel and make sure we reserve it before passing // it to debugserver. -#if defined (__APPLE__) -#define LOW_PORT (IPPORT_RESERVED) -#define HIGH_PORT (IPPORT_HIFIRSTAUTO) +#if defined(__APPLE__) +#define LOW_PORT (IPPORT_RESERVED) +#define HIGH_PORT (IPPORT_HIFIRSTAUTO) #else -#define LOW_PORT (1024u) -#define HIGH_PORT (49151u) +#define LOW_PORT (1024u) +#define HIGH_PORT (49151u) #endif -#if defined(__APPLE__) && (defined(__arm__) || defined(__arm64__) || defined(__aarch64__)) +#if defined(__APPLE__) && \ + (defined(__arm__) || defined(__arm64__) || defined(__aarch64__)) static bool rand_initialized = false; -static inline uint16_t -get_random_port () -{ - if (!rand_initialized) - { - time_t seed = time(NULL); +static inline uint16_t get_random_port() { + if (!rand_initialized) { + time_t seed = time(NULL); - rand_initialized = true; - srand(seed); - } - return (rand() % (HIGH_PORT - LOW_PORT)) + LOW_PORT; + rand_initialized = true; + srand(seed); + } + return (rand() % (HIGH_PORT - LOW_PORT)) + LOW_PORT; } #endif -ConstString -ProcessGDBRemote::GetPluginNameStatic() -{ - static ConstString g_name("gdb-remote"); - return g_name; +ConstString ProcessGDBRemote::GetPluginNameStatic() { + static ConstString g_name("gdb-remote"); + return g_name; } -const char * -ProcessGDBRemote::GetPluginDescriptionStatic() -{ - return "GDB Remote protocol based debugging plug-in."; +const char *ProcessGDBRemote::GetPluginDescriptionStatic() { + return "GDB Remote protocol based debugging plug-in."; } -void -ProcessGDBRemote::Terminate() -{ - PluginManager::UnregisterPlugin (ProcessGDBRemote::CreateInstance); +void ProcessGDBRemote::Terminate() { + PluginManager::UnregisterPlugin(ProcessGDBRemote::CreateInstance); } - lldb::ProcessSP -ProcessGDBRemote::CreateInstance (lldb::TargetSP target_sp, ListenerSP listener_sp, const FileSpec *crash_file_path) -{ - lldb::ProcessSP process_sp; - if (crash_file_path == NULL) - process_sp.reset (new ProcessGDBRemote (target_sp, listener_sp)); - return process_sp; +ProcessGDBRemote::CreateInstance(lldb::TargetSP target_sp, + ListenerSP listener_sp, + const FileSpec *crash_file_path) { + lldb::ProcessSP process_sp; + if (crash_file_path == NULL) + process_sp.reset(new ProcessGDBRemote(target_sp, listener_sp)); + return process_sp; } -bool -ProcessGDBRemote::CanDebug (lldb::TargetSP target_sp, bool plugin_specified_by_name) -{ - if (plugin_specified_by_name) - return true; - - // For now we are just making sure the file exists for a given module - Module *exe_module = target_sp->GetExecutableModulePointer(); - if (exe_module) - { - ObjectFile *exe_objfile = exe_module->GetObjectFile(); - // We can't debug core files... - switch (exe_objfile->GetType()) - { - case ObjectFile::eTypeInvalid: - case ObjectFile::eTypeCoreFile: - case ObjectFile::eTypeDebugInfo: - case ObjectFile::eTypeObjectFile: - case ObjectFile::eTypeSharedLibrary: - case ObjectFile::eTypeStubLibrary: - case ObjectFile::eTypeJIT: - return false; - case ObjectFile::eTypeExecutable: - case ObjectFile::eTypeDynamicLinker: - case ObjectFile::eTypeUnknown: - break; - } - return exe_module->GetFileSpec().Exists(); - } - // However, if there is no executable module, we return true since we might be preparing to attach. +bool ProcessGDBRemote::CanDebug(lldb::TargetSP target_sp, + bool plugin_specified_by_name) { + if (plugin_specified_by_name) return true; + + // For now we are just making sure the file exists for a given module + Module *exe_module = target_sp->GetExecutableModulePointer(); + if (exe_module) { + ObjectFile *exe_objfile = exe_module->GetObjectFile(); + // We can't debug core files... + switch (exe_objfile->GetType()) { + case ObjectFile::eTypeInvalid: + case ObjectFile::eTypeCoreFile: + case ObjectFile::eTypeDebugInfo: + case ObjectFile::eTypeObjectFile: + case ObjectFile::eTypeSharedLibrary: + case ObjectFile::eTypeStubLibrary: + case ObjectFile::eTypeJIT: + return false; + case ObjectFile::eTypeExecutable: + case ObjectFile::eTypeDynamicLinker: + case ObjectFile::eTypeUnknown: + break; + } + return exe_module->GetFileSpec().Exists(); + } + // However, if there is no executable module, we return true since we might be + // preparing to attach. + return true; } //---------------------------------------------------------------------- // ProcessGDBRemote constructor //---------------------------------------------------------------------- -ProcessGDBRemote::ProcessGDBRemote(lldb::TargetSP target_sp, ListenerSP listener_sp) - : Process(target_sp, listener_sp), - m_flags(0), - m_gdb_comm(), - m_debugserver_pid(LLDB_INVALID_PROCESS_ID), - m_last_stop_packet_mutex(), +ProcessGDBRemote::ProcessGDBRemote(lldb::TargetSP target_sp, + ListenerSP listener_sp) + : Process(target_sp, listener_sp), m_flags(0), m_gdb_comm(), + m_debugserver_pid(LLDB_INVALID_PROCESS_ID), m_last_stop_packet_mutex(), m_register_info(), m_async_broadcaster(NULL, "lldb.process.gdb-remote.async-broadcaster"), - m_async_listener_sp(Listener::MakeListener("lldb.process.gdb-remote.async-listener")), - m_async_thread_state_mutex(), - m_thread_ids(), - m_thread_pcs(), - m_jstopinfo_sp(), - m_jthreadsinfo_sp(), - m_continue_c_tids(), - m_continue_C_tids(), - m_continue_s_tids(), - m_continue_S_tids(), - m_max_memory_size(0), - m_remote_stub_max_memory_size(0), - 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_async_broadcaster.SetEventName(eBroadcastBitAsyncThreadShouldExit, "async thread should exit"); - m_async_broadcaster.SetEventName(eBroadcastBitAsyncContinue, "async thread continue"); - m_async_broadcaster.SetEventName(eBroadcastBitAsyncThreadDidExit, "async thread did exit"); - - Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_ASYNC)); - - const uint32_t async_event_mask = eBroadcastBitAsyncContinue | eBroadcastBitAsyncThreadShouldExit; - - if (m_async_listener_sp->StartListeningForEvents(&m_async_broadcaster, async_event_mask) != async_event_mask) - { - if (log) - log->Printf("ProcessGDBRemote::%s failed to listen for m_async_broadcaster events", __FUNCTION__); - } - - const uint32_t gdb_event_mask = - Communication::eBroadcastBitReadThreadDidExit | GDBRemoteCommunication::eBroadcastBitGdbReadThreadGotNotify; - if (m_async_listener_sp->StartListeningForEvents(&m_gdb_comm, gdb_event_mask) != gdb_event_mask) - { - if (log) - log->Printf("ProcessGDBRemote::%s failed to listen for m_gdb_comm events", __FUNCTION__); - } - - const uint64_t timeout_seconds = GetGlobalPluginProperties()->GetPacketTimeout(); - if (timeout_seconds > 0) - m_gdb_comm.SetPacketTimeout(timeout_seconds); + m_async_listener_sp( + Listener::MakeListener("lldb.process.gdb-remote.async-listener")), + m_async_thread_state_mutex(), m_thread_ids(), m_thread_pcs(), + m_jstopinfo_sp(), m_jthreadsinfo_sp(), m_continue_c_tids(), + m_continue_C_tids(), m_continue_s_tids(), m_continue_S_tids(), + m_max_memory_size(0), m_remote_stub_max_memory_size(0), + 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_async_broadcaster.SetEventName(eBroadcastBitAsyncThreadShouldExit, + "async thread should exit"); + m_async_broadcaster.SetEventName(eBroadcastBitAsyncContinue, + "async thread continue"); + m_async_broadcaster.SetEventName(eBroadcastBitAsyncThreadDidExit, + "async thread did exit"); + + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_ASYNC)); + + const uint32_t async_event_mask = + eBroadcastBitAsyncContinue | eBroadcastBitAsyncThreadShouldExit; + + if (m_async_listener_sp->StartListeningForEvents( + &m_async_broadcaster, async_event_mask) != async_event_mask) { + if (log) + log->Printf("ProcessGDBRemote::%s failed to listen for " + "m_async_broadcaster events", + __FUNCTION__); + } + + const uint32_t gdb_event_mask = + Communication::eBroadcastBitReadThreadDidExit | + GDBRemoteCommunication::eBroadcastBitGdbReadThreadGotNotify; + if (m_async_listener_sp->StartListeningForEvents( + &m_gdb_comm, gdb_event_mask) != gdb_event_mask) { + if (log) + log->Printf("ProcessGDBRemote::%s failed to listen for m_gdb_comm events", + __FUNCTION__); + } + + const uint64_t timeout_seconds = + GetGlobalPluginProperties()->GetPacketTimeout(); + if (timeout_seconds > 0) + m_gdb_comm.SetPacketTimeout(std::chrono::seconds(timeout_seconds)); } //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- -ProcessGDBRemote::~ProcessGDBRemote() -{ - // m_mach_process.UnregisterNotificationCallbacks (this); - Clear(); - // We need to call finalize on the process before destroying ourselves - // to make sure all of the broadcaster cleanup goes as planned. If we - // destruct this class, then Process::~Process() might have problems - // trying to fully destroy the broadcaster. - Finalize(); - - // The general Finalize is going to try to destroy the process and that SHOULD - // shut down the async thread. However, if we don't kill it it will get stranded and - // its connection will go away so when it wakes up it will crash. So kill it for sure here. - StopAsyncThread(); - KillDebugserverProcess(); +ProcessGDBRemote::~ProcessGDBRemote() { + // m_mach_process.UnregisterNotificationCallbacks (this); + Clear(); + // We need to call finalize on the process before destroying ourselves + // to make sure all of the broadcaster cleanup goes as planned. If we + // destruct this class, then Process::~Process() might have problems + // trying to fully destroy the broadcaster. + Finalize(); + + // The general Finalize is going to try to destroy the process and that SHOULD + // shut down the async thread. However, if we don't kill it it will get + // stranded and + // its connection will go away so when it wakes up it will crash. So kill it + // for sure here. + StopAsyncThread(); + KillDebugserverProcess(); } //---------------------------------------------------------------------- // PluginInterface //---------------------------------------------------------------------- -ConstString -ProcessGDBRemote::GetPluginName() -{ - return GetPluginNameStatic(); -} - -uint32_t -ProcessGDBRemote::GetPluginVersion() -{ - return 1; -} - -bool -ProcessGDBRemote::ParsePythonTargetDefinition(const FileSpec &target_definition_fspec) -{ - ScriptInterpreter *interpreter = GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); - Error error; - StructuredData::ObjectSP module_object_sp(interpreter->LoadPluginModule(target_definition_fspec, error)); - if (module_object_sp) - { - StructuredData::DictionarySP target_definition_sp( - interpreter->GetDynamicSettings(module_object_sp, &GetTarget(), "gdb-server-target-definition", error)); - - if (target_definition_sp) - { - StructuredData::ObjectSP target_object(target_definition_sp->GetValueForKey("host-info")); - if (target_object) - { - if (auto host_info_dict = target_object->GetAsDictionary()) - { - StructuredData::ObjectSP triple_value = host_info_dict->GetValueForKey("triple"); - if (auto triple_string_value = triple_value->GetAsString()) - { - std::string triple_string = triple_string_value->GetValue(); - ArchSpec host_arch(triple_string.c_str()); - if (!host_arch.IsCompatibleMatch(GetTarget().GetArchitecture())) - { - GetTarget().SetArchitecture(host_arch); - } - } - } - } - m_breakpoint_pc_offset = 0; - StructuredData::ObjectSP breakpoint_pc_offset_value = target_definition_sp->GetValueForKey("breakpoint-pc-offset"); - if (breakpoint_pc_offset_value) - { - if (auto breakpoint_pc_int_value = breakpoint_pc_offset_value->GetAsInteger()) - m_breakpoint_pc_offset = breakpoint_pc_int_value->GetValue(); - } - - if (m_register_info.SetRegisterInfo(*target_definition_sp, GetTarget().GetArchitecture()) > 0) - { - return true; +ConstString ProcessGDBRemote::GetPluginName() { return GetPluginNameStatic(); } + +uint32_t ProcessGDBRemote::GetPluginVersion() { return 1; } + +bool ProcessGDBRemote::ParsePythonTargetDefinition( + const FileSpec &target_definition_fspec) { + ScriptInterpreter *interpreter = + GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); + Error error; + StructuredData::ObjectSP module_object_sp( + interpreter->LoadPluginModule(target_definition_fspec, error)); + if (module_object_sp) { + StructuredData::DictionarySP target_definition_sp( + interpreter->GetDynamicSettings(module_object_sp, &GetTarget(), + "gdb-server-target-definition", error)); + + if (target_definition_sp) { + StructuredData::ObjectSP target_object( + target_definition_sp->GetValueForKey("host-info")); + if (target_object) { + if (auto host_info_dict = target_object->GetAsDictionary()) { + StructuredData::ObjectSP triple_value = + host_info_dict->GetValueForKey("triple"); + if (auto triple_string_value = triple_value->GetAsString()) { + std::string triple_string = triple_string_value->GetValue(); + ArchSpec host_arch(triple_string.c_str()); + if (!host_arch.IsCompatibleMatch(GetTarget().GetArchitecture())) { + GetTarget().SetArchitecture(host_arch); } + } } + } + m_breakpoint_pc_offset = 0; + StructuredData::ObjectSP breakpoint_pc_offset_value = + target_definition_sp->GetValueForKey("breakpoint-pc-offset"); + if (breakpoint_pc_offset_value) { + if (auto breakpoint_pc_int_value = + breakpoint_pc_offset_value->GetAsInteger()) + m_breakpoint_pc_offset = breakpoint_pc_int_value->GetValue(); + } + + if (m_register_info.SetRegisterInfo(*target_definition_sp, + GetTarget().GetArchitecture()) > 0) { + return true; + } } - return false; + } + return false; } -// If the remote stub didn't give us eh_frame or DWARF register numbers for a register, +// If the remote stub didn't give us eh_frame or DWARF register numbers for a +// register, // see if the ABI can provide them. // DWARF and eh_frame register numbers are defined as a part of the ABI. -static void -AugmentRegisterInfoViaABI (RegisterInfo ®_info, ConstString reg_name, ABISP abi_sp) -{ - if (reg_info.kinds[eRegisterKindEHFrame] == LLDB_INVALID_REGNUM - || reg_info.kinds[eRegisterKindDWARF] == LLDB_INVALID_REGNUM) - { - if (abi_sp) - { - RegisterInfo abi_reg_info; - if (abi_sp->GetRegisterInfoByName (reg_name, abi_reg_info)) - { - if (reg_info.kinds[eRegisterKindEHFrame] == LLDB_INVALID_REGNUM && - abi_reg_info.kinds[eRegisterKindEHFrame] != LLDB_INVALID_REGNUM) - { - reg_info.kinds[eRegisterKindEHFrame] = abi_reg_info.kinds[eRegisterKindEHFrame]; - } - if (reg_info.kinds[eRegisterKindDWARF] == LLDB_INVALID_REGNUM && - abi_reg_info.kinds[eRegisterKindDWARF] != LLDB_INVALID_REGNUM) - { - reg_info.kinds[eRegisterKindDWARF] = abi_reg_info.kinds[eRegisterKindDWARF]; - } - if (reg_info.kinds[eRegisterKindGeneric] == LLDB_INVALID_REGNUM && - abi_reg_info.kinds[eRegisterKindGeneric] != LLDB_INVALID_REGNUM) - { - reg_info.kinds[eRegisterKindGeneric] = abi_reg_info.kinds[eRegisterKindGeneric]; - } - } +static void AugmentRegisterInfoViaABI(RegisterInfo ®_info, + ConstString reg_name, ABISP abi_sp) { + if (reg_info.kinds[eRegisterKindEHFrame] == LLDB_INVALID_REGNUM || + reg_info.kinds[eRegisterKindDWARF] == LLDB_INVALID_REGNUM) { + if (abi_sp) { + RegisterInfo abi_reg_info; + if (abi_sp->GetRegisterInfoByName(reg_name, abi_reg_info)) { + if (reg_info.kinds[eRegisterKindEHFrame] == LLDB_INVALID_REGNUM && + abi_reg_info.kinds[eRegisterKindEHFrame] != LLDB_INVALID_REGNUM) { + reg_info.kinds[eRegisterKindEHFrame] = + abi_reg_info.kinds[eRegisterKindEHFrame]; } - } -} - -static size_t -SplitCommaSeparatedRegisterNumberString(const llvm::StringRef &comma_separated_regiter_numbers, std::vector<uint32_t> ®nums, int base) -{ - regnums.clear(); - std::pair<llvm::StringRef, llvm::StringRef> value_pair; - value_pair.second = comma_separated_regiter_numbers; - do - { - value_pair = value_pair.second.split(','); - if (!value_pair.first.empty()) - { - uint32_t reg = StringConvert::ToUInt32 (value_pair.first.str().c_str(), LLDB_INVALID_REGNUM, base); - if (reg != LLDB_INVALID_REGNUM) - regnums.push_back (reg); - } - } while (!value_pair.second.empty()); - return regnums.size(); -} - - -void -ProcessGDBRemote::BuildDynamicRegisterInfo (bool force) -{ - if (!force && m_register_info.GetNumRegisters() > 0) - return; - - m_register_info.Clear(); - - // Check if qHostInfo specified a specific packet timeout for this connection. - // If so then lets update our setting so the user knows what the timeout is - // and can see it. - const uint32_t host_packet_timeout = m_gdb_comm.GetHostDefaultPacketTimeout(); - if (host_packet_timeout) - { - GetGlobalPluginProperties()->SetPacketTimeout(host_packet_timeout); - } - - // Register info search order: - // 1 - Use the target definition python file if one is specified. - // 2 - If the target definition doesn't have any of the info from the target.xml (registers) then proceed to read the target.xml. - // 3 - Fall back on the qRegisterInfo packets. - - FileSpec target_definition_fspec = GetGlobalPluginProperties()->GetTargetDefinitionFile (); - if (!target_definition_fspec.Exists()) - { - // If the filename doesn't exist, it may be a ~ not having been expanded - try to resolve it. - target_definition_fspec.ResolvePath(); - } - if (target_definition_fspec) - { - // See if we can get register definitions from a python file - if (ParsePythonTargetDefinition (target_definition_fspec)) - { - return; + if (reg_info.kinds[eRegisterKindDWARF] == LLDB_INVALID_REGNUM && + abi_reg_info.kinds[eRegisterKindDWARF] != LLDB_INVALID_REGNUM) { + reg_info.kinds[eRegisterKindDWARF] = + abi_reg_info.kinds[eRegisterKindDWARF]; } - else - { - StreamSP stream_sp = GetTarget().GetDebugger().GetAsyncOutputStream(); - stream_sp->Printf ("ERROR: target description file %s failed to parse.\n", target_definition_fspec.GetPath().c_str()); + if (reg_info.kinds[eRegisterKindGeneric] == LLDB_INVALID_REGNUM && + abi_reg_info.kinds[eRegisterKindGeneric] != LLDB_INVALID_REGNUM) { + reg_info.kinds[eRegisterKindGeneric] = + abi_reg_info.kinds[eRegisterKindGeneric]; } + } } + } +} - const ArchSpec &target_arch = GetTarget().GetArchitecture(); - const ArchSpec &remote_host_arch = m_gdb_comm.GetHostArchitecture(); - const ArchSpec &remote_process_arch = m_gdb_comm.GetProcessArchitecture(); +static size_t SplitCommaSeparatedRegisterNumberString( + const llvm::StringRef &comma_separated_regiter_numbers, + std::vector<uint32_t> ®nums, int base) { + regnums.clear(); + std::pair<llvm::StringRef, llvm::StringRef> value_pair; + value_pair.second = comma_separated_regiter_numbers; + do { + value_pair = value_pair.second.split(','); + if (!value_pair.first.empty()) { + uint32_t reg = StringConvert::ToUInt32(value_pair.first.str().c_str(), + LLDB_INVALID_REGNUM, base); + if (reg != LLDB_INVALID_REGNUM) + regnums.push_back(reg); + } + } while (!value_pair.second.empty()); + return regnums.size(); +} - // Use the process' architecture instead of the host arch, if available - ArchSpec arch_to_use; - if (remote_process_arch.IsValid ()) - arch_to_use = remote_process_arch; - else - arch_to_use = remote_host_arch; - - if (!arch_to_use.IsValid()) - arch_to_use = target_arch; - - if (GetGDBServerRegisterInfo (arch_to_use)) - return; - - char packet[128]; - uint32_t reg_offset = 0; - uint32_t reg_num = 0; - for (StringExtractorGDBRemote::ResponseType response_type = StringExtractorGDBRemote::eResponse; - response_type == StringExtractorGDBRemote::eResponse; - ++reg_num) - { - const int packet_len = ::snprintf (packet, sizeof(packet), "qRegisterInfo%x", reg_num); - assert (packet_len < (int)sizeof(packet)); - StringExtractorGDBRemote response; - if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false) == GDBRemoteCommunication::PacketResult::Success) - { - response_type = response.GetResponseType(); - if (response_type == StringExtractorGDBRemote::eResponse) +void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) { + if (!force && m_register_info.GetNumRegisters() > 0) + return; + + m_register_info.Clear(); + + // Check if qHostInfo specified a specific packet timeout for this connection. + // If so then lets update our setting so the user knows what the timeout is + // and can see it. + const auto host_packet_timeout = m_gdb_comm.GetHostDefaultPacketTimeout(); + if (host_packet_timeout > std::chrono::seconds(0)) { + GetGlobalPluginProperties()->SetPacketTimeout(host_packet_timeout.count()); + } + + // Register info search order: + // 1 - Use the target definition python file if one is specified. + // 2 - If the target definition doesn't have any of the info from the + // target.xml (registers) then proceed to read the target.xml. + // 3 - Fall back on the qRegisterInfo packets. + + FileSpec target_definition_fspec = + GetGlobalPluginProperties()->GetTargetDefinitionFile(); + if (!target_definition_fspec.Exists()) { + // If the filename doesn't exist, it may be a ~ not having been expanded - + // try to resolve it. + target_definition_fspec.ResolvePath(); + } + if (target_definition_fspec) { + // See if we can get register definitions from a python file + if (ParsePythonTargetDefinition(target_definition_fspec)) { + return; + } else { + StreamSP stream_sp = GetTarget().GetDebugger().GetAsyncOutputStream(); + stream_sp->Printf("ERROR: target description file %s failed to parse.\n", + target_definition_fspec.GetPath().c_str()); + } + } + + const ArchSpec &target_arch = GetTarget().GetArchitecture(); + const ArchSpec &remote_host_arch = m_gdb_comm.GetHostArchitecture(); + const ArchSpec &remote_process_arch = m_gdb_comm.GetProcessArchitecture(); + + // Use the process' architecture instead of the host arch, if available + ArchSpec arch_to_use; + if (remote_process_arch.IsValid()) + arch_to_use = remote_process_arch; + else + arch_to_use = remote_host_arch; + + if (!arch_to_use.IsValid()) + arch_to_use = target_arch; + + if (GetGDBServerRegisterInfo(arch_to_use)) + return; + + char packet[128]; + uint32_t reg_offset = 0; + uint32_t reg_num = 0; + for (StringExtractorGDBRemote::ResponseType response_type = + StringExtractorGDBRemote::eResponse; + response_type == StringExtractorGDBRemote::eResponse; ++reg_num) { + const int packet_len = + ::snprintf(packet, sizeof(packet), "qRegisterInfo%x", reg_num); + assert(packet_len < (int)sizeof(packet)); + UNUSED_IF_ASSERT_DISABLED(packet_len); + StringExtractorGDBRemote response; + if (m_gdb_comm.SendPacketAndWaitForResponse(packet, response, false) == + GDBRemoteCommunication::PacketResult::Success) { + response_type = response.GetResponseType(); + if (response_type == StringExtractorGDBRemote::eResponse) { + llvm::StringRef name; + llvm::StringRef value; + ConstString reg_name; + ConstString alt_name; + ConstString set_name; + std::vector<uint32_t> value_regs; + std::vector<uint32_t> invalidate_regs; + std::vector<uint8_t> dwarf_opcode_bytes; + RegisterInfo reg_info = { + NULL, // Name + NULL, // Alt name + 0, // byte size + reg_offset, // offset + eEncodingUint, // encoding + eFormatHex, // format { - std::string name; - std::string value; - ConstString reg_name; - ConstString alt_name; - ConstString set_name; - std::vector<uint32_t> value_regs; - std::vector<uint32_t> invalidate_regs; - std::vector<uint8_t> dwarf_opcode_bytes; - RegisterInfo reg_info = { NULL, // Name - NULL, // Alt name - 0, // byte size - reg_offset, // offset - eEncodingUint, // encoding - eFormatHex, // format - { - LLDB_INVALID_REGNUM, // eh_frame reg num - LLDB_INVALID_REGNUM, // DWARF reg num - LLDB_INVALID_REGNUM, // generic reg num - reg_num, // process plugin reg num - reg_num // native register number - }, - NULL, - NULL, - NULL, // Dwarf expression opcode bytes pointer - 0 // Dwarf expression opcode bytes length - }; - - while (response.GetNameColonValue(name, value)) - { - if (name.compare("name") == 0) - { - reg_name.SetCString(value.c_str()); - } - else if (name.compare("alt-name") == 0) - { - alt_name.SetCString(value.c_str()); - } - else if (name.compare("bitsize") == 0) - { - reg_info.byte_size = StringConvert::ToUInt32(value.c_str(), 0, 0) / CHAR_BIT; - } - else if (name.compare("offset") == 0) - { - uint32_t offset = StringConvert::ToUInt32(value.c_str(), UINT32_MAX, 0); - if (reg_offset != offset) - { - reg_offset = offset; - } - } - else if (name.compare("encoding") == 0) - { - const Encoding encoding = Args::StringToEncoding (value.c_str()); - if (encoding != eEncodingInvalid) - reg_info.encoding = encoding; - } - else if (name.compare("format") == 0) - { - Format format = eFormatInvalid; - if (Args::StringToFormat (value.c_str(), format, NULL).Success()) - reg_info.format = format; - else if (value.compare("binary") == 0) - reg_info.format = eFormatBinary; - else if (value.compare("decimal") == 0) - reg_info.format = eFormatDecimal; - else if (value.compare("hex") == 0) - reg_info.format = eFormatHex; - else if (value.compare("float") == 0) - reg_info.format = eFormatFloat; - else if (value.compare("vector-sint8") == 0) - reg_info.format = eFormatVectorOfSInt8; - else if (value.compare("vector-uint8") == 0) - reg_info.format = eFormatVectorOfUInt8; - else if (value.compare("vector-sint16") == 0) - reg_info.format = eFormatVectorOfSInt16; - else if (value.compare("vector-uint16") == 0) - reg_info.format = eFormatVectorOfUInt16; - else if (value.compare("vector-sint32") == 0) - reg_info.format = eFormatVectorOfSInt32; - else if (value.compare("vector-uint32") == 0) - reg_info.format = eFormatVectorOfUInt32; - else if (value.compare("vector-float32") == 0) - reg_info.format = eFormatVectorOfFloat32; - else if (value.compare("vector-uint128") == 0) - reg_info.format = eFormatVectorOfUInt128; - } - else if (name.compare("set") == 0) - { - set_name.SetCString(value.c_str()); - } - else if (name.compare("gcc") == 0 || name.compare("ehframe") == 0) - { - reg_info.kinds[eRegisterKindEHFrame] = StringConvert::ToUInt32(value.c_str(), LLDB_INVALID_REGNUM, 0); - } - else if (name.compare("dwarf") == 0) - { - reg_info.kinds[eRegisterKindDWARF] = StringConvert::ToUInt32(value.c_str(), LLDB_INVALID_REGNUM, 0); - } - else if (name.compare("generic") == 0) - { - reg_info.kinds[eRegisterKindGeneric] = Args::StringToGenericRegister (value.c_str()); - } - else if (name.compare("container-regs") == 0) - { - SplitCommaSeparatedRegisterNumberString(value, value_regs, 16); - } - else if (name.compare("invalidate-regs") == 0) - { - SplitCommaSeparatedRegisterNumberString(value, invalidate_regs, 16); - } - else if (name.compare("dynamic_size_dwarf_expr_bytes") == 0) - { - size_t dwarf_opcode_len = value.length () / 2; - assert (dwarf_opcode_len > 0); - - dwarf_opcode_bytes.resize (dwarf_opcode_len); - StringExtractor opcode_extractor; - reg_info.dynamic_size_dwarf_len = dwarf_opcode_len; - - // Swap "value" over into "opcode_extractor" - opcode_extractor.GetStringRef ().swap (value); - uint32_t ret_val = opcode_extractor.GetHexBytesAvail (dwarf_opcode_bytes.data (), - dwarf_opcode_len); - assert (dwarf_opcode_len == ret_val); - - reg_info.dynamic_size_dwarf_expr_bytes = dwarf_opcode_bytes.data (); - } - } - - reg_info.byte_offset = reg_offset; - assert (reg_info.byte_size != 0); - reg_offset += reg_info.byte_size; - if (!value_regs.empty()) - { - value_regs.push_back(LLDB_INVALID_REGNUM); - reg_info.value_regs = value_regs.data(); - } - if (!invalidate_regs.empty()) - { - invalidate_regs.push_back(LLDB_INVALID_REGNUM); - reg_info.invalidate_regs = invalidate_regs.data(); - } - - // We have to make a temporary ABI here, and not use the GetABI because this code - // gets called in DidAttach, when the target architecture (and consequently the ABI we'll get from - // the process) may be wrong. - ABISP abi_to_use = ABI::FindPlugin(arch_to_use); - - AugmentRegisterInfoViaABI (reg_info, reg_name, abi_to_use); + LLDB_INVALID_REGNUM, // eh_frame reg num + LLDB_INVALID_REGNUM, // DWARF reg num + LLDB_INVALID_REGNUM, // generic reg num + reg_num, // process plugin reg num + reg_num // native register number + }, + NULL, + NULL, + NULL, // Dwarf expression opcode bytes pointer + 0 // Dwarf expression opcode bytes length + }; - m_register_info.AddRegister(reg_info, reg_name, alt_name, set_name); + while (response.GetNameColonValue(name, value)) { + if (name.equals("name")) { + reg_name.SetString(value); + } else if (name.equals("alt-name")) { + alt_name.SetString(value); + } else if (name.equals("bitsize")) { + value.getAsInteger(0, reg_info.byte_size); + reg_info.byte_size /= CHAR_BIT; + } else if (name.equals("offset")) { + if (value.getAsInteger(0, reg_offset)) + reg_offset = UINT32_MAX; + } else if (name.equals("encoding")) { + const Encoding encoding = Args::StringToEncoding(value); + if (encoding != eEncodingInvalid) + reg_info.encoding = encoding; + } else if (name.equals("format")) { + Format format = eFormatInvalid; + if (Args::StringToFormat(value.str().c_str(), format, NULL) + .Success()) + reg_info.format = format; + else { + reg_info.format = + llvm::StringSwitch<Format>(value) + .Case("binary", eFormatBinary) + .Case("decimal", eFormatDecimal) + .Case("hex", eFormatHex) + .Case("float", eFormatFloat) + .Case("vector-sint8", eFormatVectorOfSInt8) + .Case("vector-uint8", eFormatVectorOfUInt8) + .Case("vector-sint16", eFormatVectorOfSInt16) + .Case("vector-uint16", eFormatVectorOfUInt16) + .Case("vector-sint32", eFormatVectorOfSInt32) + .Case("vector-uint32", eFormatVectorOfUInt32) + .Case("vector-float32", eFormatVectorOfFloat32) + .Case("vector-uint64", eFormatVectorOfUInt64) + .Case("vector-uint128", eFormatVectorOfUInt128) + .Default(eFormatInvalid); } - else - { - break; // ensure exit before reg_num is incremented - } - } - else - { - break; + } else if (name.equals("set")) { + set_name.SetString(value); + } else if (name.equals("gcc") || name.equals("ehframe")) { + if (value.getAsInteger(0, reg_info.kinds[eRegisterKindEHFrame])) + reg_info.kinds[eRegisterKindEHFrame] = LLDB_INVALID_REGNUM; + } else if (name.equals("dwarf")) { + if (value.getAsInteger(0, reg_info.kinds[eRegisterKindDWARF])) + reg_info.kinds[eRegisterKindDWARF] = LLDB_INVALID_REGNUM; + } else if (name.equals("generic")) { + reg_info.kinds[eRegisterKindGeneric] = + Args::StringToGenericRegister(value); + } else if (name.equals("container-regs")) { + SplitCommaSeparatedRegisterNumberString(value, value_regs, 16); + } else if (name.equals("invalidate-regs")) { + SplitCommaSeparatedRegisterNumberString(value, invalidate_regs, 16); + } else if (name.equals("dynamic_size_dwarf_expr_bytes")) { + size_t dwarf_opcode_len = value.size() / 2; + assert(dwarf_opcode_len > 0); + + dwarf_opcode_bytes.resize(dwarf_opcode_len); + reg_info.dynamic_size_dwarf_len = dwarf_opcode_len; + + StringExtractor opcode_extractor(value); + uint32_t ret_val = + opcode_extractor.GetHexBytesAvail(dwarf_opcode_bytes); + assert(dwarf_opcode_len == ret_val); + + reg_info.dynamic_size_dwarf_expr_bytes = dwarf_opcode_bytes.data(); + } } - } - if (m_register_info.GetNumRegisters() > 0) - { - m_register_info.Finalize(GetTarget().GetArchitecture()); - return; - } + reg_info.byte_offset = reg_offset; + assert(reg_info.byte_size != 0); + reg_offset += reg_info.byte_size; + if (!value_regs.empty()) { + value_regs.push_back(LLDB_INVALID_REGNUM); + reg_info.value_regs = value_regs.data(); + } + if (!invalidate_regs.empty()) { + invalidate_regs.push_back(LLDB_INVALID_REGNUM); + reg_info.invalidate_regs = invalidate_regs.data(); + } - // We didn't get anything if the accumulated reg_num is zero. See if we are - // debugging ARM and fill with a hard coded register set until we can get an - // updated debugserver down on the devices. - // On the other hand, if the accumulated reg_num is positive, see if we can - // add composite registers to the existing primordial ones. - bool from_scratch = (m_register_info.GetNumRegisters() == 0); + // We have to make a temporary ABI here, and not use the GetABI because + // this code + // gets called in DidAttach, when the target architecture (and + // consequently the ABI we'll get from + // the process) may be wrong. + ABISP abi_to_use = ABI::FindPlugin(arch_to_use); - if (!target_arch.IsValid()) - { - if (arch_to_use.IsValid() - && (arch_to_use.GetMachine() == llvm::Triple::arm || arch_to_use.GetMachine() == llvm::Triple::thumb) - && arch_to_use.GetTriple().getVendor() == llvm::Triple::Apple) - m_register_info.HardcodeARMRegisters(from_scratch); - } - else if (target_arch.GetMachine() == llvm::Triple::arm - || target_arch.GetMachine() == llvm::Triple::thumb) - { - m_register_info.HardcodeARMRegisters(from_scratch); - } + AugmentRegisterInfoViaABI(reg_info, reg_name, abi_to_use); - // At this point, we can finalize our register info. - m_register_info.Finalize (GetTarget().GetArchitecture()); + m_register_info.AddRegister(reg_info, reg_name, alt_name, set_name); + } else { + break; // ensure exit before reg_num is incremented + } + } else { + break; + } + } + + if (m_register_info.GetNumRegisters() > 0) { + m_register_info.Finalize(GetTarget().GetArchitecture()); + return; + } + + // We didn't get anything if the accumulated reg_num is zero. See if we are + // debugging ARM and fill with a hard coded register set until we can get an + // updated debugserver down on the devices. + // On the other hand, if the accumulated reg_num is positive, see if we can + // add composite registers to the existing primordial ones. + bool from_scratch = (m_register_info.GetNumRegisters() == 0); + + if (!target_arch.IsValid()) { + if (arch_to_use.IsValid() && + (arch_to_use.GetMachine() == llvm::Triple::arm || + arch_to_use.GetMachine() == llvm::Triple::thumb) && + arch_to_use.GetTriple().getVendor() == llvm::Triple::Apple) + m_register_info.HardcodeARMRegisters(from_scratch); + } else if (target_arch.GetMachine() == llvm::Triple::arm || + target_arch.GetMachine() == llvm::Triple::thumb) { + m_register_info.HardcodeARMRegisters(from_scratch); + } + + // At this point, we can finalize our register info. + m_register_info.Finalize(GetTarget().GetArchitecture()); } -Error -ProcessGDBRemote::WillLaunch (Module* module) -{ - return WillLaunchOrAttach (); +Error ProcessGDBRemote::WillLaunch(Module *module) { + return WillLaunchOrAttach(); } -Error -ProcessGDBRemote::WillAttachToProcessWithID (lldb::pid_t pid) -{ - return WillLaunchOrAttach (); +Error ProcessGDBRemote::WillAttachToProcessWithID(lldb::pid_t pid) { + return WillLaunchOrAttach(); } -Error -ProcessGDBRemote::WillAttachToProcessWithName (const char *process_name, bool wait_for_launch) -{ - return WillLaunchOrAttach (); +Error ProcessGDBRemote::WillAttachToProcessWithName(const char *process_name, + bool wait_for_launch) { + return WillLaunchOrAttach(); } -Error -ProcessGDBRemote::DoConnectRemote (Stream *strm, const char *remote_url) -{ - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); - Error error (WillLaunchOrAttach ()); - - if (error.Fail()) - return error; - - error = ConnectToDebugserver (remote_url); +Error ProcessGDBRemote::DoConnectRemote(Stream *strm, + llvm::StringRef remote_url) { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + Error error(WillLaunchOrAttach()); - if (error.Fail()) - return error; - StartAsyncThread (); - - lldb::pid_t pid = m_gdb_comm.GetCurrentProcessID (); - if (pid == LLDB_INVALID_PROCESS_ID) - { - // We don't have a valid process ID, so note that we are connected - // and could now request to launch or attach, or get remote process - // listings... - SetPrivateState (eStateConnected); - } - else - { - // We have a valid process - SetID (pid); - GetThreadList(); - StringExtractorGDBRemote response; - if (m_gdb_comm.GetStopReply(response)) - { - SetLastStopPacket(response); + if (error.Fail()) + return error; - // '?' Packets must be handled differently in non-stop mode - if (GetTarget().GetNonStopModeEnabled()) - HandleStopReplySequence(); + error = ConnectToDebugserver(remote_url); - Target &target = GetTarget(); - if (!target.GetArchitecture().IsValid()) - { - if (m_gdb_comm.GetProcessArchitecture().IsValid()) - { - target.SetArchitecture(m_gdb_comm.GetProcessArchitecture()); - } - else - { - target.SetArchitecture(m_gdb_comm.GetHostArchitecture()); - } - } - - const StateType state = SetThreadStopInfo (response); - if (state != eStateInvalid) - { - SetPrivateState (state); - } - else - error.SetErrorStringWithFormat ("Process %" PRIu64 " was reported after connecting to '%s', but state was not stopped: %s", pid, remote_url, StateAsCString (state)); + if (error.Fail()) + return error; + StartAsyncThread(); + + lldb::pid_t pid = m_gdb_comm.GetCurrentProcessID(); + if (pid == LLDB_INVALID_PROCESS_ID) { + // We don't have a valid process ID, so note that we are connected + // and could now request to launch or attach, or get remote process + // listings... + SetPrivateState(eStateConnected); + } else { + // We have a valid process + SetID(pid); + GetThreadList(); + StringExtractorGDBRemote response; + if (m_gdb_comm.GetStopReply(response)) { + SetLastStopPacket(response); + + // '?' Packets must be handled differently in non-stop mode + if (GetTarget().GetNonStopModeEnabled()) + HandleStopReplySequence(); + + Target &target = GetTarget(); + if (!target.GetArchitecture().IsValid()) { + if (m_gdb_comm.GetProcessArchitecture().IsValid()) { + target.SetArchitecture(m_gdb_comm.GetProcessArchitecture()); + } else { + target.SetArchitecture(m_gdb_comm.GetHostArchitecture()); } - else - error.SetErrorStringWithFormat ("Process %" PRIu64 " was reported after connecting to '%s', but no stop reply packet was received", pid, remote_url); - } - - if (log) - log->Printf ("ProcessGDBRemote::%s pid %" PRIu64 ": normalizing target architecture initial triple: %s (GetTarget().GetArchitecture().IsValid() %s, m_gdb_comm.GetHostArchitecture().IsValid(): %s)", __FUNCTION__, GetID (), GetTarget ().GetArchitecture ().GetTriple ().getTriple ().c_str (), GetTarget ().GetArchitecture ().IsValid () ? "true" : "false", m_gdb_comm.GetHostArchitecture ().IsValid () ? "true" : "false"); - - - if (error.Success() - && !GetTarget().GetArchitecture().IsValid() - && m_gdb_comm.GetHostArchitecture().IsValid()) - { - // Prefer the *process'* architecture over that of the *host*, if available. - if (m_gdb_comm.GetProcessArchitecture().IsValid()) - GetTarget().SetArchitecture(m_gdb_comm.GetProcessArchitecture()); - else - GetTarget().SetArchitecture(m_gdb_comm.GetHostArchitecture()); - } - - if (log) - log->Printf ("ProcessGDBRemote::%s pid %" PRIu64 ": normalized target architecture triple: %s", __FUNCTION__, GetID (), GetTarget ().GetArchitecture ().GetTriple ().getTriple ().c_str ()); - - if (error.Success()) - { - PlatformSP platform_sp = GetTarget().GetPlatform(); - if (platform_sp && platform_sp->IsConnected()) - SetUnixSignals(platform_sp->GetUnixSignals()); - else - SetUnixSignals(UnixSignals::Create(GetTarget().GetArchitecture())); - } + } + + const StateType state = SetThreadStopInfo(response); + if (state != eStateInvalid) { + SetPrivateState(state); + } else + error.SetErrorStringWithFormat( + "Process %" PRIu64 " was reported after connecting to " + "'%s', but state was not stopped: %s", + pid, remote_url.str().c_str(), StateAsCString(state)); + } else + error.SetErrorStringWithFormat("Process %" PRIu64 + " was reported after connecting to '%s', " + "but no stop reply packet was received", + pid, remote_url.str().c_str()); + } + + if (log) + log->Printf("ProcessGDBRemote::%s pid %" PRIu64 + ": normalizing target architecture initial triple: %s " + "(GetTarget().GetArchitecture().IsValid() %s, " + "m_gdb_comm.GetHostArchitecture().IsValid(): %s)", + __FUNCTION__, GetID(), + GetTarget().GetArchitecture().GetTriple().getTriple().c_str(), + GetTarget().GetArchitecture().IsValid() ? "true" : "false", + m_gdb_comm.GetHostArchitecture().IsValid() ? "true" : "false"); + + if (error.Success() && !GetTarget().GetArchitecture().IsValid() && + m_gdb_comm.GetHostArchitecture().IsValid()) { + // Prefer the *process'* architecture over that of the *host*, if available. + if (m_gdb_comm.GetProcessArchitecture().IsValid()) + GetTarget().SetArchitecture(m_gdb_comm.GetProcessArchitecture()); + else + GetTarget().SetArchitecture(m_gdb_comm.GetHostArchitecture()); + } + + if (log) + log->Printf("ProcessGDBRemote::%s pid %" PRIu64 + ": normalized target architecture triple: %s", + __FUNCTION__, GetID(), + GetTarget().GetArchitecture().GetTriple().getTriple().c_str()); + + if (error.Success()) { + PlatformSP platform_sp = GetTarget().GetPlatform(); + if (platform_sp && platform_sp->IsConnected()) + SetUnixSignals(platform_sp->GetUnixSignals()); + else + SetUnixSignals(UnixSignals::Create(GetTarget().GetArchitecture())); + } - return error; + return error; } -Error -ProcessGDBRemote::WillLaunchOrAttach () -{ - Error error; - m_stdio_communication.Clear (); - return error; +Error ProcessGDBRemote::WillLaunchOrAttach() { + Error error; + m_stdio_communication.Clear(); + return error; } //---------------------------------------------------------------------- // Process Control //---------------------------------------------------------------------- -Error -ProcessGDBRemote::DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info) -{ - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); - Error error; - - if (log) - log->Printf ("ProcessGDBRemote::%s() entered", __FUNCTION__); - - uint32_t launch_flags = launch_info.GetFlags().Get(); - FileSpec stdin_file_spec{}; - FileSpec stdout_file_spec{}; - FileSpec stderr_file_spec{}; - FileSpec working_dir = launch_info.GetWorkingDirectory(); - - const FileAction *file_action; - file_action = launch_info.GetFileActionForFD (STDIN_FILENO); - if (file_action) - { - if (file_action->GetAction() == FileAction::eFileActionOpen) - stdin_file_spec = file_action->GetFileSpec(); - } - file_action = launch_info.GetFileActionForFD (STDOUT_FILENO); - if (file_action) - { - if (file_action->GetAction() == FileAction::eFileActionOpen) - stdout_file_spec = file_action->GetFileSpec(); - } - file_action = launch_info.GetFileActionForFD (STDERR_FILENO); - if (file_action) - { - if (file_action->GetAction() == FileAction::eFileActionOpen) - stderr_file_spec = file_action->GetFileSpec(); - } - - if (log) - { - if (stdin_file_spec || stdout_file_spec || stderr_file_spec) - log->Printf ("ProcessGDBRemote::%s provided with STDIO paths via launch_info: stdin=%s, stdout=%s, stderr=%s", - __FUNCTION__, - stdin_file_spec ? stdin_file_spec.GetCString() : "<null>", - stdout_file_spec ? stdout_file_spec.GetCString() : "<null>", - stderr_file_spec ? stderr_file_spec.GetCString() : "<null>"); - else - log->Printf ("ProcessGDBRemote::%s no STDIO paths given via launch_info", __FUNCTION__); - } - - const bool disable_stdio = (launch_flags & eLaunchFlagDisableSTDIO) != 0; - if (stdin_file_spec || disable_stdio) - { - // the inferior will be reading stdin from the specified file - // or stdio is completely disabled - m_stdin_forward = false; - } +Error ProcessGDBRemote::DoLaunch(Module *exe_module, + ProcessLaunchInfo &launch_info) { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + Error error; + + if (log) + log->Printf("ProcessGDBRemote::%s() entered", __FUNCTION__); + + uint32_t launch_flags = launch_info.GetFlags().Get(); + FileSpec stdin_file_spec{}; + FileSpec stdout_file_spec{}; + FileSpec stderr_file_spec{}; + FileSpec working_dir = launch_info.GetWorkingDirectory(); + + const FileAction *file_action; + file_action = launch_info.GetFileActionForFD(STDIN_FILENO); + if (file_action) { + if (file_action->GetAction() == FileAction::eFileActionOpen) + stdin_file_spec = file_action->GetFileSpec(); + } + file_action = launch_info.GetFileActionForFD(STDOUT_FILENO); + if (file_action) { + if (file_action->GetAction() == FileAction::eFileActionOpen) + stdout_file_spec = file_action->GetFileSpec(); + } + file_action = launch_info.GetFileActionForFD(STDERR_FILENO); + if (file_action) { + if (file_action->GetAction() == FileAction::eFileActionOpen) + stderr_file_spec = file_action->GetFileSpec(); + } + + if (log) { + if (stdin_file_spec || stdout_file_spec || stderr_file_spec) + log->Printf("ProcessGDBRemote::%s provided with STDIO paths via " + "launch_info: stdin=%s, stdout=%s, stderr=%s", + __FUNCTION__, + stdin_file_spec ? stdin_file_spec.GetCString() : "<null>", + stdout_file_spec ? stdout_file_spec.GetCString() : "<null>", + stderr_file_spec ? stderr_file_spec.GetCString() : "<null>"); else - { - m_stdin_forward = true; - } - - // ::LogSetBitMask (GDBR_LOG_DEFAULT); - // ::LogSetOptions (LLDB_LOG_OPTION_THREADSAFE | LLDB_LOG_OPTION_PREPEND_TIMESTAMP | LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD); - // ::LogSetLogFile ("/dev/stdout"); - - ObjectFile * object_file = exe_module->GetObjectFile(); - if (object_file) - { - error = EstablishConnectionIfNeeded (launch_info); - if (error.Success()) - { - lldb_utility::PseudoTerminal pty; - const bool disable_stdio = (launch_flags & eLaunchFlagDisableSTDIO) != 0; - - PlatformSP platform_sp (GetTarget().GetPlatform()); - 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); - if (!stdout_file_spec) - stdout_file_spec.SetFile(FileSystem::DEV_NULL, false); - if (!stderr_file_spec) - stderr_file_spec.SetFile(FileSystem::DEV_NULL, false); - } - else if (platform_sp && platform_sp->IsHost()) - { - // If the debugserver is local and we aren't disabling STDIO, lets use - // a pseudo terminal to instead of relying on the 'O' packets for stdio - // since 'O' packets can really slow down debugging if the inferior - // 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}; - - if (!stdin_file_spec) - stdin_file_spec = slave_name; - - if (!stdout_file_spec) - stdout_file_spec = slave_name; - - if (!stderr_file_spec) - stderr_file_spec = slave_name; - } - if (log) - log->Printf ("ProcessGDBRemote::%s adjusted STDIO paths for local platform (IsHost() is true) using slave: stdin=%s, stdout=%s, stderr=%s", - __FUNCTION__, - stdin_file_spec ? stdin_file_spec.GetCString() : "<null>", - stdout_file_spec ? stdout_file_spec.GetCString() : "<null>", - stderr_file_spec ? stderr_file_spec.GetCString() : "<null>"); - } - - if (log) - log->Printf ("ProcessGDBRemote::%s final STDIO paths after all adjustments: stdin=%s, stdout=%s, stderr=%s", - __FUNCTION__, - stdin_file_spec ? stdin_file_spec.GetCString() : "<null>", - stdout_file_spec ? stdout_file_spec.GetCString() : "<null>", - stderr_file_spec ? stderr_file_spec.GetCString() : "<null>"); - - if (stdin_file_spec) - m_gdb_comm.SetSTDIN(stdin_file_spec); - if (stdout_file_spec) - m_gdb_comm.SetSTDOUT(stdout_file_spec); - if (stderr_file_spec) - m_gdb_comm.SetSTDERR(stderr_file_spec); - - m_gdb_comm.SetDisableASLR (launch_flags & eLaunchFlagDisableASLR); - m_gdb_comm.SetDetachOnError (launch_flags & eLaunchFlagDetachOnError); - - m_gdb_comm.SendLaunchArchPacket (GetTarget().GetArchitecture().GetArchitectureName()); - - const char * launch_event_data = launch_info.GetLaunchEventData(); - if (launch_event_data != NULL && *launch_event_data != '\0') - m_gdb_comm.SendLaunchEventDataPacket (launch_event_data); - - if (working_dir) - { - m_gdb_comm.SetWorkingDir (working_dir); - } - - // Send the environment and the program + arguments after we connect - const Args &environment = launch_info.GetEnvironmentEntries(); - if (environment.GetArgumentCount()) - { - size_t num_environment_entries = environment.GetArgumentCount(); - for (size_t i=0; i<num_environment_entries; ++i) - { - const char *env_entry = environment.GetArgumentAtIndex(i); - if (env_entry == NULL || m_gdb_comm.SendEnvironmentPacket(env_entry) != 0) - break; - } - } - - { - // Scope for the scoped timeout object - GDBRemoteCommunication::ScopedTimeout timeout (m_gdb_comm, 10); - - int arg_packet_err = m_gdb_comm.SendArgumentsPacket (launch_info); - if (arg_packet_err == 0) - { - std::string error_str; - if (m_gdb_comm.GetLaunchSuccess (error_str)) - { - SetID (m_gdb_comm.GetCurrentProcessID ()); - } - else - { - error.SetErrorString (error_str.c_str()); - } - } - else - { - error.SetErrorStringWithFormat("'A' packet returned an error: %i", arg_packet_err); - } - } - - if (GetID() == LLDB_INVALID_PROCESS_ID) - { - if (log) - log->Printf("failed to connect to debugserver: %s", error.AsCString()); - KillDebugserverProcess (); - return error; - } - - StringExtractorGDBRemote response; - if (m_gdb_comm.GetStopReply(response)) - { - SetLastStopPacket(response); - // '?' Packets must be handled differently in non-stop mode - if (GetTarget().GetNonStopModeEnabled()) - HandleStopReplySequence(); - - const ArchSpec &process_arch = m_gdb_comm.GetProcessArchitecture(); - - if (process_arch.IsValid()) - { - GetTarget().MergeArchitecture(process_arch); - } - else - { - const ArchSpec &host_arch = m_gdb_comm.GetHostArchitecture(); - if (host_arch.IsValid()) - GetTarget().MergeArchitecture(host_arch); - } - - SetPrivateState (SetThreadStopInfo (response)); - - if (!disable_stdio) - { - if (pty.GetMasterFileDescriptor() != lldb_utility::PseudoTerminal::invalid_fd) - SetSTDIOFileDescriptor (pty.ReleaseMasterFileDescriptor()); - } - } + log->Printf("ProcessGDBRemote::%s no STDIO paths given via launch_info", + __FUNCTION__); + } + + const bool disable_stdio = (launch_flags & eLaunchFlagDisableSTDIO) != 0; + if (stdin_file_spec || disable_stdio) { + // the inferior will be reading stdin from the specified file + // or stdio is completely disabled + m_stdin_forward = false; + } else { + m_stdin_forward = true; + } + + // ::LogSetBitMask (GDBR_LOG_DEFAULT); + // ::LogSetOptions (LLDB_LOG_OPTION_THREADSAFE | + // LLDB_LOG_OPTION_PREPEND_TIMESTAMP | + // LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD); + // ::LogSetLogFile ("/dev/stdout"); + + ObjectFile *object_file = exe_module->GetObjectFile(); + if (object_file) { + error = EstablishConnectionIfNeeded(launch_info); + if (error.Success()) { + lldb_utility::PseudoTerminal pty; + const bool disable_stdio = (launch_flags & eLaunchFlagDisableSTDIO) != 0; + + PlatformSP platform_sp(GetTarget().GetPlatform()); + 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); + if (!stdout_file_spec) + stdout_file_spec.SetFile(FileSystem::DEV_NULL, false); + if (!stderr_file_spec) + stderr_file_spec.SetFile(FileSystem::DEV_NULL, false); + } else if (platform_sp && platform_sp->IsHost()) { + // If the debugserver is local and we aren't disabling STDIO, lets use + // a pseudo terminal to instead of relying on the 'O' packets for stdio + // since 'O' packets can really slow down debugging if the inferior + // 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}; + + if (!stdin_file_spec) + stdin_file_spec = slave_name; + + if (!stdout_file_spec) + stdout_file_spec = slave_name; + + if (!stderr_file_spec) + stderr_file_spec = slave_name; } - else - { - if (log) - log->Printf("failed to connect to debugserver: %s", error.AsCString()); + if (log) + log->Printf( + "ProcessGDBRemote::%s adjusted STDIO paths for local platform " + "(IsHost() is true) using slave: stdin=%s, stdout=%s, stderr=%s", + __FUNCTION__, + stdin_file_spec ? stdin_file_spec.GetCString() : "<null>", + stdout_file_spec ? stdout_file_spec.GetCString() : "<null>", + stderr_file_spec ? stderr_file_spec.GetCString() : "<null>"); + } + + if (log) + log->Printf("ProcessGDBRemote::%s final STDIO paths after all " + "adjustments: stdin=%s, stdout=%s, stderr=%s", + __FUNCTION__, + stdin_file_spec ? stdin_file_spec.GetCString() : "<null>", + stdout_file_spec ? stdout_file_spec.GetCString() : "<null>", + stderr_file_spec ? stderr_file_spec.GetCString() + : "<null>"); + + if (stdin_file_spec) + m_gdb_comm.SetSTDIN(stdin_file_spec); + if (stdout_file_spec) + m_gdb_comm.SetSTDOUT(stdout_file_spec); + if (stderr_file_spec) + m_gdb_comm.SetSTDERR(stderr_file_spec); + + m_gdb_comm.SetDisableASLR(launch_flags & eLaunchFlagDisableASLR); + m_gdb_comm.SetDetachOnError(launch_flags & eLaunchFlagDetachOnError); + + m_gdb_comm.SendLaunchArchPacket( + GetTarget().GetArchitecture().GetArchitectureName()); + + const char *launch_event_data = launch_info.GetLaunchEventData(); + if (launch_event_data != NULL && *launch_event_data != '\0') + m_gdb_comm.SendLaunchEventDataPacket(launch_event_data); + + if (working_dir) { + m_gdb_comm.SetWorkingDir(working_dir); + } + + // Send the environment and the program + arguments after we connect + const Args &environment = launch_info.GetEnvironmentEntries(); + if (environment.GetArgumentCount()) { + size_t num_environment_entries = environment.GetArgumentCount(); + for (size_t i = 0; i < num_environment_entries; ++i) { + const char *env_entry = environment.GetArgumentAtIndex(i); + if (env_entry == NULL || + m_gdb_comm.SendEnvironmentPacket(env_entry) != 0) + break; } - } - else - { - // Set our user ID to an invalid process ID. - SetID(LLDB_INVALID_PROCESS_ID); - error.SetErrorStringWithFormat ("failed to get object file from '%s' for arch %s", - exe_module->GetFileSpec().GetFilename().AsCString(), - exe_module->GetArchitecture().GetArchitectureName()); - } - return error; - -} - + } -Error -ProcessGDBRemote::ConnectToDebugserver (const char *connect_url) -{ - Error error; - // Only connect if we have a valid connect URL - Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + { + // Scope for the scoped timeout object + GDBRemoteCommunication::ScopedTimeout timeout(m_gdb_comm, + std::chrono::seconds(10)); + + int arg_packet_err = m_gdb_comm.SendArgumentsPacket(launch_info); + if (arg_packet_err == 0) { + std::string error_str; + if (m_gdb_comm.GetLaunchSuccess(error_str)) { + SetID(m_gdb_comm.GetCurrentProcessID()); + } else { + error.SetErrorString(error_str.c_str()); + } + } else { + error.SetErrorStringWithFormat("'A' packet returned an error: %i", + arg_packet_err); + } + } - if (connect_url && connect_url[0]) - { + if (GetID() == LLDB_INVALID_PROCESS_ID) { if (log) - log->Printf("ProcessGDBRemote::%s Connecting to %s", __FUNCTION__, connect_url); - std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor()); - if (conn_ap.get()) - { - const uint32_t max_retry_count = 50; - uint32_t retry_count = 0; - while (!m_gdb_comm.IsConnected()) - { - if (conn_ap->Connect(connect_url, &error) == eConnectionStatusSuccess) - { - m_gdb_comm.SetConnection (conn_ap.release()); - break; - } - else if (error.WasInterrupted()) - { - // If we were interrupted, don't keep retrying. - break; - } + log->Printf("failed to connect to debugserver: %s", + error.AsCString()); + KillDebugserverProcess(); + return error; + } - retry_count++; + StringExtractorGDBRemote response; + if (m_gdb_comm.GetStopReply(response)) { + SetLastStopPacket(response); + // '?' Packets must be handled differently in non-stop mode + if (GetTarget().GetNonStopModeEnabled()) + HandleStopReplySequence(); + + const ArchSpec &process_arch = m_gdb_comm.GetProcessArchitecture(); + + if (process_arch.IsValid()) { + GetTarget().MergeArchitecture(process_arch); + } else { + const ArchSpec &host_arch = m_gdb_comm.GetHostArchitecture(); + if (host_arch.IsValid()) + GetTarget().MergeArchitecture(host_arch); + } - if (retry_count >= max_retry_count) - break; + SetPrivateState(SetThreadStopInfo(response)); - usleep (100000); - } + if (!disable_stdio) { + if (pty.GetMasterFileDescriptor() != + lldb_utility::PseudoTerminal::invalid_fd) + SetSTDIOFileDescriptor(pty.ReleaseMasterFileDescriptor()); } - } + } + } else { + if (log) + log->Printf("failed to connect to debugserver: %s", error.AsCString()); + } + } else { + // Set our user ID to an invalid process ID. + SetID(LLDB_INVALID_PROCESS_ID); + error.SetErrorStringWithFormat( + "failed to get object file from '%s' for arch %s", + exe_module->GetFileSpec().GetFilename().AsCString(), + exe_module->GetArchitecture().GetArchitectureName()); + } + return error; +} - if (!m_gdb_comm.IsConnected()) - { - if (error.Success()) - error.SetErrorString("not connected to remote gdb server"); - return error; - } +Error ProcessGDBRemote::ConnectToDebugserver(llvm::StringRef connect_url) { + Error error; + // Only connect if we have a valid connect URL + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + if (!connect_url.empty()) { + if (log) + log->Printf("ProcessGDBRemote::%s Connecting to %s", __FUNCTION__, + connect_url.str().c_str()); + std::unique_ptr<ConnectionFileDescriptor> conn_ap( + new ConnectionFileDescriptor()); + if (conn_ap.get()) { + const uint32_t max_retry_count = 50; + uint32_t retry_count = 0; + while (!m_gdb_comm.IsConnected()) { + if (conn_ap->Connect(connect_url, &error) == eConnectionStatusSuccess) { + m_gdb_comm.SetConnection(conn_ap.release()); + break; + } else if (error.WasInterrupted()) { + // If we were interrupted, don't keep retrying. + break; + } - // Start the communications read thread so all incoming data can be - // parsed into packets and queued as they arrive. - if (GetTarget().GetNonStopModeEnabled()) - m_gdb_comm.StartReadThread(); + retry_count++; - // We always seem to be able to open a connection to a local port - // so we need to make sure we can then send data to it. If we can't - // then we aren't actually connected to anything, so try and do the - // handshake with the remote GDB server and make sure that goes - // alright. - if (!m_gdb_comm.HandshakeWithServer (&error)) - { - m_gdb_comm.Disconnect(); - if (error.Success()) - error.SetErrorString("not connected to remote gdb server"); - return error; + if (retry_count >= max_retry_count) + break; + + usleep(100000); + } } + } - // Send $QNonStop:1 packet on startup if required - if (GetTarget().GetNonStopModeEnabled()) - GetTarget().SetNonStopModeEnabled (m_gdb_comm.SetNonStopMode(true)); + if (!m_gdb_comm.IsConnected()) { + if (error.Success()) + error.SetErrorString("not connected to remote gdb server"); + return error; + } + + // Start the communications read thread so all incoming data can be + // parsed into packets and queued as they arrive. + if (GetTarget().GetNonStopModeEnabled()) + m_gdb_comm.StartReadThread(); + + // We always seem to be able to open a connection to a local port + // so we need to make sure we can then send data to it. If we can't + // then we aren't actually connected to anything, so try and do the + // handshake with the remote GDB server and make sure that goes + // alright. + if (!m_gdb_comm.HandshakeWithServer(&error)) { + m_gdb_comm.Disconnect(); + if (error.Success()) + error.SetErrorString("not connected to remote gdb server"); + return error; + } - m_gdb_comm.GetEchoSupported (); - m_gdb_comm.GetThreadSuffixSupported (); - m_gdb_comm.GetListThreadsInStopReplySupported (); - m_gdb_comm.GetHostInfo (); - m_gdb_comm.GetVContSupported ('c'); - m_gdb_comm.GetVAttachOrWaitSupported(); + // Send $QNonStop:1 packet on startup if required + if (GetTarget().GetNonStopModeEnabled()) + GetTarget().SetNonStopModeEnabled(m_gdb_comm.SetNonStopMode(true)); - // Ask the remote server for the default thread id - if (GetTarget().GetNonStopModeEnabled()) - m_gdb_comm.GetDefaultThreadId(m_initial_tid); + m_gdb_comm.GetEchoSupported(); + m_gdb_comm.GetThreadSuffixSupported(); + m_gdb_comm.GetListThreadsInStopReplySupported(); + m_gdb_comm.GetHostInfo(); + m_gdb_comm.GetVContSupported('c'); + m_gdb_comm.GetVAttachOrWaitSupported(); + // Ask the remote server for the default thread id + if (GetTarget().GetNonStopModeEnabled()) + m_gdb_comm.GetDefaultThreadId(m_initial_tid); - size_t num_cmds = GetExtraStartupCommands().GetArgumentCount(); - for (size_t idx = 0; idx < num_cmds; idx++) - { - StringExtractorGDBRemote response; - m_gdb_comm.SendPacketAndWaitForResponse (GetExtraStartupCommands().GetArgumentAtIndex(idx), response, false); - } - return error; + size_t num_cmds = GetExtraStartupCommands().GetArgumentCount(); + for (size_t idx = 0; idx < num_cmds; idx++) { + StringExtractorGDBRemote response; + m_gdb_comm.SendPacketAndWaitForResponse( + GetExtraStartupCommands().GetArgumentAtIndex(idx), response, false); + } + return error; } -void -ProcessGDBRemote::DidLaunchOrAttach (ArchSpec& process_arch) -{ - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); - if (log) - log->Printf ("ProcessGDBRemote::DidLaunch()"); - if (GetID() != LLDB_INVALID_PROCESS_ID) - { - BuildDynamicRegisterInfo (false); +void ProcessGDBRemote::DidLaunchOrAttach(ArchSpec &process_arch) { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + if (log) + log->Printf("ProcessGDBRemote::%s()", __FUNCTION__); + if (GetID() != LLDB_INVALID_PROCESS_ID) { + BuildDynamicRegisterInfo(false); - // See if the GDB server supports the qHostInfo information + // See if the GDB server supports the qHostInfo information + // See if the GDB server supports the qProcessInfo packet, if so + // prefer that over the Host information as it will be more specific + // to our process. - // See if the GDB server supports the qProcessInfo packet, if so - // prefer that over the Host information as it will be more specific - // to our process. + const ArchSpec &remote_process_arch = m_gdb_comm.GetProcessArchitecture(); + if (remote_process_arch.IsValid()) { + process_arch = remote_process_arch; + if (log) + log->Printf("ProcessGDBRemote::%s gdb-remote had process architecture, " + "using %s %s", + __FUNCTION__, process_arch.GetArchitectureName() + ? process_arch.GetArchitectureName() + : "<null>", + process_arch.GetTriple().getTriple().c_str() + ? process_arch.GetTriple().getTriple().c_str() + : "<null>"); + } else { + process_arch = m_gdb_comm.GetHostArchitecture(); + 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>", + process_arch.GetTriple().getTriple().c_str() + ? process_arch.GetTriple().getTriple().c_str() + : "<null>"); + } + + if (process_arch.IsValid()) { + const ArchSpec &target_arch = GetTarget().GetArchitecture(); + if (target_arch.IsValid()) { + if (log) + log->Printf( + "ProcessGDBRemote::%s analyzing target arch, currently %s %s", + __FUNCTION__, target_arch.GetArchitectureName() + ? target_arch.GetArchitectureName() + : "<null>", + target_arch.GetTriple().getTriple().c_str() + ? target_arch.GetTriple().getTriple().c_str() + : "<null>"); + + // If the remote host is ARM and we have apple as the vendor, then + // ARM executables and shared libraries can have mixed ARM + // architectures. + // You can have an armv6 executable, and if the host is armv7, then the + // system will load the best possible architecture for all shared + // libraries + // it has, so we really need to take the remote host architecture as our + // defacto architecture in this case. + + if ((process_arch.GetMachine() == llvm::Triple::arm || + process_arch.GetMachine() == llvm::Triple::thumb) && + process_arch.GetTriple().getVendor() == llvm::Triple::Apple) { + GetTarget().SetArchitecture(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>", + process_arch.GetTriple().getTriple().c_str() + ? process_arch.GetTriple().getTriple().c_str() + : "<null>"); + } else { + // Fill in what is missing in the triple + const llvm::Triple &remote_triple = process_arch.GetTriple(); + llvm::Triple new_target_triple = target_arch.GetTriple(); + if (new_target_triple.getVendorName().size() == 0) { + new_target_triple.setVendor(remote_triple.getVendor()); + + if (new_target_triple.getOSName().size() == 0) { + new_target_triple.setOS(remote_triple.getOS()); + + if (new_target_triple.getEnvironmentName().size() == 0) + new_target_triple.setEnvironment( + remote_triple.getEnvironment()); + } - const ArchSpec &remote_process_arch = m_gdb_comm.GetProcessArchitecture(); - if (remote_process_arch.IsValid()) - { - process_arch = remote_process_arch; - if (log) - log->Printf ("ProcessGDBRemote::%s gdb-remote had process architecture, using %s %s", - __FUNCTION__, - process_arch.GetArchitectureName () ? process_arch.GetArchitectureName () : "<null>", - process_arch.GetTriple().getTriple ().c_str() ? process_arch.GetTriple().getTriple ().c_str() : "<null>"); + ArchSpec new_target_arch = target_arch; + new_target_arch.SetTriple(new_target_triple); + GetTarget().SetArchitecture(new_target_arch); + } } - else - { - process_arch = m_gdb_comm.GetHostArchitecture(); - 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>", - process_arch.GetTriple().getTriple ().c_str() ? process_arch.GetTriple().getTriple ().c_str() : "<null>"); - } - - if (process_arch.IsValid()) - { - const ArchSpec &target_arch = GetTarget().GetArchitecture(); - if (target_arch.IsValid()) - { - if (log) - log->Printf ("ProcessGDBRemote::%s analyzing target arch, currently %s %s", - __FUNCTION__, - target_arch.GetArchitectureName () ? target_arch.GetArchitectureName () : "<null>", - target_arch.GetTriple().getTriple ().c_str() ? target_arch.GetTriple().getTriple ().c_str() : "<null>"); - - // If the remote host is ARM and we have apple as the vendor, then - // ARM executables and shared libraries can have mixed ARM architectures. - // You can have an armv6 executable, and if the host is armv7, then the - // system will load the best possible architecture for all shared libraries - // it has, so we really need to take the remote host architecture as our - // defacto architecture in this case. - - if ((process_arch.GetMachine() == llvm::Triple::arm || process_arch.GetMachine() == llvm::Triple::thumb) - && process_arch.GetTriple().getVendor() == llvm::Triple::Apple) - { - GetTarget().SetArchitecture (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>", - process_arch.GetTriple().getTriple ().c_str() ? process_arch.GetTriple().getTriple ().c_str() : "<null>"); - } - else - { - // Fill in what is missing in the triple - const llvm::Triple &remote_triple = process_arch.GetTriple(); - llvm::Triple new_target_triple = target_arch.GetTriple(); - if (new_target_triple.getVendorName().size() == 0) - { - new_target_triple.setVendor (remote_triple.getVendor()); - - if (new_target_triple.getOSName().size() == 0) - { - new_target_triple.setOS (remote_triple.getOS()); - - if (new_target_triple.getEnvironmentName().size() == 0) - new_target_triple.setEnvironment (remote_triple.getEnvironment()); - } - - ArchSpec new_target_arch = target_arch; - new_target_arch.SetTriple(new_target_triple); - GetTarget().SetArchitecture(new_target_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>", - target_arch.GetTriple().getTriple ().c_str() ? target_arch.GetTriple().getTriple ().c_str() : "<null>"); - } - else - { - // The target doesn't have a valid architecture yet, set it from - // the architecture we got from the remote GDB server - GetTarget().SetArchitecture (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>", + target_arch.GetTriple().getTriple().c_str() + ? target_arch.GetTriple().getTriple().c_str() + : "<null>"); + } else { + // The target doesn't have a valid architecture yet, set it from + // the architecture we got from the remote GDB server + GetTarget().SetArchitecture(process_arch); + } + } + + // Find out which StructuredDataPlugins are supported by the + // debug monitor. These plugins transmit data over async $J packets. + auto supported_packets_array = + m_gdb_comm.GetSupportedStructuredDataPlugins(); + if (supported_packets_array) + MapSupportedStructuredDataPlugins(*supported_packets_array); + } } -void -ProcessGDBRemote::DidLaunch () -{ - ArchSpec process_arch; - DidLaunchOrAttach (process_arch); +void ProcessGDBRemote::DidLaunch() { + ArchSpec process_arch; + DidLaunchOrAttach(process_arch); } -Error -ProcessGDBRemote::DoAttachToProcessWithID (lldb::pid_t attach_pid, const ProcessAttachInfo &attach_info) -{ - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); - Error error; - - if (log) - log->Printf ("ProcessGDBRemote::%s()", __FUNCTION__); - - // Clear out and clean up from any current state - Clear(); - if (attach_pid != LLDB_INVALID_PROCESS_ID) - { - error = EstablishConnectionIfNeeded (attach_info); - if (error.Success()) - { - m_gdb_comm.SetDetachOnError(attach_info.GetDetachOnError()); - - char packet[64]; - const int packet_len = ::snprintf (packet, sizeof(packet), "vAttach;%" PRIx64, attach_pid); - SetID (attach_pid); - m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncContinue, new EventDataBytes (packet, packet_len)); - } - else - SetExitStatus (-1, error.AsCString()); - } - - return error; +Error ProcessGDBRemote::DoAttachToProcessWithID( + lldb::pid_t attach_pid, const ProcessAttachInfo &attach_info) { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + Error error; + + if (log) + log->Printf("ProcessGDBRemote::%s()", __FUNCTION__); + + // Clear out and clean up from any current state + Clear(); + if (attach_pid != LLDB_INVALID_PROCESS_ID) { + error = EstablishConnectionIfNeeded(attach_info); + if (error.Success()) { + m_gdb_comm.SetDetachOnError(attach_info.GetDetachOnError()); + + char packet[64]; + const int packet_len = + ::snprintf(packet, sizeof(packet), "vAttach;%" PRIx64, attach_pid); + SetID(attach_pid); + m_async_broadcaster.BroadcastEvent( + eBroadcastBitAsyncContinue, new EventDataBytes(packet, packet_len)); + } else + SetExitStatus(-1, error.AsCString()); + } + + return error; } -Error -ProcessGDBRemote::DoAttachToProcessWithName (const char *process_name, const ProcessAttachInfo &attach_info) -{ - Error error; - // Clear out and clean up from any current state - Clear(); - - if (process_name && process_name[0]) - { - error = EstablishConnectionIfNeeded (attach_info); - if (error.Success()) - { - StreamString packet; - - m_gdb_comm.SetDetachOnError(attach_info.GetDetachOnError()); - - if (attach_info.GetWaitForLaunch()) - { - if (!m_gdb_comm.GetVAttachOrWaitSupported()) - { - packet.PutCString ("vAttachWait"); - } - else - { - if (attach_info.GetIgnoreExisting()) - packet.PutCString("vAttachWait"); - else - packet.PutCString ("vAttachOrWait"); - } - } - else - packet.PutCString("vAttachName"); - packet.PutChar(';'); - packet.PutBytesAsRawHex8(process_name, strlen(process_name), endian::InlHostByteOrder(), endian::InlHostByteOrder()); - - m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncContinue, new EventDataBytes (packet.GetData(), packet.GetSize())); - +Error ProcessGDBRemote::DoAttachToProcessWithName( + const char *process_name, const ProcessAttachInfo &attach_info) { + Error error; + // Clear out and clean up from any current state + Clear(); + + if (process_name && process_name[0]) { + error = EstablishConnectionIfNeeded(attach_info); + if (error.Success()) { + StreamString packet; + + m_gdb_comm.SetDetachOnError(attach_info.GetDetachOnError()); + + if (attach_info.GetWaitForLaunch()) { + if (!m_gdb_comm.GetVAttachOrWaitSupported()) { + packet.PutCString("vAttachWait"); + } else { + if (attach_info.GetIgnoreExisting()) + packet.PutCString("vAttachWait"); + else + packet.PutCString("vAttachOrWait"); } - else - SetExitStatus (-1, error.AsCString()); - } - return error; + } else + packet.PutCString("vAttachName"); + packet.PutChar(';'); + packet.PutBytesAsRawHex8(process_name, strlen(process_name), + endian::InlHostByteOrder(), + endian::InlHostByteOrder()); + + m_async_broadcaster.BroadcastEvent( + eBroadcastBitAsyncContinue, + new EventDataBytes(packet.GetString().data(), packet.GetSize())); + + } else + SetExitStatus(-1, error.AsCString()); + } + return error; } -void -ProcessGDBRemote::DidExit () -{ - // When we exit, disconnect from the GDB server communications - m_gdb_comm.Disconnect(); +void ProcessGDBRemote::DidExit() { + // When we exit, disconnect from the GDB server communications + m_gdb_comm.Disconnect(); } -void -ProcessGDBRemote::DidAttach (ArchSpec &process_arch) -{ - // If you can figure out what the architecture is, fill it in here. - process_arch.Clear(); - DidLaunchOrAttach (process_arch); +void ProcessGDBRemote::DidAttach(ArchSpec &process_arch) { + // If you can figure out what the architecture is, fill it in here. + process_arch.Clear(); + DidLaunchOrAttach(process_arch); } - -Error -ProcessGDBRemote::WillResume () -{ - m_continue_c_tids.clear(); - m_continue_C_tids.clear(); - m_continue_s_tids.clear(); - m_continue_S_tids.clear(); - m_jstopinfo_sp.reset(); - m_jthreadsinfo_sp.reset(); - return Error(); +Error ProcessGDBRemote::WillResume() { + m_continue_c_tids.clear(); + m_continue_C_tids.clear(); + m_continue_s_tids.clear(); + m_continue_S_tids.clear(); + m_jstopinfo_sp.reset(); + m_jthreadsinfo_sp.reset(); + return Error(); } -Error -ProcessGDBRemote::DoResume () -{ - Error error; - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); - if (log) - log->Printf ("ProcessGDBRemote::Resume()"); - - ListenerSP listener_sp (Listener::MakeListener("gdb-remote.resume-packet-sent")); - if (listener_sp->StartListeningForEvents (&m_gdb_comm, GDBRemoteCommunication::eBroadcastBitRunPacketSent)) - { - listener_sp->StartListeningForEvents (&m_async_broadcaster, ProcessGDBRemote::eBroadcastBitAsyncThreadDidExit); - - const size_t num_threads = GetThreadList().GetSize(); - - StreamString continue_packet; - bool continue_packet_error = false; - if (m_gdb_comm.HasAnyVContSupport ()) - { - if (!GetTarget().GetNonStopModeEnabled() && - (m_continue_c_tids.size() == num_threads || - (m_continue_c_tids.empty() && - m_continue_C_tids.empty() && - m_continue_s_tids.empty() && - m_continue_S_tids.empty()))) - { - // All threads are continuing, just send a "c" packet - continue_packet.PutCString ("c"); - } - else - { - continue_packet.PutCString ("vCont"); - - if (!m_continue_c_tids.empty()) - { - if (m_gdb_comm.GetVContSupported ('c')) - { - for (tid_collection::const_iterator t_pos = m_continue_c_tids.begin(), t_end = m_continue_c_tids.end(); t_pos != t_end; ++t_pos) - continue_packet.Printf(";c:%4.4" PRIx64, *t_pos); - } - else - continue_packet_error = true; - } - - if (!continue_packet_error && !m_continue_C_tids.empty()) - { - if (m_gdb_comm.GetVContSupported ('C')) - { - for (tid_sig_collection::const_iterator s_pos = m_continue_C_tids.begin(), s_end = m_continue_C_tids.end(); s_pos != s_end; ++s_pos) - continue_packet.Printf(";C%2.2x:%4.4" PRIx64, s_pos->second, s_pos->first); - } - else - continue_packet_error = true; - } - - if (!continue_packet_error && !m_continue_s_tids.empty()) - { - if (m_gdb_comm.GetVContSupported ('s')) - { - for (tid_collection::const_iterator t_pos = m_continue_s_tids.begin(), t_end = m_continue_s_tids.end(); t_pos != t_end; ++t_pos) - continue_packet.Printf(";s:%4.4" PRIx64, *t_pos); - } - else - continue_packet_error = true; - } +Error ProcessGDBRemote::DoResume() { + Error error; + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + if (log) + log->Printf("ProcessGDBRemote::Resume()"); + + ListenerSP listener_sp( + Listener::MakeListener("gdb-remote.resume-packet-sent")); + if (listener_sp->StartListeningForEvents( + &m_gdb_comm, GDBRemoteCommunication::eBroadcastBitRunPacketSent)) { + listener_sp->StartListeningForEvents( + &m_async_broadcaster, + ProcessGDBRemote::eBroadcastBitAsyncThreadDidExit); + + const size_t num_threads = GetThreadList().GetSize(); + + StreamString continue_packet; + bool continue_packet_error = false; + if (m_gdb_comm.HasAnyVContSupport()) { + if (!GetTarget().GetNonStopModeEnabled() && + (m_continue_c_tids.size() == num_threads || + (m_continue_c_tids.empty() && m_continue_C_tids.empty() && + m_continue_s_tids.empty() && m_continue_S_tids.empty()))) { + // All threads are continuing, just send a "c" packet + continue_packet.PutCString("c"); + } else { + continue_packet.PutCString("vCont"); + + if (!m_continue_c_tids.empty()) { + if (m_gdb_comm.GetVContSupported('c')) { + for (tid_collection::const_iterator + t_pos = m_continue_c_tids.begin(), + t_end = m_continue_c_tids.end(); + t_pos != t_end; ++t_pos) + continue_packet.Printf(";c:%4.4" PRIx64, *t_pos); + } else + continue_packet_error = true; + } - if (!continue_packet_error && !m_continue_S_tids.empty()) - { - if (m_gdb_comm.GetVContSupported ('S')) - { - for (tid_sig_collection::const_iterator s_pos = m_continue_S_tids.begin(), s_end = m_continue_S_tids.end(); s_pos != s_end; ++s_pos) - continue_packet.Printf(";S%2.2x:%4.4" PRIx64, s_pos->second, s_pos->first); - } - else - continue_packet_error = true; - } + if (!continue_packet_error && !m_continue_C_tids.empty()) { + if (m_gdb_comm.GetVContSupported('C')) { + for (tid_sig_collection::const_iterator + s_pos = m_continue_C_tids.begin(), + s_end = m_continue_C_tids.end(); + s_pos != s_end; ++s_pos) + continue_packet.Printf(";C%2.2x:%4.4" PRIx64, s_pos->second, + s_pos->first); + } else + continue_packet_error = true; + } - if (continue_packet_error) - continue_packet.GetString().clear(); - } + if (!continue_packet_error && !m_continue_s_tids.empty()) { + if (m_gdb_comm.GetVContSupported('s')) { + for (tid_collection::const_iterator + t_pos = m_continue_s_tids.begin(), + t_end = m_continue_s_tids.end(); + t_pos != t_end; ++t_pos) + continue_packet.Printf(";s:%4.4" PRIx64, *t_pos); + } else + continue_packet_error = true; } - else + + if (!continue_packet_error && !m_continue_S_tids.empty()) { + if (m_gdb_comm.GetVContSupported('S')) { + for (tid_sig_collection::const_iterator + s_pos = m_continue_S_tids.begin(), + s_end = m_continue_S_tids.end(); + s_pos != s_end; ++s_pos) + continue_packet.Printf(";S%2.2x:%4.4" PRIx64, s_pos->second, + s_pos->first); + } else continue_packet_error = true; + } if (continue_packet_error) - { - // Either no vCont support, or we tried to use part of the vCont - // packet that wasn't supported by the remote GDB server. - // We need to try and make a simple packet that can do our continue - const size_t num_continue_c_tids = m_continue_c_tids.size(); - const size_t num_continue_C_tids = m_continue_C_tids.size(); - const size_t num_continue_s_tids = m_continue_s_tids.size(); - const size_t num_continue_S_tids = m_continue_S_tids.size(); - if (num_continue_c_tids > 0) - { - if (num_continue_c_tids == num_threads) - { - // All threads are resuming... - m_gdb_comm.SetCurrentThreadForRun (-1); - continue_packet.PutChar ('c'); - continue_packet_error = false; - } - else if (num_continue_c_tids == 1 && - num_continue_C_tids == 0 && - num_continue_s_tids == 0 && - num_continue_S_tids == 0 ) - { - // Only one thread is continuing - m_gdb_comm.SetCurrentThreadForRun (m_continue_c_tids.front()); - continue_packet.PutChar ('c'); - continue_packet_error = false; - } + continue_packet.Clear(); + } + } else + continue_packet_error = true; + + if (continue_packet_error) { + // Either no vCont support, or we tried to use part of the vCont + // packet that wasn't supported by the remote GDB server. + // We need to try and make a simple packet that can do our continue + const size_t num_continue_c_tids = m_continue_c_tids.size(); + const size_t num_continue_C_tids = m_continue_C_tids.size(); + const size_t num_continue_s_tids = m_continue_s_tids.size(); + const size_t num_continue_S_tids = m_continue_S_tids.size(); + if (num_continue_c_tids > 0) { + if (num_continue_c_tids == num_threads) { + // All threads are resuming... + m_gdb_comm.SetCurrentThreadForRun(-1); + continue_packet.PutChar('c'); + continue_packet_error = false; + } else if (num_continue_c_tids == 1 && num_continue_C_tids == 0 && + num_continue_s_tids == 0 && num_continue_S_tids == 0) { + // Only one thread is continuing + m_gdb_comm.SetCurrentThreadForRun(m_continue_c_tids.front()); + continue_packet.PutChar('c'); + continue_packet_error = false; + } + } + + if (continue_packet_error && num_continue_C_tids > 0) { + if ((num_continue_C_tids + num_continue_c_tids) == num_threads && + num_continue_C_tids > 0 && num_continue_s_tids == 0 && + num_continue_S_tids == 0) { + const int continue_signo = m_continue_C_tids.front().second; + // Only one thread is continuing + if (num_continue_C_tids > 1) { + // More that one thread with a signal, yet we don't have + // vCont support and we are being asked to resume each + // thread with a signal, we need to make sure they are + // all the same signal, or we can't issue the continue + // accurately with the current support... + if (num_continue_C_tids > 1) { + continue_packet_error = false; + for (size_t i = 1; i < m_continue_C_tids.size(); ++i) { + if (m_continue_C_tids[i].second != continue_signo) + continue_packet_error = true; + } } + if (!continue_packet_error) + m_gdb_comm.SetCurrentThreadForRun(-1); + } else { + // Set the continue thread ID + continue_packet_error = false; + m_gdb_comm.SetCurrentThreadForRun(m_continue_C_tids.front().first); + } + if (!continue_packet_error) { + // Add threads continuing with the same signo... + continue_packet.Printf("C%2.2x", continue_signo); + } + } + } - if (continue_packet_error && num_continue_C_tids > 0) - { - if ((num_continue_C_tids + num_continue_c_tids) == num_threads && - num_continue_C_tids > 0 && - num_continue_s_tids == 0 && - num_continue_S_tids == 0 ) - { - const int continue_signo = m_continue_C_tids.front().second; - // Only one thread is continuing - if (num_continue_C_tids > 1) - { - // More that one thread with a signal, yet we don't have - // vCont support and we are being asked to resume each - // thread with a signal, we need to make sure they are - // all the same signal, or we can't issue the continue - // accurately with the current support... - if (num_continue_C_tids > 1) - { - continue_packet_error = false; - for (size_t i=1; i<m_continue_C_tids.size(); ++i) - { - if (m_continue_C_tids[i].second != continue_signo) - continue_packet_error = true; - } - } - if (!continue_packet_error) - m_gdb_comm.SetCurrentThreadForRun (-1); - } - else - { - // Set the continue thread ID - continue_packet_error = false; - m_gdb_comm.SetCurrentThreadForRun (m_continue_C_tids.front().first); - } - if (!continue_packet_error) - { - // Add threads continuing with the same signo... - continue_packet.Printf("C%2.2x", continue_signo); - } - } - } + if (continue_packet_error && num_continue_s_tids > 0) { + if (num_continue_s_tids == num_threads) { + // All threads are resuming... + m_gdb_comm.SetCurrentThreadForRun(-1); - if (continue_packet_error && num_continue_s_tids > 0) - { - if (num_continue_s_tids == num_threads) - { - // All threads are resuming... - m_gdb_comm.SetCurrentThreadForRun (-1); - - // If in Non-Stop-Mode use vCont when stepping - if (GetTarget().GetNonStopModeEnabled()) - { - if (m_gdb_comm.GetVContSupported('s')) - continue_packet.PutCString("vCont;s"); - else - continue_packet.PutChar('s'); - } - else - continue_packet.PutChar('s'); - - continue_packet_error = false; - } - else if (num_continue_c_tids == 0 && - num_continue_C_tids == 0 && - num_continue_s_tids == 1 && - num_continue_S_tids == 0 ) - { - // Only one thread is stepping - m_gdb_comm.SetCurrentThreadForRun (m_continue_s_tids.front()); - continue_packet.PutChar ('s'); - continue_packet_error = false; - } - } - - if (!continue_packet_error && num_continue_S_tids > 0) - { - if (num_continue_S_tids == num_threads) - { - const int step_signo = m_continue_S_tids.front().second; - // Are all threads trying to step with the same signal? - continue_packet_error = false; - if (num_continue_S_tids > 1) - { - for (size_t i=1; i<num_threads; ++i) - { - if (m_continue_S_tids[i].second != step_signo) - continue_packet_error = true; - } - } - if (!continue_packet_error) - { - // Add threads stepping with the same signo... - m_gdb_comm.SetCurrentThreadForRun (-1); - continue_packet.Printf("S%2.2x", step_signo); - } - } - else if (num_continue_c_tids == 0 && - num_continue_C_tids == 0 && - num_continue_s_tids == 0 && - num_continue_S_tids == 1 ) - { - // Only one thread is stepping with signal - m_gdb_comm.SetCurrentThreadForRun (m_continue_S_tids.front().first); - continue_packet.Printf("S%2.2x", m_continue_S_tids.front().second); - continue_packet_error = false; - } + // If in Non-Stop-Mode use vCont when stepping + if (GetTarget().GetNonStopModeEnabled()) { + if (m_gdb_comm.GetVContSupported('s')) + continue_packet.PutCString("vCont;s"); + else + continue_packet.PutChar('s'); + } else + continue_packet.PutChar('s'); + + continue_packet_error = false; + } else if (num_continue_c_tids == 0 && num_continue_C_tids == 0 && + num_continue_s_tids == 1 && num_continue_S_tids == 0) { + // Only one thread is stepping + m_gdb_comm.SetCurrentThreadForRun(m_continue_s_tids.front()); + continue_packet.PutChar('s'); + continue_packet_error = false; + } + } + + if (!continue_packet_error && num_continue_S_tids > 0) { + if (num_continue_S_tids == num_threads) { + const int step_signo = m_continue_S_tids.front().second; + // Are all threads trying to step with the same signal? + continue_packet_error = false; + if (num_continue_S_tids > 1) { + for (size_t i = 1; i < num_threads; ++i) { + if (m_continue_S_tids[i].second != step_signo) + continue_packet_error = true; } + } + if (!continue_packet_error) { + // Add threads stepping with the same signo... + m_gdb_comm.SetCurrentThreadForRun(-1); + continue_packet.Printf("S%2.2x", step_signo); + } + } else if (num_continue_c_tids == 0 && num_continue_C_tids == 0 && + num_continue_s_tids == 0 && num_continue_S_tids == 1) { + // Only one thread is stepping with signal + m_gdb_comm.SetCurrentThreadForRun(m_continue_S_tids.front().first); + continue_packet.Printf("S%2.2x", m_continue_S_tids.front().second); + continue_packet_error = false; } + } + } - if (continue_packet_error) - { - error.SetErrorString ("can't make continue packet for this resume"); - } - else - { - EventSP event_sp; - TimeValue timeout; - timeout = TimeValue::Now(); - timeout.OffsetWithSeconds (5); - if (!m_async_thread.IsJoinable()) - { - error.SetErrorString ("Trying to resume but the async thread is dead."); - if (log) - log->Printf ("ProcessGDBRemote::DoResume: Trying to resume but the async thread is dead."); - return error; - } + if (continue_packet_error) { + error.SetErrorString("can't make continue packet for this resume"); + } else { + EventSP event_sp; + if (!m_async_thread.IsJoinable()) { + error.SetErrorString("Trying to resume but the async thread is dead."); + if (log) + log->Printf("ProcessGDBRemote::DoResume: Trying to resume but the " + "async thread is dead."); + return error; + } - m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncContinue, new EventDataBytes (continue_packet.GetData(), continue_packet.GetSize())); + m_async_broadcaster.BroadcastEvent( + eBroadcastBitAsyncContinue, + new EventDataBytes(continue_packet.GetString().data(), + continue_packet.GetSize())); - if (listener_sp->WaitForEvent (&timeout, event_sp) == false) - { - error.SetErrorString("Resume timed out."); - if (log) - log->Printf ("ProcessGDBRemote::DoResume: Resume timed out."); - } - else if (event_sp->BroadcasterIs (&m_async_broadcaster)) - { - error.SetErrorString ("Broadcast continue, but the async thread was killed before we got an ack back."); - if (log) - log->Printf ("ProcessGDBRemote::DoResume: Broadcast continue, but the async thread was killed before we got an ack back."); - return error; - } - } + if (listener_sp->GetEvent(event_sp, std::chrono::seconds(5)) == false) { + error.SetErrorString("Resume timed out."); + if (log) + log->Printf("ProcessGDBRemote::DoResume: Resume timed out."); + } else if (event_sp->BroadcasterIs(&m_async_broadcaster)) { + error.SetErrorString("Broadcast continue, but the async thread was " + "killed before we got an ack back."); + if (log) + log->Printf("ProcessGDBRemote::DoResume: Broadcast continue, but the " + "async thread was killed before we got an ack back."); + return error; + } } + } - return error; + return error; } -void -ProcessGDBRemote::HandleStopReplySequence () -{ - while(true) - { - // Send vStopped - StringExtractorGDBRemote response; - m_gdb_comm.SendPacketAndWaitForResponse("vStopped", response, false); +void ProcessGDBRemote::HandleStopReplySequence() { + while (true) { + // Send vStopped + StringExtractorGDBRemote response; + m_gdb_comm.SendPacketAndWaitForResponse("vStopped", response, false); - // OK represents end of signal list - if (response.IsOKResponse()) - break; + // OK represents end of signal list + if (response.IsOKResponse()) + break; - // If not OK or a normal packet we have a problem - if (!response.IsNormalResponse()) - break; + // If not OK or a normal packet we have a problem + if (!response.IsNormalResponse()) + break; - SetLastStopPacket(response); - } + SetLastStopPacket(response); + } } -void -ProcessGDBRemote::ClearThreadIDList () -{ - std::lock_guard<std::recursive_mutex> guard(m_thread_list_real.GetMutex()); - m_thread_ids.clear(); - m_thread_pcs.clear(); +void ProcessGDBRemote::ClearThreadIDList() { + std::lock_guard<std::recursive_mutex> guard(m_thread_list_real.GetMutex()); + m_thread_ids.clear(); + m_thread_pcs.clear(); } size_t -ProcessGDBRemote::UpdateThreadIDsFromStopReplyThreadsValue (std::string &value) -{ - m_thread_ids.clear(); - m_thread_pcs.clear(); - size_t comma_pos; - lldb::tid_t tid; - while ((comma_pos = value.find(',')) != std::string::npos) - { - value[comma_pos] = '\0'; - // thread in big endian hex - tid = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_THREAD_ID, 16); - if (tid != LLDB_INVALID_THREAD_ID) - m_thread_ids.push_back (tid); - value.erase(0, comma_pos + 1); - } - tid = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_THREAD_ID, 16); +ProcessGDBRemote::UpdateThreadIDsFromStopReplyThreadsValue(std::string &value) { + m_thread_ids.clear(); + m_thread_pcs.clear(); + size_t comma_pos; + lldb::tid_t tid; + while ((comma_pos = value.find(',')) != std::string::npos) { + value[comma_pos] = '\0'; + // thread in big endian hex + tid = StringConvert::ToUInt64(value.c_str(), LLDB_INVALID_THREAD_ID, 16); if (tid != LLDB_INVALID_THREAD_ID) - m_thread_ids.push_back (tid); - return m_thread_ids.size(); + m_thread_ids.push_back(tid); + value.erase(0, comma_pos + 1); + } + tid = StringConvert::ToUInt64(value.c_str(), LLDB_INVALID_THREAD_ID, 16); + if (tid != LLDB_INVALID_THREAD_ID) + m_thread_ids.push_back(tid); + return m_thread_ids.size(); } size_t -ProcessGDBRemote::UpdateThreadPCsFromStopReplyThreadsValue (std::string &value) -{ - m_thread_pcs.clear(); - size_t comma_pos; - lldb::addr_t pc; - while ((comma_pos = value.find(',')) != std::string::npos) - { - value[comma_pos] = '\0'; - pc = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_ADDRESS, 16); - if (pc != LLDB_INVALID_ADDRESS) - m_thread_pcs.push_back (pc); - value.erase(0, comma_pos + 1); - } - pc = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_ADDRESS, 16); - if (pc != LLDB_INVALID_THREAD_ID) - m_thread_pcs.push_back (pc); - return m_thread_pcs.size(); +ProcessGDBRemote::UpdateThreadPCsFromStopReplyThreadsValue(std::string &value) { + m_thread_pcs.clear(); + size_t comma_pos; + lldb::addr_t pc; + while ((comma_pos = value.find(',')) != std::string::npos) { + value[comma_pos] = '\0'; + pc = StringConvert::ToUInt64(value.c_str(), LLDB_INVALID_ADDRESS, 16); + if (pc != LLDB_INVALID_ADDRESS) + m_thread_pcs.push_back(pc); + value.erase(0, comma_pos + 1); + } + pc = StringConvert::ToUInt64(value.c_str(), LLDB_INVALID_ADDRESS, 16); + if (pc != LLDB_INVALID_THREAD_ID) + m_thread_pcs.push_back(pc); + return m_thread_pcs.size(); } -bool -ProcessGDBRemote::UpdateThreadIDList () -{ - std::lock_guard<std::recursive_mutex> guard(m_thread_list_real.GetMutex()); - - if (m_jthreadsinfo_sp) - { - // If we have the JSON threads info, we can get the thread list from that - StructuredData::Array *thread_infos = m_jthreadsinfo_sp->GetAsArray(); - if (thread_infos && thread_infos->GetSize() > 0) - { - m_thread_ids.clear(); - m_thread_pcs.clear(); - thread_infos->ForEach([this](StructuredData::Object* object) -> bool { - StructuredData::Dictionary *thread_dict = object->GetAsDictionary(); - if (thread_dict) - { - // Set the thread stop info from the JSON dictionary - SetThreadStopInfo (thread_dict); - lldb::tid_t tid = LLDB_INVALID_THREAD_ID; - if (thread_dict->GetValueForKeyAsInteger<lldb::tid_t>("tid", tid)) - m_thread_ids.push_back(tid); - } - return true; // Keep iterating through all thread_info objects - }); +bool ProcessGDBRemote::UpdateThreadIDList() { + std::lock_guard<std::recursive_mutex> guard(m_thread_list_real.GetMutex()); + + if (m_jthreadsinfo_sp) { + // If we have the JSON threads info, we can get the thread list from that + StructuredData::Array *thread_infos = m_jthreadsinfo_sp->GetAsArray(); + if (thread_infos && thread_infos->GetSize() > 0) { + m_thread_ids.clear(); + m_thread_pcs.clear(); + thread_infos->ForEach([this](StructuredData::Object *object) -> bool { + StructuredData::Dictionary *thread_dict = object->GetAsDictionary(); + if (thread_dict) { + // Set the thread stop info from the JSON dictionary + SetThreadStopInfo(thread_dict); + lldb::tid_t tid = LLDB_INVALID_THREAD_ID; + if (thread_dict->GetValueForKeyAsInteger<lldb::tid_t>("tid", tid)) + m_thread_ids.push_back(tid); + } + return true; // Keep iterating through all thread_info objects + }); + } + if (!m_thread_ids.empty()) + return true; + } else { + // See if we can get the thread IDs from the current stop reply packets + // that might contain a "threads" key/value pair + + // Lock the thread stack while we access it + // Mutex::Locker stop_stack_lock(m_last_stop_packet_mutex); + std::unique_lock<std::recursive_mutex> stop_stack_lock( + m_last_stop_packet_mutex, std::defer_lock); + if (stop_stack_lock.try_lock()) { + // Get the number of stop packets on the stack + int nItems = m_stop_packet_stack.size(); + // Iterate over them + for (int i = 0; i < nItems; i++) { + // Get the thread stop info + StringExtractorGDBRemote &stop_info = m_stop_packet_stack[i]; + const std::string &stop_info_str = stop_info.GetStringRef(); + + m_thread_pcs.clear(); + const size_t thread_pcs_pos = stop_info_str.find(";thread-pcs:"); + if (thread_pcs_pos != std::string::npos) { + const size_t start = thread_pcs_pos + strlen(";thread-pcs:"); + const size_t end = stop_info_str.find(';', start); + if (end != std::string::npos) { + std::string value = stop_info_str.substr(start, end - start); + UpdateThreadPCsFromStopReplyThreadsValue(value); + } } - if (!m_thread_ids.empty()) - return true; - } - else - { - // See if we can get the thread IDs from the current stop reply packets - // that might contain a "threads" key/value pair - - // Lock the thread stack while we access it - //Mutex::Locker stop_stack_lock(m_last_stop_packet_mutex); - std::unique_lock<std::recursive_mutex> stop_stack_lock(m_last_stop_packet_mutex, std::defer_lock); - if (stop_stack_lock.try_lock()) - { - // Get the number of stop packets on the stack - int nItems = m_stop_packet_stack.size(); - // Iterate over them - for (int i = 0; i < nItems; i++) - { - // Get the thread stop info - StringExtractorGDBRemote &stop_info = m_stop_packet_stack[i]; - const std::string &stop_info_str = stop_info.GetStringRef(); - - m_thread_pcs.clear(); - const size_t thread_pcs_pos = stop_info_str.find(";thread-pcs:"); - if (thread_pcs_pos != std::string::npos) - { - const size_t start = thread_pcs_pos + strlen(";thread-pcs:"); - const size_t end = stop_info_str.find(';', start); - if (end != std::string::npos) - { - std::string value = stop_info_str.substr(start, end - start); - UpdateThreadPCsFromStopReplyThreadsValue(value); - } - } - const size_t threads_pos = stop_info_str.find(";threads:"); - if (threads_pos != std::string::npos) - { - const size_t start = threads_pos + strlen(";threads:"); - const size_t end = stop_info_str.find(';', start); - if (end != std::string::npos) - { - std::string value = stop_info_str.substr(start, end - start); - if (UpdateThreadIDsFromStopReplyThreadsValue(value)) - return true; - } - } - } + const size_t threads_pos = stop_info_str.find(";threads:"); + if (threads_pos != std::string::npos) { + const size_t start = threads_pos + strlen(";threads:"); + const size_t end = stop_info_str.find(';', start); + if (end != std::string::npos) { + std::string value = stop_info_str.substr(start, end - start); + if (UpdateThreadIDsFromStopReplyThreadsValue(value)) + return true; + } } + } } + } - bool sequence_mutex_unavailable = false; - m_gdb_comm.GetCurrentThreadIDs (m_thread_ids, sequence_mutex_unavailable); - if (sequence_mutex_unavailable) - { - return false; // We just didn't get the list - } - return true; + bool sequence_mutex_unavailable = false; + m_gdb_comm.GetCurrentThreadIDs(m_thread_ids, sequence_mutex_unavailable); + if (sequence_mutex_unavailable) { + return false; // We just didn't get the list + } + return true; } -bool -ProcessGDBRemote::UpdateThreadList (ThreadList &old_thread_list, ThreadList &new_thread_list) -{ - // locker will keep a mutex locked until it goes out of scope - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_THREAD)); - if (log && log->GetMask().Test(GDBR_LOG_VERBOSE)) - log->Printf ("ProcessGDBRemote::%s (pid = %" PRIu64 ")", __FUNCTION__, GetID()); - - size_t num_thread_ids = m_thread_ids.size(); - // The "m_thread_ids" thread ID list should always be updated after each stop - // reply packet, but in case it isn't, update it here. - if (num_thread_ids == 0) - { - if (!UpdateThreadIDList ()) - return false; - num_thread_ids = m_thread_ids.size(); - } - - ThreadList old_thread_list_copy(old_thread_list); - if (num_thread_ids > 0) - { - for (size_t i=0; i<num_thread_ids; ++i) - { - tid_t tid = m_thread_ids[i]; - ThreadSP thread_sp (old_thread_list_copy.RemoveThreadByProtocolID(tid, false)); - if (!thread_sp) - { - thread_sp.reset (new ThreadGDBRemote (*this, tid)); - if (log && log->GetMask().Test(GDBR_LOG_VERBOSE)) - log->Printf( - "ProcessGDBRemote::%s Making new thread: %p for thread ID: 0x%" PRIx64 ".\n", - __FUNCTION__, static_cast<void*>(thread_sp.get()), - thread_sp->GetID()); - } - else - { - if (log && log->GetMask().Test(GDBR_LOG_VERBOSE)) - log->Printf( - "ProcessGDBRemote::%s Found old thread: %p for thread ID: 0x%" PRIx64 ".\n", - __FUNCTION__, static_cast<void*>(thread_sp.get()), - thread_sp->GetID()); - } - // The m_thread_pcs vector has pc values in big-endian order, not target-endian, unlike most - // of the register read/write packets in gdb-remote protocol. - // Early in the process startup, we may not yet have set the process ByteOrder so we ignore these; - // they are a performance improvement over fetching thread register values individually, the - // method we will fall back to if needed. - if (m_thread_ids.size() == m_thread_pcs.size() && thread_sp.get() && GetByteOrder() != eByteOrderInvalid) - { - ThreadGDBRemote *gdb_thread = static_cast<ThreadGDBRemote *> (thread_sp.get()); - RegisterContextSP reg_ctx_sp (thread_sp->GetRegisterContext()); - if (reg_ctx_sp) - { - uint32_t pc_regnum = reg_ctx_sp->ConvertRegisterKindToRegisterNumber - (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); - if (pc_regnum != LLDB_INVALID_REGNUM) - { - gdb_thread->PrivateSetRegisterValue (pc_regnum, m_thread_pcs[i]); - } - } - } - new_thread_list.AddThreadSortedByIndexID (thread_sp); +bool ProcessGDBRemote::UpdateThreadList(ThreadList &old_thread_list, + ThreadList &new_thread_list) { + // locker will keep a mutex locked until it goes out of scope + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_THREAD)); + if (log && log->GetMask().Test(GDBR_LOG_VERBOSE)) + log->Printf("ProcessGDBRemote::%s (pid = %" PRIu64 ")", __FUNCTION__, + GetID()); + + size_t num_thread_ids = m_thread_ids.size(); + // The "m_thread_ids" thread ID list should always be updated after each stop + // reply packet, but in case it isn't, update it here. + if (num_thread_ids == 0) { + if (!UpdateThreadIDList()) + return false; + num_thread_ids = m_thread_ids.size(); + } + + ThreadList old_thread_list_copy(old_thread_list); + if (num_thread_ids > 0) { + for (size_t i = 0; i < num_thread_ids; ++i) { + tid_t tid = m_thread_ids[i]; + ThreadSP thread_sp( + old_thread_list_copy.RemoveThreadByProtocolID(tid, false)); + if (!thread_sp) { + thread_sp.reset(new ThreadGDBRemote(*this, tid)); + if (log && log->GetMask().Test(GDBR_LOG_VERBOSE)) + log->Printf("ProcessGDBRemote::%s Making new thread: %p for thread " + "ID: 0x%" PRIx64 ".\n", + __FUNCTION__, static_cast<void *>(thread_sp.get()), + thread_sp->GetID()); + } else { + if (log && log->GetMask().Test(GDBR_LOG_VERBOSE)) + log->Printf("ProcessGDBRemote::%s Found old thread: %p for thread " + "ID: 0x%" PRIx64 ".\n", + __FUNCTION__, static_cast<void *>(thread_sp.get()), + thread_sp->GetID()); + } + // The m_thread_pcs vector has pc values in big-endian order, not + // target-endian, unlike most + // of the register read/write packets in gdb-remote protocol. + // Early in the process startup, we may not yet have set the process + // ByteOrder so we ignore these; + // they are a performance improvement over fetching thread register values + // individually, the + // method we will fall back to if needed. + if (m_thread_ids.size() == m_thread_pcs.size() && thread_sp.get() && + GetByteOrder() != eByteOrderInvalid) { + ThreadGDBRemote *gdb_thread = + static_cast<ThreadGDBRemote *>(thread_sp.get()); + RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext()); + if (reg_ctx_sp) { + uint32_t pc_regnum = reg_ctx_sp->ConvertRegisterKindToRegisterNumber( + eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); + if (pc_regnum != LLDB_INVALID_REGNUM) { + gdb_thread->PrivateSetRegisterValue(pc_regnum, m_thread_pcs[i]); + } } + } + new_thread_list.AddThreadSortedByIndexID(thread_sp); } + } - // Whatever that is left in old_thread_list_copy are not - // present in new_thread_list. Remove non-existent threads from internal id table. - size_t old_num_thread_ids = old_thread_list_copy.GetSize(false); - for (size_t i=0; i<old_num_thread_ids; i++) - { - ThreadSP old_thread_sp(old_thread_list_copy.GetThreadAtIndex (i, false)); - if (old_thread_sp) - { - lldb::tid_t old_thread_id = old_thread_sp->GetProtocolID(); - m_thread_id_to_index_id_map.erase(old_thread_id); - } + // Whatever that is left in old_thread_list_copy are not + // present in new_thread_list. Remove non-existent threads from internal id + // table. + size_t old_num_thread_ids = old_thread_list_copy.GetSize(false); + for (size_t i = 0; i < old_num_thread_ids; i++) { + ThreadSP old_thread_sp(old_thread_list_copy.GetThreadAtIndex(i, false)); + if (old_thread_sp) { + lldb::tid_t old_thread_id = old_thread_sp->GetProtocolID(); + m_thread_id_to_index_id_map.erase(old_thread_id); } + } - return true; + return true; } - -bool -ProcessGDBRemote::GetThreadStopInfoFromJSON (ThreadGDBRemote *thread, const StructuredData::ObjectSP &thread_infos_sp) -{ - // See if we got thread stop infos for all threads via the "jThreadsInfo" packet - if (thread_infos_sp) - { - StructuredData::Array *thread_infos = thread_infos_sp->GetAsArray(); - if (thread_infos) - { - lldb::tid_t tid; - const size_t n = thread_infos->GetSize(); - for (size_t i=0; i<n; ++i) - { - StructuredData::Dictionary *thread_dict = thread_infos->GetItemAtIndex(i)->GetAsDictionary(); - if (thread_dict) - { - if (thread_dict->GetValueForKeyAsInteger<lldb::tid_t>("tid", tid, LLDB_INVALID_THREAD_ID)) - { - if (tid == thread->GetID()) - return (bool)SetThreadStopInfo(thread_dict); - } - } - } +bool ProcessGDBRemote::GetThreadStopInfoFromJSON( + ThreadGDBRemote *thread, const StructuredData::ObjectSP &thread_infos_sp) { + // See if we got thread stop infos for all threads via the "jThreadsInfo" + // packet + if (thread_infos_sp) { + StructuredData::Array *thread_infos = thread_infos_sp->GetAsArray(); + if (thread_infos) { + lldb::tid_t tid; + const size_t n = thread_infos->GetSize(); + for (size_t i = 0; i < n; ++i) { + StructuredData::Dictionary *thread_dict = + thread_infos->GetItemAtIndex(i)->GetAsDictionary(); + if (thread_dict) { + if (thread_dict->GetValueForKeyAsInteger<lldb::tid_t>( + "tid", tid, LLDB_INVALID_THREAD_ID)) { + if (tid == thread->GetID()) + return (bool)SetThreadStopInfo(thread_dict); + } } + } } - return false; + } + return false; } -bool -ProcessGDBRemote::CalculateThreadStopInfo (ThreadGDBRemote *thread) -{ - // See if we got thread stop infos for all threads via the "jThreadsInfo" packet - if (GetThreadStopInfoFromJSON (thread, m_jthreadsinfo_sp)) - return true; +bool ProcessGDBRemote::CalculateThreadStopInfo(ThreadGDBRemote *thread) { + // See if we got thread stop infos for all threads via the "jThreadsInfo" + // packet + if (GetThreadStopInfoFromJSON(thread, m_jthreadsinfo_sp)) + return true; - // See if we got thread stop info for any threads valid stop info reasons threads - // via the "jstopinfo" packet stop reply packet key/value pair? - if (m_jstopinfo_sp) - { - // If we have "jstopinfo" then we have stop descriptions for all threads - // that have stop reasons, and if there is no entry for a thread, then - // it has no stop reason. - thread->GetRegisterContext()->InvalidateIfNeeded(true); - if (!GetThreadStopInfoFromJSON (thread, m_jstopinfo_sp)) - { - thread->SetStopInfo (StopInfoSP()); - } - return true; + // See if we got thread stop info for any threads valid stop info reasons + // threads + // via the "jstopinfo" packet stop reply packet key/value pair? + if (m_jstopinfo_sp) { + // If we have "jstopinfo" then we have stop descriptions for all threads + // that have stop reasons, and if there is no entry for a thread, then + // it has no stop reason. + thread->GetRegisterContext()->InvalidateIfNeeded(true); + if (!GetThreadStopInfoFromJSON(thread, m_jstopinfo_sp)) { + thread->SetStopInfo(StopInfoSP()); } + return true; + } - // Fall back to using the qThreadStopInfo packet - StringExtractorGDBRemote stop_packet; - if (GetGDBRemote().GetThreadStopInfo(thread->GetProtocolID(), stop_packet)) - return SetThreadStopInfo (stop_packet) == eStateStopped; - return false; + // Fall back to using the qThreadStopInfo packet + StringExtractorGDBRemote stop_packet; + if (GetGDBRemote().GetThreadStopInfo(thread->GetProtocolID(), stop_packet)) + return SetThreadStopInfo(stop_packet) == eStateStopped; + return false; } - -ThreadSP -ProcessGDBRemote::SetThreadStopInfo (lldb::tid_t tid, - ExpeditedRegisterMap &expedited_register_map, - uint8_t signo, - const std::string &thread_name, - const std::string &reason, - const std::string &description, - uint32_t exc_type, - const std::vector<addr_t> &exc_data, - addr_t thread_dispatch_qaddr, - bool queue_vars_valid, // Set to true if queue_name, queue_kind and queue_serial are valid - LazyBool associated_with_dispatch_queue, - addr_t dispatch_queue_t, - std::string &queue_name, - QueueKind queue_kind, - uint64_t queue_serial) -{ - ThreadSP thread_sp; - if (tid != LLDB_INVALID_THREAD_ID) - { - // Scope for "locker" below - { - // m_thread_list_real does have its own mutex, but we need to - // hold onto the mutex between the call to m_thread_list_real.FindThreadByID(...) - // and the m_thread_list_real.AddThread(...) so it doesn't change on us - std::lock_guard<std::recursive_mutex> guard(m_thread_list_real.GetMutex()); - thread_sp = m_thread_list_real.FindThreadByProtocolID(tid, false); - - if (!thread_sp) - { - // Create the thread if we need to - thread_sp.reset (new ThreadGDBRemote (*this, tid)); - m_thread_list_real.AddThread(thread_sp); +ThreadSP ProcessGDBRemote::SetThreadStopInfo( + lldb::tid_t tid, ExpeditedRegisterMap &expedited_register_map, + uint8_t signo, const std::string &thread_name, const std::string &reason, + const std::string &description, uint32_t exc_type, + const std::vector<addr_t> &exc_data, addr_t thread_dispatch_qaddr, + bool queue_vars_valid, // Set to true if queue_name, queue_kind and + // queue_serial are valid + LazyBool associated_with_dispatch_queue, addr_t dispatch_queue_t, + std::string &queue_name, QueueKind queue_kind, uint64_t queue_serial) { + ThreadSP thread_sp; + if (tid != LLDB_INVALID_THREAD_ID) { + // Scope for "locker" below + { + // m_thread_list_real does have its own mutex, but we need to + // hold onto the mutex between the call to + // m_thread_list_real.FindThreadByID(...) + // and the m_thread_list_real.AddThread(...) so it doesn't change on us + std::lock_guard<std::recursive_mutex> guard( + m_thread_list_real.GetMutex()); + thread_sp = m_thread_list_real.FindThreadByProtocolID(tid, false); + + if (!thread_sp) { + // Create the thread if we need to + thread_sp.reset(new ThreadGDBRemote(*this, tid)); + m_thread_list_real.AddThread(thread_sp); + } + } + + if (thread_sp) { + ThreadGDBRemote *gdb_thread = + static_cast<ThreadGDBRemote *>(thread_sp.get()); + gdb_thread->GetRegisterContext()->InvalidateIfNeeded(true); + + for (const auto &pair : expedited_register_map) { + StringExtractor reg_value_extractor; + reg_value_extractor.GetStringRef() = pair.second; + DataBufferSP buffer_sp(new DataBufferHeap( + reg_value_extractor.GetStringRef().size() / 2, 0)); + reg_value_extractor.GetHexBytes(buffer_sp->GetData(), '\xcc'); + gdb_thread->PrivateSetRegisterValue(pair.first, buffer_sp->GetData()); + } + + thread_sp->SetName(thread_name.empty() ? NULL : thread_name.c_str()); + + gdb_thread->SetThreadDispatchQAddr(thread_dispatch_qaddr); + // Check if the GDB server was able to provide the queue name, kind and + // serial number + if (queue_vars_valid) + gdb_thread->SetQueueInfo(std::move(queue_name), queue_kind, + queue_serial, dispatch_queue_t, + associated_with_dispatch_queue); + else + gdb_thread->ClearQueueInfo(); + + gdb_thread->SetAssociatedWithLibdispatchQueue( + associated_with_dispatch_queue); + + if (dispatch_queue_t != LLDB_INVALID_ADDRESS) + gdb_thread->SetQueueLibdispatchQueueAddress(dispatch_queue_t); + + // Make sure we update our thread stop reason just once + if (!thread_sp->StopInfoIsUpToDate()) { + thread_sp->SetStopInfo(StopInfoSP()); + // If there's a memory thread backed by this thread, we need to use it + // to calcualte StopInfo. + ThreadSP memory_thread_sp = + m_thread_list.FindThreadByProtocolID(thread_sp->GetProtocolID()); + if (memory_thread_sp) + thread_sp = memory_thread_sp; + + if (exc_type != 0) { + const size_t exc_data_size = exc_data.size(); + + thread_sp->SetStopInfo( + StopInfoMachException::CreateStopReasonWithMachException( + *thread_sp, exc_type, exc_data_size, + exc_data_size >= 1 ? exc_data[0] : 0, + exc_data_size >= 2 ? exc_data[1] : 0, + exc_data_size >= 3 ? exc_data[2] : 0)); + } else { + bool handled = false; + bool did_exec = false; + if (!reason.empty()) { + if (reason.compare("trace") == 0) { + addr_t pc = thread_sp->GetRegisterContext()->GetPC(); + lldb::BreakpointSiteSP bp_site_sp = thread_sp->GetProcess() + ->GetBreakpointSiteList() + .FindByAddress(pc); + + // If the current pc is a breakpoint site then the StopInfo should + // be set to Breakpoint + // Otherwise, it will be set to Trace. + if (bp_site_sp && + bp_site_sp->ValidForThisThread(thread_sp.get())) { + thread_sp->SetStopInfo( + StopInfo::CreateStopReasonWithBreakpointSiteID( + *thread_sp, bp_site_sp->GetID())); + } else + thread_sp->SetStopInfo( + StopInfo::CreateStopReasonToTrace(*thread_sp)); + handled = true; + } else if (reason.compare("breakpoint") == 0) { + addr_t pc = thread_sp->GetRegisterContext()->GetPC(); + lldb::BreakpointSiteSP bp_site_sp = thread_sp->GetProcess() + ->GetBreakpointSiteList() + .FindByAddress(pc); + if (bp_site_sp) { + // If the breakpoint is for this thread, then we'll report the + // hit, but if it is for another thread, + // we can just report no reason. We don't need to worry about + // stepping over the breakpoint here, that + // will be taken care of when the thread resumes and notices + // that there's a breakpoint under the pc. + handled = true; + if (bp_site_sp->ValidForThisThread(thread_sp.get())) { + thread_sp->SetStopInfo( + StopInfo::CreateStopReasonWithBreakpointSiteID( + *thread_sp, bp_site_sp->GetID())); + } else { + StopInfoSP invalid_stop_info_sp; + thread_sp->SetStopInfo(invalid_stop_info_sp); + } + } + } else if (reason.compare("trap") == 0) { + // Let the trap just use the standard signal stop reason below... + } else if (reason.compare("watchpoint") == 0) { + 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); + addr_t wp_hit_addr = desc_extractor.GetU64(LLDB_INVALID_ADDRESS); + watch_id_t watch_id = LLDB_INVALID_WATCH_ID; + if (wp_addr != LLDB_INVALID_ADDRESS) { + WatchpointSP wp_sp; + ArchSpec::Core core = GetTarget().GetArchitecture().GetCore(); + if ((core >= ArchSpec::kCore_mips_first && + core <= ArchSpec::kCore_mips_last) || + (core >= ArchSpec::eCore_arm_generic && + core <= ArchSpec::eCore_arm_aarch64)) + wp_sp = GetTarget().GetWatchpointList().FindByAddress( + wp_hit_addr); + if (!wp_sp) + wp_sp = + GetTarget().GetWatchpointList().FindByAddress(wp_addr); + if (wp_sp) { + wp_sp->SetHardwareIndex(wp_index); + watch_id = wp_sp->GetID(); + } + } + if (watch_id == LLDB_INVALID_WATCH_ID) { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet( + GDBR_LOG_WATCHPOINTS)); + if (log) + log->Printf("failed to find watchpoint"); + } + thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithWatchpointID( + *thread_sp, watch_id, wp_hit_addr)); + handled = true; + } else if (reason.compare("exception") == 0) { + thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithException( + *thread_sp, description.c_str())); + handled = true; + } else if (reason.compare("exec") == 0) { + did_exec = true; + thread_sp->SetStopInfo( + StopInfo::CreateStopReasonWithExec(*thread_sp)); + handled = true; } - } - - if (thread_sp) - { - ThreadGDBRemote *gdb_thread = static_cast<ThreadGDBRemote *> (thread_sp.get()); - gdb_thread->GetRegisterContext()->InvalidateIfNeeded(true); - - for (const auto &pair : expedited_register_map) - { - StringExtractor reg_value_extractor; - reg_value_extractor.GetStringRef() = pair.second; - gdb_thread->PrivateSetRegisterValue (pair.first, reg_value_extractor); + } else if (!signo) { + addr_t pc = thread_sp->GetRegisterContext()->GetPC(); + lldb::BreakpointSiteSP bp_site_sp = + thread_sp->GetProcess()->GetBreakpointSiteList().FindByAddress( + pc); + + // If the current pc is a breakpoint site then the StopInfo should + // be set to Breakpoint + // even though the remote stub did not set it as such. This can + // happen when + // the thread is involuntarily interrupted (e.g. due to stops on + // other + // threads) just as it is about to execute the breakpoint + // instruction. + if (bp_site_sp && bp_site_sp->ValidForThisThread(thread_sp.get())) { + thread_sp->SetStopInfo( + StopInfo::CreateStopReasonWithBreakpointSiteID( + *thread_sp, bp_site_sp->GetID())); + handled = true; } - - thread_sp->SetName (thread_name.empty() ? NULL : thread_name.c_str()); - - gdb_thread->SetThreadDispatchQAddr (thread_dispatch_qaddr); - // Check if the GDB server was able to provide the queue name, kind and serial number - if (queue_vars_valid) - gdb_thread->SetQueueInfo(std::move(queue_name), queue_kind, queue_serial, dispatch_queue_t, associated_with_dispatch_queue); - else - gdb_thread->ClearQueueInfo(); - - gdb_thread->SetAssociatedWithLibdispatchQueue (associated_with_dispatch_queue); - - if (dispatch_queue_t != LLDB_INVALID_ADDRESS) - gdb_thread->SetQueueLibdispatchQueueAddress (dispatch_queue_t); - - // Make sure we update our thread stop reason just once - if (!thread_sp->StopInfoIsUpToDate()) - { - thread_sp->SetStopInfo (StopInfoSP()); - // If there's a memory thread backed by this thread, we need to use it to calcualte StopInfo. - ThreadSP memory_thread_sp = m_thread_list.FindThreadByProtocolID(thread_sp->GetProtocolID()); - if (memory_thread_sp) - thread_sp = memory_thread_sp; - - if (exc_type != 0) - { - const size_t exc_data_size = exc_data.size(); - - thread_sp->SetStopInfo (StopInfoMachException::CreateStopReasonWithMachException (*thread_sp, - exc_type, - exc_data_size, - exc_data_size >= 1 ? exc_data[0] : 0, - exc_data_size >= 2 ? exc_data[1] : 0, - exc_data_size >= 3 ? exc_data[2] : 0)); + } + + if (!handled && signo && did_exec == false) { + if (signo == SIGTRAP) { + // Currently we are going to assume SIGTRAP means we are either + // hitting a breakpoint or hardware single stepping. + handled = true; + addr_t pc = thread_sp->GetRegisterContext()->GetPC() + + m_breakpoint_pc_offset; + lldb::BreakpointSiteSP bp_site_sp = thread_sp->GetProcess() + ->GetBreakpointSiteList() + .FindByAddress(pc); + + if (bp_site_sp) { + // If the breakpoint is for this thread, then we'll report the + // hit, but if it is for another thread, + // we can just report no reason. We don't need to worry about + // stepping over the breakpoint here, that + // will be taken care of when the thread resumes and notices + // that there's a breakpoint under the pc. + if (bp_site_sp->ValidForThisThread(thread_sp.get())) { + if (m_breakpoint_pc_offset != 0) + thread_sp->GetRegisterContext()->SetPC(pc); + thread_sp->SetStopInfo( + StopInfo::CreateStopReasonWithBreakpointSiteID( + *thread_sp, bp_site_sp->GetID())); + } else { + StopInfoSP invalid_stop_info_sp; + thread_sp->SetStopInfo(invalid_stop_info_sp); } + } else { + // If we were stepping then assume the stop was the result of + // the trace. If we were + // not stepping then report the SIGTRAP. + // FIXME: We are still missing the case where we single step + // over a trap instruction. + if (thread_sp->GetTemporaryResumeState() == eStateStepping) + thread_sp->SetStopInfo( + StopInfo::CreateStopReasonToTrace(*thread_sp)); else - { - bool handled = false; - bool did_exec = false; - if (!reason.empty()) - { - if (reason.compare("trace") == 0) - { - addr_t pc = thread_sp->GetRegisterContext()->GetPC(); - lldb::BreakpointSiteSP bp_site_sp = thread_sp->GetProcess()->GetBreakpointSiteList().FindByAddress(pc); - - // If the current pc is a breakpoint site then the StopInfo should be set to Breakpoint - // Otherwise, it will be set to Trace. - if (bp_site_sp && bp_site_sp->ValidForThisThread(thread_sp.get())) - { - thread_sp->SetStopInfo( - StopInfo::CreateStopReasonWithBreakpointSiteID(*thread_sp, bp_site_sp->GetID())); - } - else - thread_sp->SetStopInfo (StopInfo::CreateStopReasonToTrace (*thread_sp)); - handled = true; - } - else if (reason.compare("breakpoint") == 0) - { - addr_t pc = thread_sp->GetRegisterContext()->GetPC(); - lldb::BreakpointSiteSP bp_site_sp = thread_sp->GetProcess()->GetBreakpointSiteList().FindByAddress(pc); - if (bp_site_sp) - { - // If the breakpoint is for this thread, then we'll report the hit, but if it is for another thread, - // we can just report no reason. We don't need to worry about stepping over the breakpoint here, that - // will be taken care of when the thread resumes and notices that there's a breakpoint under the pc. - handled = true; - if (bp_site_sp->ValidForThisThread (thread_sp.get())) - { - thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID (*thread_sp, bp_site_sp->GetID())); - } - else - { - StopInfoSP invalid_stop_info_sp; - thread_sp->SetStopInfo (invalid_stop_info_sp); - } - } - } - else if (reason.compare("trap") == 0) - { - // Let the trap just use the standard signal stop reason below... - } - else if (reason.compare("watchpoint") == 0) - { - 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); - addr_t wp_hit_addr = desc_extractor.GetU64(LLDB_INVALID_ADDRESS); - watch_id_t watch_id = LLDB_INVALID_WATCH_ID; - if (wp_addr != LLDB_INVALID_ADDRESS) - { - WatchpointSP wp_sp; - ArchSpec::Core core = GetTarget().GetArchitecture().GetCore(); - if ((core >= ArchSpec::kCore_mips_first && core <= ArchSpec::kCore_mips_last) || - (core >= ArchSpec::eCore_arm_generic && core <= ArchSpec::eCore_arm_aarch64)) - wp_sp = GetTarget().GetWatchpointList().FindByAddress(wp_hit_addr); - if (!wp_sp) - wp_sp = GetTarget().GetWatchpointList().FindByAddress(wp_addr); - if (wp_sp) - { - wp_sp->SetHardwareIndex(wp_index); - watch_id = wp_sp->GetID(); - } - } - if (watch_id == LLDB_INVALID_WATCH_ID) - { - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_WATCHPOINTS)); - if (log) log->Printf ("failed to find watchpoint"); - } - thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithWatchpointID (*thread_sp, watch_id, wp_hit_addr)); - handled = true; - } - else if (reason.compare("exception") == 0) - { - thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithException(*thread_sp, description.c_str())); - handled = true; - } - else if (reason.compare("exec") == 0) - { - did_exec = true; - thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithExec(*thread_sp)); - handled = true; - } - } - else if (!signo) - { - addr_t pc = thread_sp->GetRegisterContext()->GetPC(); - lldb::BreakpointSiteSP bp_site_sp = - thread_sp->GetProcess()->GetBreakpointSiteList().FindByAddress(pc); - - // If the current pc is a breakpoint site then the StopInfo should be set to Breakpoint - // even though the remote stub did not set it as such. This can happen when - // the thread is involuntarily interrupted (e.g. due to stops on other - // threads) just as it is about to execute the breakpoint instruction. - if (bp_site_sp && bp_site_sp->ValidForThisThread(thread_sp.get())) - { - thread_sp->SetStopInfo( - StopInfo::CreateStopReasonWithBreakpointSiteID(*thread_sp, bp_site_sp->GetID())); - handled = true; - } - } - - if (!handled && signo && did_exec == false) - { - if (signo == SIGTRAP) - { - // Currently we are going to assume SIGTRAP means we are either - // hitting a breakpoint or hardware single stepping. - handled = true; - addr_t pc = thread_sp->GetRegisterContext()->GetPC() + m_breakpoint_pc_offset; - lldb::BreakpointSiteSP bp_site_sp = thread_sp->GetProcess()->GetBreakpointSiteList().FindByAddress(pc); - - if (bp_site_sp) - { - // If the breakpoint is for this thread, then we'll report the hit, but if it is for another thread, - // we can just report no reason. We don't need to worry about stepping over the breakpoint here, that - // will be taken care of when the thread resumes and notices that there's a breakpoint under the pc. - if (bp_site_sp->ValidForThisThread (thread_sp.get())) - { - if(m_breakpoint_pc_offset != 0) - thread_sp->GetRegisterContext()->SetPC(pc); - thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID (*thread_sp, bp_site_sp->GetID())); - } - else - { - StopInfoSP invalid_stop_info_sp; - thread_sp->SetStopInfo (invalid_stop_info_sp); - } - } - else - { - // If we were stepping then assume the stop was the result of the trace. If we were - // not stepping then report the SIGTRAP. - // FIXME: We are still missing the case where we single step over a trap instruction. - if (thread_sp->GetTemporaryResumeState() == eStateStepping) - thread_sp->SetStopInfo (StopInfo::CreateStopReasonToTrace (*thread_sp)); - else - thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithSignal(*thread_sp, signo, description.c_str())); - } - } - if (!handled) - thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithSignal (*thread_sp, signo, description.c_str())); - } - - if (!description.empty()) - { - lldb::StopInfoSP stop_info_sp (thread_sp->GetStopInfo ()); - if (stop_info_sp) - { - const char *stop_info_desc = stop_info_sp->GetDescription(); - if (!stop_info_desc || !stop_info_desc[0]) - stop_info_sp->SetDescription (description.c_str()); - } - else - { - thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithException (*thread_sp, description.c_str())); - } - } - } + thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithSignal( + *thread_sp, signo, description.c_str())); + } } + if (!handled) + thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithSignal( + *thread_sp, signo, description.c_str())); + } + + if (!description.empty()) { + lldb::StopInfoSP stop_info_sp(thread_sp->GetStopInfo()); + if (stop_info_sp) { + const char *stop_info_desc = stop_info_sp->GetDescription(); + if (!stop_info_desc || !stop_info_desc[0]) + stop_info_sp->SetDescription(description.c_str()); + } else { + thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithException( + *thread_sp, description.c_str())); + } + } } + } } - return thread_sp; + } + return thread_sp; } lldb::ThreadSP -ProcessGDBRemote::SetThreadStopInfo (StructuredData::Dictionary *thread_dict) -{ - static ConstString g_key_tid("tid"); - static ConstString g_key_name("name"); - static ConstString g_key_reason("reason"); - static ConstString g_key_metype("metype"); - static ConstString g_key_medata("medata"); - static ConstString g_key_qaddr("qaddr"); - static ConstString g_key_dispatch_queue_t("dispatch_queue_t"); - static ConstString g_key_associated_with_dispatch_queue("associated_with_dispatch_queue"); - static ConstString g_key_queue_name("qname"); - static ConstString g_key_queue_kind("qkind"); - static ConstString g_key_queue_serial_number("qserialnum"); - static ConstString g_key_registers("registers"); - static ConstString g_key_memory("memory"); - static ConstString g_key_address("address"); - static ConstString g_key_bytes("bytes"); - static ConstString g_key_description("description"); - static ConstString g_key_signal("signal"); +ProcessGDBRemote::SetThreadStopInfo(StructuredData::Dictionary *thread_dict) { + static ConstString g_key_tid("tid"); + static ConstString g_key_name("name"); + static ConstString g_key_reason("reason"); + static ConstString g_key_metype("metype"); + static ConstString g_key_medata("medata"); + static ConstString g_key_qaddr("qaddr"); + static ConstString g_key_dispatch_queue_t("dispatch_queue_t"); + static ConstString g_key_associated_with_dispatch_queue( + "associated_with_dispatch_queue"); + static ConstString g_key_queue_name("qname"); + static ConstString g_key_queue_kind("qkind"); + static ConstString g_key_queue_serial_number("qserialnum"); + static ConstString g_key_registers("registers"); + static ConstString g_key_memory("memory"); + static ConstString g_key_address("address"); + static ConstString g_key_bytes("bytes"); + static ConstString g_key_description("description"); + static ConstString g_key_signal("signal"); + + // Stop with signal and thread info + lldb::tid_t tid = LLDB_INVALID_THREAD_ID; + uint8_t signo = 0; + std::string value; + std::string thread_name; + std::string reason; + std::string description; + uint32_t exc_type = 0; + std::vector<addr_t> exc_data; + addr_t thread_dispatch_qaddr = LLDB_INVALID_ADDRESS; + ExpeditedRegisterMap expedited_register_map; + bool queue_vars_valid = false; + addr_t dispatch_queue_t = LLDB_INVALID_ADDRESS; + LazyBool associated_with_dispatch_queue = eLazyBoolCalculate; + std::string queue_name; + QueueKind queue_kind = eQueueKindUnknown; + uint64_t queue_serial_number = 0; + // Iterate through all of the thread dictionary key/value pairs from the + // structured data dictionary + + thread_dict->ForEach([this, &tid, &expedited_register_map, &thread_name, + &signo, &reason, &description, &exc_type, &exc_data, + &thread_dispatch_qaddr, &queue_vars_valid, + &associated_with_dispatch_queue, &dispatch_queue_t, + &queue_name, &queue_kind, &queue_serial_number]( + ConstString key, + StructuredData::Object *object) -> bool { + if (key == g_key_tid) { + // thread in big endian hex + tid = object->GetIntegerValue(LLDB_INVALID_THREAD_ID); + } else if (key == g_key_metype) { + // exception type in big endian hex + exc_type = object->GetIntegerValue(0); + } else if (key == g_key_medata) { + // exception data in big endian hex + StructuredData::Array *array = object->GetAsArray(); + if (array) { + array->ForEach([&exc_data](StructuredData::Object *object) -> bool { + exc_data.push_back(object->GetIntegerValue()); + return true; // Keep iterating through all array items + }); + } + } else if (key == g_key_name) { + thread_name = object->GetStringValue(); + } else if (key == g_key_qaddr) { + thread_dispatch_qaddr = object->GetIntegerValue(LLDB_INVALID_ADDRESS); + } else if (key == g_key_queue_name) { + queue_vars_valid = true; + queue_name = object->GetStringValue(); + } else if (key == g_key_queue_kind) { + std::string queue_kind_str = object->GetStringValue(); + if (queue_kind_str == "serial") { + queue_vars_valid = true; + queue_kind = eQueueKindSerial; + } else if (queue_kind_str == "concurrent") { + queue_vars_valid = true; + queue_kind = eQueueKindConcurrent; + } + } else if (key == g_key_queue_serial_number) { + queue_serial_number = object->GetIntegerValue(0); + if (queue_serial_number != 0) + queue_vars_valid = true; + } else if (key == g_key_dispatch_queue_t) { + dispatch_queue_t = object->GetIntegerValue(0); + if (dispatch_queue_t != 0 && dispatch_queue_t != LLDB_INVALID_ADDRESS) + queue_vars_valid = true; + } else if (key == g_key_associated_with_dispatch_queue) { + queue_vars_valid = true; + bool associated = object->GetBooleanValue(); + if (associated) + associated_with_dispatch_queue = eLazyBoolYes; + else + associated_with_dispatch_queue = eLazyBoolNo; + } else if (key == g_key_reason) { + reason = object->GetStringValue(); + } else if (key == g_key_description) { + description = object->GetStringValue(); + } else if (key == g_key_registers) { + StructuredData::Dictionary *registers_dict = object->GetAsDictionary(); + + if (registers_dict) { + registers_dict->ForEach( + [&expedited_register_map](ConstString key, + StructuredData::Object *object) -> bool { + const uint32_t reg = + StringConvert::ToUInt32(key.GetCString(), UINT32_MAX, 10); + if (reg != UINT32_MAX) + expedited_register_map[reg] = object->GetStringValue(); + return true; // Keep iterating through all array items + }); + } + } else if (key == g_key_memory) { + StructuredData::Array *array = object->GetAsArray(); + if (array) { + array->ForEach([this](StructuredData::Object *object) -> bool { + StructuredData::Dictionary *mem_cache_dict = + object->GetAsDictionary(); + if (mem_cache_dict) { + lldb::addr_t mem_cache_addr = LLDB_INVALID_ADDRESS; + if (mem_cache_dict->GetValueForKeyAsInteger<lldb::addr_t>( + "address", mem_cache_addr)) { + if (mem_cache_addr != LLDB_INVALID_ADDRESS) { + StringExtractor bytes; + if (mem_cache_dict->GetValueForKeyAsString( + "bytes", bytes.GetStringRef())) { + bytes.SetFilePos(0); + + const size_t byte_size = bytes.GetStringRef().size() / 2; + DataBufferSP data_buffer_sp(new DataBufferHeap(byte_size, 0)); + const size_t bytes_copied = + bytes.GetHexBytes(data_buffer_sp->GetData(), 0); + if (bytes_copied == byte_size) + m_memory_cache.AddL1CacheData(mem_cache_addr, + data_buffer_sp); + } + } + } + } + return true; // Keep iterating through all array items + }); + } + + } else if (key == g_key_signal) + signo = object->GetIntegerValue(LLDB_INVALID_SIGNAL_NUMBER); + return true; // Keep iterating through all dictionary key/value pairs + }); + + return SetThreadStopInfo(tid, expedited_register_map, signo, thread_name, + reason, description, exc_type, exc_data, + thread_dispatch_qaddr, queue_vars_valid, + associated_with_dispatch_queue, dispatch_queue_t, + queue_name, queue_kind, queue_serial_number); +} +StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) { + stop_packet.SetFilePos(0); + const char stop_type = stop_packet.GetChar(); + switch (stop_type) { + case 'T': + case 'S': { + // This is a bit of a hack, but is is required. If we did exec, we + // need to clear our thread lists and also know to rebuild our dynamic + // register info before we lookup and threads and populate the expedited + // register values so we need to know this right away so we can cleanup + // and update our registers. + const uint32_t stop_id = GetStopID(); + if (stop_id == 0) { + // Our first stop, make sure we have a process ID, and also make + // sure we know about our registers + if (GetID() == LLDB_INVALID_PROCESS_ID) { + lldb::pid_t pid = m_gdb_comm.GetCurrentProcessID(); + if (pid != LLDB_INVALID_PROCESS_ID) + SetID(pid); + } + BuildDynamicRegisterInfo(true); + } // Stop with signal and thread info lldb::tid_t tid = LLDB_INVALID_THREAD_ID; - uint8_t signo = 0; - std::string value; + const uint8_t signo = stop_packet.GetHexU8(); + llvm::StringRef key; + llvm::StringRef value; std::string thread_name; std::string reason; std::string description; uint32_t exc_type = 0; std::vector<addr_t> exc_data; addr_t thread_dispatch_qaddr = LLDB_INVALID_ADDRESS; - ExpeditedRegisterMap expedited_register_map; - bool queue_vars_valid = false; + bool queue_vars_valid = + false; // says if locals below that start with "queue_" are valid addr_t dispatch_queue_t = LLDB_INVALID_ADDRESS; LazyBool associated_with_dispatch_queue = eLazyBoolCalculate; std::string queue_name; QueueKind queue_kind = eQueueKindUnknown; uint64_t queue_serial_number = 0; - // Iterate through all of the thread dictionary key/value pairs from the structured data dictionary - - thread_dict->ForEach([this, - &tid, - &expedited_register_map, - &thread_name, - &signo, - &reason, - &description, - &exc_type, - &exc_data, - &thread_dispatch_qaddr, - &queue_vars_valid, - &associated_with_dispatch_queue, - &dispatch_queue_t, - &queue_name, - &queue_kind, - &queue_serial_number] - (ConstString key, StructuredData::Object* object) -> bool - { - if (key == g_key_tid) - { - // thread in big endian hex - tid = object->GetIntegerValue(LLDB_INVALID_THREAD_ID); - } - else if (key == g_key_metype) - { - // exception type in big endian hex - exc_type = object->GetIntegerValue(0); - } - else if (key == g_key_medata) - { - // exception data in big endian hex - StructuredData::Array *array = object->GetAsArray(); - if (array) - { - array->ForEach([&exc_data](StructuredData::Object* object) -> bool { - exc_data.push_back(object->GetIntegerValue()); - return true; // Keep iterating through all array items - }); - } - } - else if (key == g_key_name) - { - thread_name = object->GetStringValue(); - } - else if (key == g_key_qaddr) - { - thread_dispatch_qaddr = object->GetIntegerValue(LLDB_INVALID_ADDRESS); - } - else if (key == g_key_queue_name) - { - queue_vars_valid = true; - queue_name = object->GetStringValue(); - } - else if (key == g_key_queue_kind) - { - std::string queue_kind_str = object->GetStringValue(); - if (queue_kind_str == "serial") - { - queue_vars_valid = true; - queue_kind = eQueueKindSerial; - } - else if (queue_kind_str == "concurrent") - { - queue_vars_valid = true; - queue_kind = eQueueKindConcurrent; - } - } - else if (key == g_key_queue_serial_number) - { - queue_serial_number = object->GetIntegerValue(0); - if (queue_serial_number != 0) - queue_vars_valid = true; - } - else if (key == g_key_dispatch_queue_t) - { - dispatch_queue_t = object->GetIntegerValue(0); - if (dispatch_queue_t != 0 && dispatch_queue_t != LLDB_INVALID_ADDRESS) - queue_vars_valid = true; - } - else if (key == g_key_associated_with_dispatch_queue) - { - queue_vars_valid = true; - bool associated = object->GetBooleanValue (); - if (associated) - associated_with_dispatch_queue = eLazyBoolYes; - else - associated_with_dispatch_queue = eLazyBoolNo; - } - else if (key == g_key_reason) - { - reason = object->GetStringValue(); - } - else if (key == g_key_description) - { - description = object->GetStringValue(); + ExpeditedRegisterMap expedited_register_map; + while (stop_packet.GetNameColonValue(key, value)) { + if (key.compare("metype") == 0) { + // exception type in big endian hex + value.getAsInteger(16, exc_type); + } else if (key.compare("medata") == 0) { + // exception data in big endian hex + uint64_t x; + value.getAsInteger(16, x); + exc_data.push_back(x); + } else if (key.compare("thread") == 0) { + // thread in big endian hex + if (value.getAsInteger(16, tid)) + tid = LLDB_INVALID_THREAD_ID; + } else if (key.compare("threads") == 0) { + std::lock_guard<std::recursive_mutex> guard( + m_thread_list_real.GetMutex()); + + m_thread_ids.clear(); + // A comma separated list of all threads in the current + // process that includes the thread for this stop reply + // packet + lldb::tid_t tid; + while (!value.empty()) { + llvm::StringRef tid_str; + std::tie(tid_str, value) = value.split(','); + if (tid_str.getAsInteger(16, tid)) + tid = LLDB_INVALID_THREAD_ID; + m_thread_ids.push_back(tid); } - else if (key == g_key_registers) - { - StructuredData::Dictionary *registers_dict = object->GetAsDictionary(); - - if (registers_dict) - { - registers_dict->ForEach([&expedited_register_map](ConstString key, StructuredData::Object* object) -> bool { - const uint32_t reg = StringConvert::ToUInt32 (key.GetCString(), UINT32_MAX, 10); - if (reg != UINT32_MAX) - expedited_register_map[reg] = object->GetStringValue(); - return true; // Keep iterating through all array items - }); - } + } else if (key.compare("thread-pcs") == 0) { + m_thread_pcs.clear(); + // A comma separated list of all threads in the current + // process that includes the thread for this stop reply + // packet + lldb::addr_t pc; + while (!value.empty()) { + llvm::StringRef pc_str; + std::tie(pc_str, value) = value.split(','); + if (pc_str.getAsInteger(16, pc)) + pc = LLDB_INVALID_ADDRESS; + m_thread_pcs.push_back(pc); } - else if (key == g_key_memory) - { - StructuredData::Array *array = object->GetAsArray(); - if (array) - { - array->ForEach([this](StructuredData::Object* object) -> bool { - StructuredData::Dictionary *mem_cache_dict = object->GetAsDictionary(); - if (mem_cache_dict) - { - lldb::addr_t mem_cache_addr = LLDB_INVALID_ADDRESS; - if (mem_cache_dict->GetValueForKeyAsInteger<lldb::addr_t>("address", mem_cache_addr)) - { - if (mem_cache_addr != LLDB_INVALID_ADDRESS) - { - StringExtractor bytes; - if (mem_cache_dict->GetValueForKeyAsString("bytes", bytes.GetStringRef())) - { - bytes.SetFilePos(0); - - const size_t byte_size = bytes.GetStringRef().size()/2; - DataBufferSP data_buffer_sp(new DataBufferHeap(byte_size, 0)); - const size_t bytes_copied = bytes.GetHexBytes (data_buffer_sp->GetBytes(), byte_size, 0); - if (bytes_copied == byte_size) - m_memory_cache.AddL1CacheData(mem_cache_addr, data_buffer_sp); - } - } - } - } - return true; // Keep iterating through all array items - }); - } - + } else if (key.compare("jstopinfo") == 0) { + StringExtractor json_extractor(value); + std::string json; + // Now convert the HEX bytes into a string value + json_extractor.GetHexByteString(json); + + // This JSON contains thread IDs and thread stop info for all threads. + // It doesn't contain expedited registers, memory or queue info. + m_jstopinfo_sp = StructuredData::ParseJSON(json); + } else if (key.compare("hexname") == 0) { + StringExtractor name_extractor(value); + std::string name; + // Now convert the HEX bytes into a string value + name_extractor.GetHexByteString(thread_name); + } else if (key.compare("name") == 0) { + thread_name = value; + } else if (key.compare("qaddr") == 0) { + value.getAsInteger(16, thread_dispatch_qaddr); + } else if (key.compare("dispatch_queue_t") == 0) { + queue_vars_valid = true; + value.getAsInteger(16, dispatch_queue_t); + } else if (key.compare("qname") == 0) { + queue_vars_valid = true; + StringExtractor name_extractor(value); + // Now convert the HEX bytes into a string value + name_extractor.GetHexByteString(queue_name); + } else if (key.compare("qkind") == 0) { + queue_kind = llvm::StringSwitch<QueueKind>(value) + .Case("serial", eQueueKindSerial) + .Case("concurrent", eQueueKindConcurrent) + .Default(eQueueKindUnknown); + queue_vars_valid = queue_kind != eQueueKindUnknown; + } else if (key.compare("qserialnum") == 0) { + if (!value.getAsInteger(0, queue_serial_number)) + queue_vars_valid = true; + } else if (key.compare("reason") == 0) { + reason = value; + } else if (key.compare("description") == 0) { + StringExtractor desc_extractor(value); + // Now convert the HEX bytes into a string value + desc_extractor.GetHexByteString(description); + } else if (key.compare("memory") == 0) { + // Expedited memory. GDB servers can choose to send back expedited + // memory + // that can populate the L1 memory cache in the process so that things + // like + // the frame pointer backchain can be expedited. This will help stack + // backtracing be more efficient by not having to send as many memory + // read + // requests down the remote GDB server. + + // Key/value pair format: memory:<addr>=<bytes>; + // <addr> is a number whose base will be interpreted by the prefix: + // "0x[0-9a-fA-F]+" for hex + // "0[0-7]+" for octal + // "[1-9]+" for decimal + // <bytes> is native endian ASCII hex bytes just like the register + // values + llvm::StringRef addr_str, bytes_str; + std::tie(addr_str, bytes_str) = value.split('='); + if (!addr_str.empty() && !bytes_str.empty()) { + lldb::addr_t mem_cache_addr = LLDB_INVALID_ADDRESS; + if (!addr_str.getAsInteger(0, mem_cache_addr)) { + StringExtractor bytes(bytes_str); + const size_t byte_size = bytes.GetBytesLeft() / 2; + DataBufferSP data_buffer_sp(new DataBufferHeap(byte_size, 0)); + const size_t bytes_copied = + bytes.GetHexBytes(data_buffer_sp->GetData(), 0); + if (bytes_copied == byte_size) + m_memory_cache.AddL1CacheData(mem_cache_addr, data_buffer_sp); + } } - else if (key == g_key_signal) - signo = object->GetIntegerValue(LLDB_INVALID_SIGNAL_NUMBER); - return true; // Keep iterating through all dictionary key/value pairs - }); - - return SetThreadStopInfo (tid, - expedited_register_map, - signo, - thread_name, - reason, - description, - exc_type, - exc_data, - thread_dispatch_qaddr, - queue_vars_valid, - associated_with_dispatch_queue, - dispatch_queue_t, - queue_name, - queue_kind, - queue_serial_number); + } else if (key.compare("watch") == 0 || key.compare("rwatch") == 0 || + key.compare("awatch") == 0) { + // Support standard GDB remote stop reply packet 'TAAwatch:addr' + lldb::addr_t wp_addr = LLDB_INVALID_ADDRESS; + value.getAsInteger(16, wp_addr); + + WatchpointSP wp_sp = + GetTarget().GetWatchpointList().FindByAddress(wp_addr); + uint32_t wp_index = LLDB_INVALID_INDEX32; + + if (wp_sp) + wp_index = wp_sp->GetHardwareIndex(); + + reason = "watchpoint"; + StreamString ostr; + ostr.Printf("%" PRIu64 " %" PRIu32, wp_addr, wp_index); + description = ostr.GetString(); + } else if (key.compare("library") == 0) { + LoadModules(); + } else if (key.size() == 2 && ::isxdigit(key[0]) && ::isxdigit(key[1])) { + uint32_t reg = UINT32_MAX; + if (!key.getAsInteger(16, reg)) + expedited_register_map[reg] = std::move(value); + } + } + + if (tid == LLDB_INVALID_THREAD_ID) { + // A thread id may be invalid if the response is old style 'S' packet + // which does not provide the + // thread information. So update the thread list and choose the first one. + UpdateThreadIDList(); + + if (!m_thread_ids.empty()) { + tid = m_thread_ids.front(); + } + } + + ThreadSP thread_sp = SetThreadStopInfo( + tid, expedited_register_map, signo, thread_name, reason, description, + exc_type, exc_data, thread_dispatch_qaddr, queue_vars_valid, + associated_with_dispatch_queue, dispatch_queue_t, queue_name, + queue_kind, queue_serial_number); + + return eStateStopped; + } break; + + case 'W': + case 'X': + // process exited + return eStateExited; + + default: + break; + } + return eStateInvalid; } -StateType -ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet) -{ - stop_packet.SetFilePos (0); - const char stop_type = stop_packet.GetChar(); - switch (stop_type) - { - case 'T': - case 'S': - { - // This is a bit of a hack, but is is required. If we did exec, we - // need to clear our thread lists and also know to rebuild our dynamic - // register info before we lookup and threads and populate the expedited - // register values so we need to know this right away so we can cleanup - // and update our registers. - const uint32_t stop_id = GetStopID(); - if (stop_id == 0) - { - // Our first stop, make sure we have a process ID, and also make - // sure we know about our registers - if (GetID() == LLDB_INVALID_PROCESS_ID) - { - lldb::pid_t pid = m_gdb_comm.GetCurrentProcessID (); - if (pid != LLDB_INVALID_PROCESS_ID) - SetID (pid); - } - BuildDynamicRegisterInfo (true); - } - // Stop with signal and thread info - lldb::tid_t tid = LLDB_INVALID_THREAD_ID; - const uint8_t signo = stop_packet.GetHexU8(); - std::string key; - std::string value; - std::string thread_name; - std::string reason; - std::string description; - uint32_t exc_type = 0; - std::vector<addr_t> exc_data; - addr_t thread_dispatch_qaddr = LLDB_INVALID_ADDRESS; - bool queue_vars_valid = false; // says if locals below that start with "queue_" are valid - addr_t dispatch_queue_t = LLDB_INVALID_ADDRESS; - LazyBool associated_with_dispatch_queue = eLazyBoolCalculate; - std::string queue_name; - QueueKind queue_kind = eQueueKindUnknown; - uint64_t queue_serial_number = 0; - ExpeditedRegisterMap expedited_register_map; - while (stop_packet.GetNameColonValue(key, value)) - { - if (key.compare("metype") == 0) - { - // exception type in big endian hex - exc_type = StringConvert::ToUInt32 (value.c_str(), 0, 16); - } - else if (key.compare("medata") == 0) - { - // exception data in big endian hex - exc_data.push_back(StringConvert::ToUInt64 (value.c_str(), 0, 16)); - } - else if (key.compare("thread") == 0) - { - // thread in big endian hex - tid = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_THREAD_ID, 16); - } - else if (key.compare("threads") == 0) - { - std::lock_guard<std::recursive_mutex> guard(m_thread_list_real.GetMutex()); - - m_thread_ids.clear(); - // A comma separated list of all threads in the current - // process that includes the thread for this stop reply - // packet - size_t comma_pos; - lldb::tid_t tid; - while ((comma_pos = value.find(',')) != std::string::npos) - { - value[comma_pos] = '\0'; - // thread in big endian hex - tid = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_THREAD_ID, 16); - if (tid != LLDB_INVALID_THREAD_ID) - m_thread_ids.push_back (tid); - value.erase(0, comma_pos + 1); - } - tid = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_THREAD_ID, 16); - if (tid != LLDB_INVALID_THREAD_ID) - m_thread_ids.push_back (tid); - } - else if (key.compare("thread-pcs") == 0) - { - m_thread_pcs.clear(); - // A comma separated list of all threads in the current - // process that includes the thread for this stop reply - // packet - size_t comma_pos; - lldb::addr_t pc; - while ((comma_pos = value.find(',')) != std::string::npos) - { - value[comma_pos] = '\0'; - // thread in big endian hex - pc = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_ADDRESS, 16); - if (pc != LLDB_INVALID_ADDRESS) - m_thread_pcs.push_back (pc); - value.erase(0, comma_pos + 1); - } - pc = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_ADDRESS, 16); - if (pc != LLDB_INVALID_ADDRESS) - m_thread_pcs.push_back (pc); - } - else if (key.compare("jstopinfo") == 0) - { - StringExtractor json_extractor; - // Swap "value" over into "name_extractor" - json_extractor.GetStringRef().swap(value); - // Now convert the HEX bytes into a string value - json_extractor.GetHexByteString (value); - - // This JSON contains thread IDs and thread stop info for all threads. - // It doesn't contain expedited registers, memory or queue info. - m_jstopinfo_sp = StructuredData::ParseJSON (value); - } - else if (key.compare("hexname") == 0) - { - StringExtractor name_extractor; - // Swap "value" over into "name_extractor" - name_extractor.GetStringRef().swap(value); - // Now convert the HEX bytes into a string value - name_extractor.GetHexByteString (value); - thread_name.swap (value); - } - else if (key.compare("name") == 0) - { - thread_name.swap (value); - } - else if (key.compare("qaddr") == 0) - { - thread_dispatch_qaddr = StringConvert::ToUInt64 (value.c_str(), 0, 16); - } - else if (key.compare("dispatch_queue_t") == 0) - { - queue_vars_valid = true; - dispatch_queue_t = StringConvert::ToUInt64 (value.c_str(), 0, 16); - } - else if (key.compare("qname") == 0) - { - queue_vars_valid = true; - StringExtractor name_extractor; - // Swap "value" over into "name_extractor" - name_extractor.GetStringRef().swap(value); - // Now convert the HEX bytes into a string value - name_extractor.GetHexByteString (value); - queue_name.swap (value); - } - else if (key.compare("qkind") == 0) - { - if (value == "serial") - { - queue_vars_valid = true; - queue_kind = eQueueKindSerial; - } - else if (value == "concurrent") - { - queue_vars_valid = true; - queue_kind = eQueueKindConcurrent; - } - } - else if (key.compare("qserialnum") == 0) - { - queue_serial_number = StringConvert::ToUInt64 (value.c_str(), 0, 0); - if (queue_serial_number != 0) - queue_vars_valid = true; - } - else if (key.compare("reason") == 0) - { - reason.swap(value); - } - else if (key.compare("description") == 0) - { - StringExtractor desc_extractor; - // Swap "value" over into "name_extractor" - desc_extractor.GetStringRef().swap(value); - // Now convert the HEX bytes into a string value - desc_extractor.GetHexByteString (value); - description.swap(value); - } - else if (key.compare("memory") == 0) - { - // Expedited memory. GDB servers can choose to send back expedited memory - // that can populate the L1 memory cache in the process so that things like - // the frame pointer backchain can be expedited. This will help stack - // backtracing be more efficient by not having to send as many memory read - // requests down the remote GDB server. - - // Key/value pair format: memory:<addr>=<bytes>; - // <addr> is a number whose base will be interpreted by the prefix: - // "0x[0-9a-fA-F]+" for hex - // "0[0-7]+" for octal - // "[1-9]+" for decimal - // <bytes> is native endian ASCII hex bytes just like the register values - llvm::StringRef value_ref(value); - std::pair<llvm::StringRef, llvm::StringRef> pair; - pair = value_ref.split('='); - if (!pair.first.empty() && !pair.second.empty()) - { - std::string addr_str(pair.first.str()); - const lldb::addr_t mem_cache_addr = StringConvert::ToUInt64(addr_str.c_str(), LLDB_INVALID_ADDRESS, 0); - if (mem_cache_addr != LLDB_INVALID_ADDRESS) - { - StringExtractor bytes; - bytes.GetStringRef() = pair.second.str(); - const size_t byte_size = bytes.GetStringRef().size()/2; - DataBufferSP data_buffer_sp(new DataBufferHeap(byte_size, 0)); - const size_t bytes_copied = bytes.GetHexBytes (data_buffer_sp->GetBytes(), byte_size, 0); - if (bytes_copied == byte_size) - m_memory_cache.AddL1CacheData(mem_cache_addr, data_buffer_sp); - } - } - } - else if (key.compare("watch") == 0 || key.compare("rwatch") == 0 || key.compare("awatch") == 0) - { - // Support standard GDB remote stop reply packet 'TAAwatch:addr' - lldb::addr_t wp_addr = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_ADDRESS, 16); - WatchpointSP wp_sp = GetTarget().GetWatchpointList().FindByAddress(wp_addr); - uint32_t wp_index = LLDB_INVALID_INDEX32; - - if (wp_sp) - wp_index = wp_sp->GetHardwareIndex(); - - reason = "watchpoint"; - StreamString ostr; - ostr.Printf("%" PRIu64 " %" PRIu32, wp_addr, wp_index); - description = ostr.GetString().c_str(); - } - else if (key.compare("library") == 0) - { - LoadModules(); - } - else if (key.size() == 2 && ::isxdigit(key[0]) && ::isxdigit(key[1])) - { - uint32_t reg = StringConvert::ToUInt32 (key.c_str(), UINT32_MAX, 16); - if (reg != UINT32_MAX) - expedited_register_map[reg] = std::move(value); - } - } - - if (tid == LLDB_INVALID_THREAD_ID) - { - // A thread id may be invalid if the response is old style 'S' packet which does not provide the - // thread information. So update the thread list and choose the first one. - UpdateThreadIDList (); - - if (!m_thread_ids.empty ()) - { - tid = m_thread_ids.front (); - } - } - - ThreadSP thread_sp = SetThreadStopInfo (tid, - expedited_register_map, - signo, - thread_name, - reason, - description, - exc_type, - exc_data, - thread_dispatch_qaddr, - queue_vars_valid, - associated_with_dispatch_queue, - dispatch_queue_t, - queue_name, - queue_kind, - queue_serial_number); - - return eStateStopped; - } - break; - - case 'W': - case 'X': - // process exited - return eStateExited; - - default: - break; - } - return eStateInvalid; +void ProcessGDBRemote::RefreshStateAfterStop() { + std::lock_guard<std::recursive_mutex> guard(m_thread_list_real.GetMutex()); + + m_thread_ids.clear(); + m_thread_pcs.clear(); + // Set the thread stop info. It might have a "threads" key whose value is + // a list of all thread IDs in the current process, so m_thread_ids might + // get set. + + // Scope for the lock + { + // Lock the thread stack while we access it + std::lock_guard<std::recursive_mutex> guard(m_last_stop_packet_mutex); + // Get the number of stop packets on the stack + int nItems = m_stop_packet_stack.size(); + // Iterate over them + for (int i = 0; i < nItems; i++) { + // Get the thread stop info + StringExtractorGDBRemote stop_info = m_stop_packet_stack[i]; + // Process thread stop info + SetThreadStopInfo(stop_info); + } + // Clear the thread stop stack + m_stop_packet_stack.clear(); + } + + // Check to see if SetThreadStopInfo() filled in m_thread_ids? + if (m_thread_ids.empty()) { + // No, we need to fetch the thread list manually + UpdateThreadIDList(); + } + + // If we have queried for a default thread id + if (m_initial_tid != LLDB_INVALID_THREAD_ID) { + m_thread_list.SetSelectedThreadByID(m_initial_tid); + m_initial_tid = LLDB_INVALID_THREAD_ID; + } + + // Let all threads recover from stopping and do any clean up based + // on the previous thread state (if any). + m_thread_list_real.RefreshStateAfterStop(); } -void -ProcessGDBRemote::RefreshStateAfterStop () -{ - std::lock_guard<std::recursive_mutex> guard(m_thread_list_real.GetMutex()); - - m_thread_ids.clear(); - m_thread_pcs.clear(); - // Set the thread stop info. It might have a "threads" key whose value is - // a list of all thread IDs in the current process, so m_thread_ids might - // get set. - - // Scope for the lock - { - // Lock the thread stack while we access it - std::lock_guard<std::recursive_mutex> guard(m_last_stop_packet_mutex); - // Get the number of stop packets on the stack - int nItems = m_stop_packet_stack.size(); - // Iterate over them - for (int i = 0; i < nItems; i++) - { - // Get the thread stop info - StringExtractorGDBRemote stop_info = m_stop_packet_stack[i]; - // Process thread stop info - SetThreadStopInfo(stop_info); - } - // Clear the thread stop stack - m_stop_packet_stack.clear(); - } - - // Check to see if SetThreadStopInfo() filled in m_thread_ids? - if (m_thread_ids.empty()) - { - // No, we need to fetch the thread list manually - UpdateThreadIDList(); - } - - // If we have queried for a default thread id - if (m_initial_tid != LLDB_INVALID_THREAD_ID) - { - m_thread_list.SetSelectedThreadByID(m_initial_tid); - m_initial_tid = LLDB_INVALID_THREAD_ID; - } - - // Let all threads recover from stopping and do any clean up based - // on the previous thread state (if any). - m_thread_list_real.RefreshStateAfterStop(); +Error ProcessGDBRemote::DoHalt(bool &caused_stop) { + Error error; + if (m_public_state.GetValue() == eStateAttaching) { + // We are being asked to halt during an attach. We need to just close + // our file handle and debugserver will go away, and we can be done... + m_gdb_comm.Disconnect(); + } else + caused_stop = m_gdb_comm.Interrupt(); + return error; } -Error -ProcessGDBRemote::DoHalt (bool &caused_stop) -{ - Error error; - - bool timed_out = false; - Mutex::Locker locker; +Error ProcessGDBRemote::DoDetach(bool keep_stopped) { + Error error; + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + if (log) + log->Printf("ProcessGDBRemote::DoDetach(keep_stopped: %i)", keep_stopped); - if (m_public_state.GetValue() == eStateAttaching) - { - // We are being asked to halt during an attach. We need to just close - // our file handle and debugserver will go away, and we can be done... - m_gdb_comm.Disconnect(); - } + error = m_gdb_comm.Detach(keep_stopped); + if (log) { + if (error.Success()) + log->PutCString( + "ProcessGDBRemote::DoDetach() detach packet sent successfully"); else - { - if (!m_gdb_comm.SendInterrupt (locker, 2, timed_out)) - { - if (timed_out) - error.SetErrorString("timed out sending interrupt packet"); - else - error.SetErrorString("unknown error sending interrupt packet"); - } + log->Printf("ProcessGDBRemote::DoDetach() detach packet send failed: %s", + error.AsCString() ? error.AsCString() : "<unknown error>"); + } - caused_stop = m_gdb_comm.GetInterruptWasSent (); - } + if (!error.Success()) return error; -} -Error -ProcessGDBRemote::DoDetach(bool keep_stopped) -{ - Error error; - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); - if (log) - log->Printf ("ProcessGDBRemote::DoDetach(keep_stopped: %i)", keep_stopped); + // Sleep for one second to let the process get all detached... + StopAsyncThread(); - error = m_gdb_comm.Detach (keep_stopped); - if (log) - { - if (error.Success()) - log->PutCString ("ProcessGDBRemote::DoDetach() detach packet sent successfully"); - else - log->Printf ("ProcessGDBRemote::DoDetach() detach packet send failed: %s", error.AsCString() ? error.AsCString() : "<unknown error>"); - } - - if (!error.Success()) - return error; + SetPrivateState(eStateDetached); + ResumePrivateStateThread(); - // Sleep for one second to let the process get all detached... - StopAsyncThread (); - - SetPrivateState (eStateDetached); - ResumePrivateStateThread(); - - //KillDebugserverProcess (); - return error; + // KillDebugserverProcess (); + return error; } - -Error -ProcessGDBRemote::DoDestroy () -{ - Error error; - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); - if (log) - log->Printf ("ProcessGDBRemote::DoDestroy()"); +Error ProcessGDBRemote::DoDestroy() { + Error error; + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + if (log) + log->Printf("ProcessGDBRemote::DoDestroy()"); #if 0 // XXX Currently no iOS target support on FreeBSD - // There is a bug in older iOS debugservers where they don't shut down the process - // they are debugging properly. If the process is sitting at a breakpoint or an exception, - // this can cause problems with restarting. So we check to see if any of our threads are stopped - // at a breakpoint, and if so we remove all the breakpoints, resume the process, and THEN - // destroy it again. - // - // Note, we don't have a good way to test the version of debugserver, but I happen to know that - // the set of all the iOS debugservers which don't support GetThreadSuffixSupported() and that of - // the debugservers with this bug are equal. There really should be a better way to test this! - // - // We also use m_destroy_tried_resuming to make sure we only do this once, if we resume and then halt and - // get called here to destroy again and we're still at a breakpoint or exception, then we should - // just do the straight-forward kill. - // - // And of course, if we weren't able to stop the process by the time we get here, it isn't - // necessary (or helpful) to do any of this. - - if (!m_gdb_comm.GetThreadSuffixSupported() && m_public_state.GetValue() != eStateRunning) - { - PlatformSP platform_sp = GetTarget().GetPlatform(); + // There is a bug in older iOS debugservers where they don't shut down the + // process + // they are debugging properly. If the process is sitting at a breakpoint or + // an exception, + // this can cause problems with restarting. So we check to see if any of our + // threads are stopped + // at a breakpoint, and if so we remove all the breakpoints, resume the + // process, and THEN + // destroy it again. + // + // Note, we don't have a good way to test the version of debugserver, but I + // happen to know that + // the set of all the iOS debugservers which don't support + // GetThreadSuffixSupported() and that of + // the debugservers with this bug are equal. There really should be a better + // way to test this! + // + // We also use m_destroy_tried_resuming to make sure we only do this once, if + // we resume and then halt and + // get called here to destroy again and we're still at a breakpoint or + // exception, then we should + // just do the straight-forward kill. + // + // And of course, if we weren't able to stop the process by the time we get + // here, it isn't + // necessary (or helpful) to do any of this. + + if (!m_gdb_comm.GetThreadSuffixSupported() && + m_public_state.GetValue() != eStateRunning) { + PlatformSP platform_sp = GetTarget().GetPlatform(); + + // FIXME: These should be ConstStrings so we aren't doing strcmp'ing. + if (platform_sp && platform_sp->GetName() && + platform_sp->GetName() == PlatformRemoteiOS::GetPluginNameStatic()) { + if (m_destroy_tried_resuming) { + if (log) + log->PutCString("ProcessGDBRemote::DoDestroy() - Tried resuming to " + "destroy once already, not doing it again."); + } else { + // At present, the plans are discarded and the breakpoints disabled + // Process::Destroy, + // but we really need it to happen here and it doesn't matter if we do + // it twice. + m_thread_list.DiscardThreadPlans(); + DisableAllBreakpointSites(); + + bool stop_looks_like_crash = false; + ThreadList &threads = GetThreadList(); - // FIXME: These should be ConstStrings so we aren't doing strcmp'ing. - if (platform_sp - && platform_sp->GetName() - && platform_sp->GetName() == PlatformRemoteiOS::GetPluginNameStatic()) { - if (m_destroy_tried_resuming) - { - if (log) - log->PutCString ("ProcessGDBRemote::DoDestroy() - Tried resuming to destroy once already, not doing it again."); + std::lock_guard<std::recursive_mutex> guard(threads.GetMutex()); + + size_t num_threads = threads.GetSize(); + for (size_t i = 0; i < num_threads; i++) { + ThreadSP thread_sp = threads.GetThreadAtIndex(i); + StopInfoSP stop_info_sp = thread_sp->GetPrivateStopInfo(); + StopReason reason = eStopReasonInvalid; + if (stop_info_sp) + reason = stop_info_sp->GetStopReason(); + if (reason == eStopReasonBreakpoint || + reason == eStopReasonException) { + if (log) + log->Printf( + "ProcessGDBRemote::DoDestroy() - thread: 0x%4.4" PRIx64 + " stopped with reason: %s.", + thread_sp->GetProtocolID(), stop_info_sp->GetDescription()); + stop_looks_like_crash = true; + break; } - else - { - // At present, the plans are discarded and the breakpoints disabled Process::Destroy, - // but we really need it to happen here and it doesn't matter if we do it twice. - m_thread_list.DiscardThreadPlans(); - DisableAllBreakpointSites(); - - bool stop_looks_like_crash = false; - ThreadList &threads = GetThreadList(); - - { - std::lock_guard<std::recursive_mutex> guard(threads.GetMutex()); - - size_t num_threads = threads.GetSize(); - for (size_t i = 0; i < num_threads; i++) - { - ThreadSP thread_sp = threads.GetThreadAtIndex(i); - StopInfoSP stop_info_sp = thread_sp->GetPrivateStopInfo(); - StopReason reason = eStopReasonInvalid; - if (stop_info_sp) - reason = stop_info_sp->GetStopReason(); - if (reason == eStopReasonBreakpoint - || reason == eStopReasonException) - { - if (log) - log->Printf ("ProcessGDBRemote::DoDestroy() - thread: 0x%4.4" PRIx64 " stopped with reason: %s.", - thread_sp->GetProtocolID(), - stop_info_sp->GetDescription()); - stop_looks_like_crash = true; - break; - } - } - } + } + } - if (stop_looks_like_crash) - { - if (log) - log->PutCString ("ProcessGDBRemote::DoDestroy() - Stopped at a breakpoint, continue and then kill."); - m_destroy_tried_resuming = true; - - // If we are going to run again before killing, it would be good to suspend all the threads - // before resuming so they won't get into more trouble. Sadly, for the threads stopped with - // the breakpoint or exception, the exception doesn't get cleared if it is suspended, so we do - // have to run the risk of letting those threads proceed a bit. - - { - std::lock_guard<std::recursive_mutex> guard(threads.GetMutex()); - - size_t num_threads = threads.GetSize(); - for (size_t i = 0; i < num_threads; i++) - { - ThreadSP thread_sp = threads.GetThreadAtIndex(i); - StopInfoSP stop_info_sp = thread_sp->GetPrivateStopInfo(); - StopReason reason = eStopReasonInvalid; - if (stop_info_sp) - reason = stop_info_sp->GetStopReason(); - if (reason != eStopReasonBreakpoint - && reason != eStopReasonException) - { - if (log) - log->Printf ("ProcessGDBRemote::DoDestroy() - Suspending thread: 0x%4.4" PRIx64 " before running.", - thread_sp->GetProtocolID()); - thread_sp->SetResumeState(eStateSuspended); - } - } - } - Resume (); - return Destroy(false); - } + if (stop_looks_like_crash) { + if (log) + log->PutCString("ProcessGDBRemote::DoDestroy() - Stopped at a " + "breakpoint, continue and then kill."); + m_destroy_tried_resuming = true; + + // If we are going to run again before killing, it would be good to + // suspend all the threads + // before resuming so they won't get into more trouble. Sadly, for + // the threads stopped with + // the breakpoint or exception, the exception doesn't get cleared if + // it is suspended, so we do + // have to run the risk of letting those threads proceed a bit. + + { + std::lock_guard<std::recursive_mutex> guard(threads.GetMutex()); + + size_t num_threads = threads.GetSize(); + for (size_t i = 0; i < num_threads; i++) { + ThreadSP thread_sp = threads.GetThreadAtIndex(i); + StopInfoSP stop_info_sp = thread_sp->GetPrivateStopInfo(); + StopReason reason = eStopReasonInvalid; + if (stop_info_sp) + reason = stop_info_sp->GetStopReason(); + if (reason != eStopReasonBreakpoint && + reason != eStopReasonException) { + if (log) + log->Printf("ProcessGDBRemote::DoDestroy() - Suspending " + "thread: 0x%4.4" PRIx64 " before running.", + thread_sp->GetProtocolID()); + thread_sp->SetResumeState(eStateSuspended); + } } + } + Resume(); + return Destroy(false); } + } } + } #endif - // Interrupt if our inferior is running... - int exit_status = SIGABRT; - std::string exit_string; + // Interrupt if our inferior is running... + int exit_status = SIGABRT; + std::string exit_string; - if (m_gdb_comm.IsConnected()) - { - if (m_public_state.GetValue() != eStateAttaching) - { - StringExtractorGDBRemote response; - bool send_async = true; - GDBRemoteCommunication::ScopedTimeout (m_gdb_comm, 3); + if (m_gdb_comm.IsConnected()) { + if (m_public_state.GetValue() != eStateAttaching) { + StringExtractorGDBRemote response; + bool send_async = true; + GDBRemoteCommunication::ScopedTimeout(m_gdb_comm, + std::chrono::seconds(3)); - if (m_gdb_comm.SendPacketAndWaitForResponse("k", 1, response, send_async) == GDBRemoteCommunication::PacketResult::Success) - { - char packet_cmd = response.GetChar(0); + if (m_gdb_comm.SendPacketAndWaitForResponse("k", response, send_async) == + GDBRemoteCommunication::PacketResult::Success) { + char packet_cmd = response.GetChar(0); - if (packet_cmd == 'W' || packet_cmd == 'X') - { + if (packet_cmd == 'W' || packet_cmd == 'X') { #if defined(__APPLE__) - // For Native processes on Mac OS X, we launch through the Host Platform, then hand the process off - // to debugserver, which becomes the parent process through "PT_ATTACH". Then when we go to kill - // the process on Mac OS X we call ptrace(PT_KILL) to kill it, then we call waitpid which returns - // with no error and the correct status. But amusingly enough that doesn't seem to actually reap - // the process, but instead it is left around as a Zombie. Probably the kernel is in the process of - // switching ownership back to lldb which was the original parent, and gets confused in the handoff. - // Anyway, so call waitpid here to finally reap it. - PlatformSP platform_sp(GetTarget().GetPlatform()); - if (platform_sp && platform_sp->IsHost()) - { - int status; - ::pid_t reap_pid; - reap_pid = waitpid (GetID(), &status, WNOHANG); - if (log) - log->Printf ("Reaped pid: %d, status: %d.\n", reap_pid, status); - } -#endif - SetLastStopPacket (response); - ClearThreadIDList (); - exit_status = response.GetHexU8(); - } - else - { - if (log) - log->Printf ("ProcessGDBRemote::DoDestroy - got unexpected response to k packet: %s", response.GetStringRef().c_str()); - exit_string.assign("got unexpected response to k packet: "); - exit_string.append(response.GetStringRef()); - } - } - else - { - if (log) - log->Printf ("ProcessGDBRemote::DoDestroy - failed to send k packet"); - exit_string.assign("failed to send the k packet"); - } - } - else - { + // For Native processes on Mac OS X, we launch through the Host + // Platform, then hand the process off + // to debugserver, which becomes the parent process through + // "PT_ATTACH". Then when we go to kill + // the process on Mac OS X we call ptrace(PT_KILL) to kill it, then we + // call waitpid which returns + // with no error and the correct status. But amusingly enough that + // doesn't seem to actually reap + // the process, but instead it is left around as a Zombie. Probably + // the kernel is in the process of + // switching ownership back to lldb which was the original parent, and + // gets confused in the handoff. + // Anyway, so call waitpid here to finally reap it. + PlatformSP platform_sp(GetTarget().GetPlatform()); + if (platform_sp && platform_sp->IsHost()) { + int status; + ::pid_t reap_pid; + reap_pid = waitpid(GetID(), &status, WNOHANG); if (log) - log->Printf ("ProcessGDBRemote::DoDestroy - killed or interrupted while attaching"); - exit_string.assign ("killed or interrupted while attaching."); + log->Printf("Reaped pid: %d, status: %d.\n", reap_pid, status); + } +#endif + SetLastStopPacket(response); + ClearThreadIDList(); + exit_status = response.GetHexU8(); + } else { + if (log) + log->Printf("ProcessGDBRemote::DoDestroy - got unexpected response " + "to k packet: %s", + response.GetStringRef().c_str()); + exit_string.assign("got unexpected response to k packet: "); + exit_string.append(response.GetStringRef()); } - } - else - { - // If we missed setting the exit status on the way out, do it here. - // NB set exit status can be called multiple times, the first one sets the status. - exit_string.assign("destroying when not connected to debugserver"); - } - - SetExitStatus(exit_status, exit_string.c_str()); - - StopAsyncThread (); - KillDebugserverProcess (); - return error; -} - -void -ProcessGDBRemote::SetLastStopPacket (const StringExtractorGDBRemote &response) -{ - const bool did_exec = response.GetStringRef().find(";reason:exec;") != std::string::npos; - if (did_exec) - { - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + } else { if (log) - log->Printf ("ProcessGDBRemote::SetLastStopPacket () - detected exec"); + log->Printf("ProcessGDBRemote::DoDestroy - failed to send k packet"); + exit_string.assign("failed to send the k packet"); + } + } else { + if (log) + log->Printf("ProcessGDBRemote::DoDestroy - killed or interrupted while " + "attaching"); + exit_string.assign("killed or interrupted while attaching."); + } + } else { + // If we missed setting the exit status on the way out, do it here. + // NB set exit status can be called multiple times, the first one sets the + // status. + exit_string.assign("destroying when not connected to debugserver"); + } + + SetExitStatus(exit_status, exit_string.c_str()); + + StopAsyncThread(); + KillDebugserverProcess(); + return error; +} - m_thread_list_real.Clear(); - m_thread_list.Clear(); - BuildDynamicRegisterInfo (true); - m_gdb_comm.ResetDiscoverableSettings (did_exec); - } +void ProcessGDBRemote::SetLastStopPacket( + const StringExtractorGDBRemote &response) { + const bool did_exec = + response.GetStringRef().find(";reason:exec;") != std::string::npos; + if (did_exec) { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + if (log) + log->Printf("ProcessGDBRemote::SetLastStopPacket () - detected exec"); - // Scope the lock - { - // Lock the thread stack while we access it - std::lock_guard<std::recursive_mutex> guard(m_last_stop_packet_mutex); - - // 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) - m_stop_packet_stack.clear(); - - // Add this stop packet to the stop packet stack - // This stack will get popped and examined when we switch to the - // Stopped state - m_stop_packet_stack.push_back(response); - } + m_thread_list_real.Clear(); + m_thread_list.Clear(); + BuildDynamicRegisterInfo(true); + m_gdb_comm.ResetDiscoverableSettings(did_exec); + } + + // Scope the lock + { + // Lock the thread stack while we access it + std::lock_guard<std::recursive_mutex> guard(m_last_stop_packet_mutex); + + // 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) + m_stop_packet_stack.clear(); + + // Add this stop packet to the stop packet stack + // This stack will get popped and examined when we switch to the + // Stopped state + m_stop_packet_stack.push_back(response); + } } -void -ProcessGDBRemote::SetUnixSignals(const UnixSignalsSP &signals_sp) -{ - Process::SetUnixSignals(std::make_shared<GDBRemoteSignals>(signals_sp)); +void ProcessGDBRemote::SetUnixSignals(const UnixSignalsSP &signals_sp) { + Process::SetUnixSignals(std::make_shared<GDBRemoteSignals>(signals_sp)); } //------------------------------------------------------------------ // Process Queries //------------------------------------------------------------------ -bool -ProcessGDBRemote::IsAlive () -{ - return m_gdb_comm.IsConnected() && Process::IsAlive(); +bool ProcessGDBRemote::IsAlive() { + return m_gdb_comm.IsConnected() && Process::IsAlive(); } -addr_t -ProcessGDBRemote::GetImageInfoAddress() -{ - // request the link map address via the $qShlibInfoAddr packet - lldb::addr_t addr = m_gdb_comm.GetShlibInfoAddr(); +addr_t ProcessGDBRemote::GetImageInfoAddress() { + // request the link map address via the $qShlibInfoAddr packet + lldb::addr_t addr = m_gdb_comm.GetShlibInfoAddr(); - // the loaded module list can also provides a link map address - if (addr == LLDB_INVALID_ADDRESS) - { - LoadedModuleInfoList list; - if (GetLoadedModuleList (list).Success()) - addr = list.m_link_map; - } + // the loaded module list can also provides a link map address + if (addr == LLDB_INVALID_ADDRESS) { + LoadedModuleInfoList list; + if (GetLoadedModuleList(list).Success()) + addr = list.m_link_map; + } - return addr; + return addr; } -void -ProcessGDBRemote::WillPublicStop () -{ - // See if the GDB remote client supports the JSON threads info. - // If so, we gather stop info for all threads, expedited registers, - // expedited memory, runtime queue information (iOS and MacOSX only), - // and more. Expediting memory will help stack backtracing be much - // faster. Expediting registers will make sure we don't have to read - // the thread registers for GPRs. - m_jthreadsinfo_sp = m_gdb_comm.GetThreadsInfo(); - - if (m_jthreadsinfo_sp) - { - // Now set the stop info for each thread and also expedite any registers - // and memory that was in the jThreadsInfo response. - StructuredData::Array *thread_infos = m_jthreadsinfo_sp->GetAsArray(); - if (thread_infos) - { - const size_t n = thread_infos->GetSize(); - for (size_t i=0; i<n; ++i) - { - StructuredData::Dictionary *thread_dict = thread_infos->GetItemAtIndex(i)->GetAsDictionary(); - if (thread_dict) - SetThreadStopInfo(thread_dict); - } - } - } +void ProcessGDBRemote::WillPublicStop() { + // See if the GDB remote client supports the JSON threads info. + // If so, we gather stop info for all threads, expedited registers, + // expedited memory, runtime queue information (iOS and MacOSX only), + // and more. Expediting memory will help stack backtracing be much + // faster. Expediting registers will make sure we don't have to read + // the thread registers for GPRs. + m_jthreadsinfo_sp = m_gdb_comm.GetThreadsInfo(); + + if (m_jthreadsinfo_sp) { + // Now set the stop info for each thread and also expedite any registers + // and memory that was in the jThreadsInfo response. + StructuredData::Array *thread_infos = m_jthreadsinfo_sp->GetAsArray(); + if (thread_infos) { + const size_t n = thread_infos->GetSize(); + for (size_t i = 0; i < n; ++i) { + StructuredData::Dictionary *thread_dict = + thread_infos->GetItemAtIndex(i)->GetAsDictionary(); + if (thread_dict) + SetThreadStopInfo(thread_dict); + } + } + } } //------------------------------------------------------------------ // Process Memory //------------------------------------------------------------------ -size_t -ProcessGDBRemote::DoReadMemory (addr_t addr, void *buf, size_t size, Error &error) -{ - GetMaxMemorySize (); - if (size > m_max_memory_size) - { - // Keep memory read sizes down to a sane limit. This function will be - // called multiple times in order to complete the task by - // lldb_private::Process so it is ok to do this. - size = m_max_memory_size; - } - - char packet[64]; - int packet_len; - bool binary_memory_read = m_gdb_comm.GetxPacketSupported(); - packet_len = ::snprintf(packet, sizeof(packet), "%c%" PRIx64 ",%" PRIx64, - binary_memory_read ? 'x' : 'm', (uint64_t)addr, (uint64_t)size); - assert (packet_len + 1 < (int)sizeof(packet)); - StringExtractorGDBRemote response; - if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, true) == GDBRemoteCommunication::PacketResult::Success) - { - if (response.IsNormalResponse()) - { - error.Clear(); - if (binary_memory_read) - { - // The lower level GDBRemoteCommunication packet receive layer has already de-quoted any - // 0x7d character escaping that was present in the packet - - size_t data_received_size = response.GetBytesLeft(); - if (data_received_size > size) - { - // Don't write past the end of BUF if the remote debug server gave us too - // much data for some reason. - data_received_size = size; - } - memcpy (buf, response.GetStringRef().data(), data_received_size); - return data_received_size; - } - else - { - return response.GetHexBytes(buf, size, '\xdd'); - } +size_t ProcessGDBRemote::DoReadMemory(addr_t addr, void *buf, size_t size, + Error &error) { + GetMaxMemorySize(); + if (size > m_max_memory_size) { + // Keep memory read sizes down to a sane limit. This function will be + // called multiple times in order to complete the task by + // lldb_private::Process so it is ok to do this. + size = m_max_memory_size; + } + + char packet[64]; + int packet_len; + bool binary_memory_read = m_gdb_comm.GetxPacketSupported(); + packet_len = ::snprintf(packet, sizeof(packet), "%c%" PRIx64 ",%" PRIx64, + binary_memory_read ? 'x' : 'm', (uint64_t)addr, + (uint64_t)size); + assert(packet_len + 1 < (int)sizeof(packet)); + UNUSED_IF_ASSERT_DISABLED(packet_len); + StringExtractorGDBRemote response; + if (m_gdb_comm.SendPacketAndWaitForResponse(packet, response, true) == + GDBRemoteCommunication::PacketResult::Success) { + if (response.IsNormalResponse()) { + error.Clear(); + if (binary_memory_read) { + // The lower level GDBRemoteCommunication packet receive layer has + // already de-quoted any + // 0x7d character escaping that was present in the packet + + size_t data_received_size = response.GetBytesLeft(); + if (data_received_size > size) { + // Don't write past the end of BUF if the remote debug server gave us + // too + // much data for some reason. + data_received_size = size; } - else if (response.IsErrorResponse()) - error.SetErrorStringWithFormat("memory read failed for 0x%" PRIx64, addr); - else if (response.IsUnsupportedResponse()) - error.SetErrorStringWithFormat("GDB server does not support reading memory"); - else - error.SetErrorStringWithFormat("unexpected response to GDB server memory read packet '%s': '%s'", packet, response.GetStringRef().c_str()); - } + memcpy(buf, response.GetStringRef().data(), data_received_size); + return data_received_size; + } else { + return response.GetHexBytes( + llvm::MutableArrayRef<uint8_t>((uint8_t *)buf, size), '\xdd'); + } + } else if (response.IsErrorResponse()) + error.SetErrorStringWithFormat("memory read failed for 0x%" PRIx64, addr); + else if (response.IsUnsupportedResponse()) + error.SetErrorStringWithFormat( + "GDB server does not support reading memory"); else - { - error.SetErrorStringWithFormat("failed to send packet: '%s'", packet); - } - return 0; + error.SetErrorStringWithFormat( + "unexpected response to GDB server memory read packet '%s': '%s'", + packet, response.GetStringRef().c_str()); + } else { + error.SetErrorStringWithFormat("failed to send packet: '%s'", packet); + } + return 0; } -size_t -ProcessGDBRemote::DoWriteMemory (addr_t addr, const void *buf, size_t size, Error &error) -{ - GetMaxMemorySize (); - if (size > m_max_memory_size) - { - // Keep memory read sizes down to a sane limit. This function will be - // called multiple times in order to complete the task by - // lldb_private::Process so it is ok to do this. - size = m_max_memory_size; - } - - StreamString packet; - packet.Printf("M%" PRIx64 ",%" PRIx64 ":", addr, (uint64_t)size); - packet.PutBytesAsRawHex8(buf, size, endian::InlHostByteOrder(), endian::InlHostByteOrder()); - StringExtractorGDBRemote response; - if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetData(), packet.GetSize(), response, true) == GDBRemoteCommunication::PacketResult::Success) - { - if (response.IsOKResponse()) - { - error.Clear(); - return size; - } - else if (response.IsErrorResponse()) - error.SetErrorStringWithFormat("memory write failed for 0x%" PRIx64, addr); - else if (response.IsUnsupportedResponse()) - error.SetErrorStringWithFormat("GDB server does not support writing memory"); - else - error.SetErrorStringWithFormat("unexpected response to GDB server memory write packet '%s': '%s'", packet.GetString().c_str(), response.GetStringRef().c_str()); - } +size_t ProcessGDBRemote::DoWriteMemory(addr_t addr, const void *buf, + size_t size, Error &error) { + GetMaxMemorySize(); + if (size > m_max_memory_size) { + // Keep memory read sizes down to a sane limit. This function will be + // called multiple times in order to complete the task by + // lldb_private::Process so it is ok to do this. + size = m_max_memory_size; + } + + StreamString packet; + packet.Printf("M%" PRIx64 ",%" PRIx64 ":", addr, (uint64_t)size); + packet.PutBytesAsRawHex8(buf, size, endian::InlHostByteOrder(), + endian::InlHostByteOrder()); + StringExtractorGDBRemote response; + if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response, + true) == + GDBRemoteCommunication::PacketResult::Success) { + if (response.IsOKResponse()) { + error.Clear(); + return size; + } else if (response.IsErrorResponse()) + error.SetErrorStringWithFormat("memory write failed for 0x%" PRIx64, + addr); + else if (response.IsUnsupportedResponse()) + error.SetErrorStringWithFormat( + "GDB server does not support writing memory"); else - { - error.SetErrorStringWithFormat("failed to send packet: '%s'", packet.GetString().c_str()); - } - return 0; + error.SetErrorStringWithFormat( + "unexpected response to GDB server memory write packet '%s': '%s'", + packet.GetData(), response.GetStringRef().c_str()); + } else { + error.SetErrorStringWithFormat("failed to send packet: '%s'", + packet.GetData()); + } + return 0; } -lldb::addr_t -ProcessGDBRemote::DoAllocateMemory (size_t size, uint32_t permissions, Error &error) -{ - Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_EXPRESSIONS)); - addr_t allocated_addr = LLDB_INVALID_ADDRESS; - - if (m_gdb_comm.SupportsAllocDeallocMemory() != eLazyBoolNo) - { - allocated_addr = m_gdb_comm.AllocateMemory (size, permissions); - if (allocated_addr != LLDB_INVALID_ADDRESS || m_gdb_comm.SupportsAllocDeallocMemory() == eLazyBoolYes) - return allocated_addr; - } - - if (m_gdb_comm.SupportsAllocDeallocMemory() == eLazyBoolNo) - { - // Call mmap() to create memory in the inferior.. - unsigned prot = 0; - if (permissions & lldb::ePermissionsReadable) - prot |= eMmapProtRead; - if (permissions & lldb::ePermissionsWritable) - prot |= eMmapProtWrite; - if (permissions & lldb::ePermissionsExecutable) - prot |= eMmapProtExec; - - if (InferiorCallMmap(this, allocated_addr, 0, size, prot, - eMmapFlagsAnon | eMmapFlagsPrivate, -1, 0)) - m_addr_to_mmap_size[allocated_addr] = size; - else - { - allocated_addr = LLDB_INVALID_ADDRESS; - if (log) - log->Printf ("ProcessGDBRemote::%s no direct stub support for memory allocation, and InferiorCallMmap also failed - is stub missing register context save/restore capability?", __FUNCTION__); - } - } - - if (allocated_addr == LLDB_INVALID_ADDRESS) - error.SetErrorStringWithFormat("unable to allocate %" PRIu64 " bytes of memory with permissions %s", (uint64_t)size, GetPermissionsAsCString (permissions)); - else - error.Clear(); - return allocated_addr; +lldb::addr_t ProcessGDBRemote::DoAllocateMemory(size_t size, + uint32_t permissions, + Error &error) { + Log *log( + GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_EXPRESSIONS)); + addr_t allocated_addr = LLDB_INVALID_ADDRESS; + + if (m_gdb_comm.SupportsAllocDeallocMemory() != eLazyBoolNo) { + allocated_addr = m_gdb_comm.AllocateMemory(size, permissions); + if (allocated_addr != LLDB_INVALID_ADDRESS || + m_gdb_comm.SupportsAllocDeallocMemory() == eLazyBoolYes) + return allocated_addr; + } + + if (m_gdb_comm.SupportsAllocDeallocMemory() == eLazyBoolNo) { + // Call mmap() to create memory in the inferior.. + unsigned prot = 0; + if (permissions & lldb::ePermissionsReadable) + prot |= eMmapProtRead; + if (permissions & lldb::ePermissionsWritable) + prot |= eMmapProtWrite; + if (permissions & lldb::ePermissionsExecutable) + prot |= eMmapProtExec; + + if (InferiorCallMmap(this, allocated_addr, 0, size, prot, + eMmapFlagsAnon | eMmapFlagsPrivate, -1, 0)) + m_addr_to_mmap_size[allocated_addr] = size; + else { + allocated_addr = LLDB_INVALID_ADDRESS; + if (log) + log->Printf("ProcessGDBRemote::%s no direct stub support for memory " + "allocation, and InferiorCallMmap also failed - is stub " + "missing register context save/restore capability?", + __FUNCTION__); + } + } + + if (allocated_addr == LLDB_INVALID_ADDRESS) + error.SetErrorStringWithFormat( + "unable to allocate %" PRIu64 " bytes of memory with permissions %s", + (uint64_t)size, GetPermissionsAsCString(permissions)); + else + error.Clear(); + return allocated_addr; } -Error -ProcessGDBRemote::GetMemoryRegionInfo (addr_t load_addr, - MemoryRegionInfo ®ion_info) -{ +Error ProcessGDBRemote::GetMemoryRegionInfo(addr_t load_addr, + MemoryRegionInfo ®ion_info) { - Error error (m_gdb_comm.GetMemoryRegionInfo (load_addr, region_info)); - return error; + Error error(m_gdb_comm.GetMemoryRegionInfo(load_addr, region_info)); + return error; } -Error -ProcessGDBRemote::GetWatchpointSupportInfo (uint32_t &num) -{ +Error ProcessGDBRemote::GetWatchpointSupportInfo(uint32_t &num) { - Error error (m_gdb_comm.GetWatchpointSupportInfo (num)); - return error; + Error error(m_gdb_comm.GetWatchpointSupportInfo(num)); + return error; } -Error -ProcessGDBRemote::GetWatchpointSupportInfo (uint32_t &num, bool& after) -{ - Error error (m_gdb_comm.GetWatchpointSupportInfo (num, after, GetTarget().GetArchitecture())); - return error; +Error ProcessGDBRemote::GetWatchpointSupportInfo(uint32_t &num, bool &after) { + Error error(m_gdb_comm.GetWatchpointSupportInfo( + num, after, GetTarget().GetArchitecture())); + return error; } -Error -ProcessGDBRemote::DoDeallocateMemory (lldb::addr_t addr) -{ - Error error; - LazyBool supported = m_gdb_comm.SupportsAllocDeallocMemory(); - - switch (supported) - { - case eLazyBoolCalculate: - // We should never be deallocating memory without allocating memory - // first so we should never get eLazyBoolCalculate - error.SetErrorString ("tried to deallocate memory without ever allocating memory"); - break; - - case eLazyBoolYes: - if (!m_gdb_comm.DeallocateMemory (addr)) - error.SetErrorStringWithFormat("unable to deallocate memory at 0x%" PRIx64, addr); - break; - - case eLazyBoolNo: - // Call munmap() to deallocate memory in the inferior.. - { - MMapMap::iterator pos = m_addr_to_mmap_size.find(addr); - if (pos != m_addr_to_mmap_size.end() && - InferiorCallMunmap(this, addr, pos->second)) - m_addr_to_mmap_size.erase (pos); - else - error.SetErrorStringWithFormat("unable to deallocate memory at 0x%" PRIx64, addr); - } - break; - } - - return error; +Error ProcessGDBRemote::DoDeallocateMemory(lldb::addr_t addr) { + Error error; + LazyBool supported = m_gdb_comm.SupportsAllocDeallocMemory(); + + switch (supported) { + case eLazyBoolCalculate: + // We should never be deallocating memory without allocating memory + // first so we should never get eLazyBoolCalculate + error.SetErrorString( + "tried to deallocate memory without ever allocating memory"); + break; + + case eLazyBoolYes: + if (!m_gdb_comm.DeallocateMemory(addr)) + error.SetErrorStringWithFormat( + "unable to deallocate memory at 0x%" PRIx64, addr); + break; + + case eLazyBoolNo: + // Call munmap() to deallocate memory in the inferior.. + { + MMapMap::iterator pos = m_addr_to_mmap_size.find(addr); + if (pos != m_addr_to_mmap_size.end() && + InferiorCallMunmap(this, addr, pos->second)) + m_addr_to_mmap_size.erase(pos); + else + error.SetErrorStringWithFormat( + "unable to deallocate memory at 0x%" PRIx64, addr); + } + break; + } + + return error; } - //------------------------------------------------------------------ // Process STDIO //------------------------------------------------------------------ -size_t -ProcessGDBRemote::PutSTDIN (const char *src, size_t src_len, Error &error) -{ - if (m_stdio_communication.IsConnected()) - { - ConnectionStatus status; - m_stdio_communication.Write(src, src_len, status, NULL); - } - else if (m_stdin_forward) - { - m_gdb_comm.SendStdinNotification(src, src_len); - } - return 0; +size_t ProcessGDBRemote::PutSTDIN(const char *src, size_t src_len, + Error &error) { + if (m_stdio_communication.IsConnected()) { + ConnectionStatus status; + m_stdio_communication.Write(src, src_len, status, NULL); + } else if (m_stdin_forward) { + m_gdb_comm.SendStdinNotification(src, src_len); + } + return 0; } -Error -ProcessGDBRemote::EnableBreakpointSite (BreakpointSite *bp_site) -{ - Error error; - assert(bp_site != NULL); - - // Get logging info - Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_BREAKPOINTS)); - user_id_t site_id = bp_site->GetID(); - - // Get the breakpoint address - const addr_t addr = bp_site->GetLoadAddress(); - - // Log that a breakpoint was requested - if (log) - log->Printf("ProcessGDBRemote::EnableBreakpointSite (size_id = %" PRIu64 ") address = 0x%" PRIx64, site_id, (uint64_t)addr); - - // Breakpoint already exists and is enabled - if (bp_site->IsEnabled()) - { - if (log) - log->Printf("ProcessGDBRemote::EnableBreakpointSite (size_id = %" PRIu64 ") address = 0x%" PRIx64 " -- SUCCESS (already enabled)", site_id, (uint64_t)addr); - return error; - } +Error ProcessGDBRemote::EnableBreakpointSite(BreakpointSite *bp_site) { + Error error; + assert(bp_site != NULL); - // Get the software breakpoint trap opcode size - const size_t bp_op_size = GetSoftwareBreakpointTrapOpcode(bp_site); + // Get logging info + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_BREAKPOINTS)); + user_id_t site_id = bp_site->GetID(); - // SupportsGDBStoppointPacket() simply checks a boolean, indicating if this breakpoint type - // is supported by the remote stub. These are set to true by default, and later set to false - // only after we receive an unimplemented response when sending a breakpoint packet. This means - // initially that unless we were specifically instructed to use a hardware breakpoint, LLDB will - // attempt to set a software breakpoint. HardwareRequired() also queries a boolean variable which - // indicates if the user specifically asked for hardware breakpoints. If true then we will - // skip over software breakpoints. - if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointSoftware) && (!bp_site->HardwareRequired())) - { - // Try to send off a software breakpoint packet ($Z0) - uint8_t error_no = m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointSoftware, true, addr, bp_op_size); - if (error_no == 0) - { - // The breakpoint was placed successfully - bp_site->SetEnabled(true); - bp_site->SetType(BreakpointSite::eExternal); - return error; - } + // Get the breakpoint address + const addr_t addr = bp_site->GetLoadAddress(); - // SendGDBStoppointTypePacket() will return an error if it was unable to set this - // breakpoint. We need to differentiate between a error specific to placing this breakpoint - // or if we have learned that this breakpoint type is unsupported. To do this, we - // must test the support boolean for this breakpoint type to see if it now indicates that - // this breakpoint type is unsupported. If they are still supported then we should return - // with the error code. If they are now unsupported, then we would like to fall through - // and try another form of breakpoint. - if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointSoftware)) - { - if (error_no != UINT8_MAX) - error.SetErrorStringWithFormat("error: %d sending the breakpoint request", errno); - else - error.SetErrorString("error sending the breakpoint request"); - return error; - } - - // We reach here when software breakpoints have been found to be unsupported. For future - // calls to set a breakpoint, we will not attempt to set a breakpoint with a type that is - // known not to be supported. - if (log) - log->Printf("Software breakpoints are unsupported"); - - // So we will fall through and try a hardware breakpoint - } - - // The process of setting a hardware breakpoint is much the same as above. We check the - // supported boolean for this breakpoint type, and if it is thought to be supported then we - // will try to set this breakpoint with a hardware breakpoint. - if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointHardware)) - { - // Try to send off a hardware breakpoint packet ($Z1) - uint8_t error_no = m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointHardware, true, addr, bp_op_size); - if (error_no == 0) - { - // The breakpoint was placed successfully - bp_site->SetEnabled(true); - bp_site->SetType(BreakpointSite::eHardware); - return error; - } - - // Check if the error was something other then an unsupported breakpoint type - if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointHardware)) - { - // Unable to set this hardware breakpoint - if (error_no != UINT8_MAX) - error.SetErrorStringWithFormat("error: %d sending the hardware breakpoint request " - "(hardware breakpoint resources might be exhausted or unavailable)", - error_no); - else - error.SetErrorString("error sending the hardware breakpoint request (hardware breakpoint resources " - "might be exhausted or unavailable)"); - return error; - } + // Log that a breakpoint was requested + if (log) + log->Printf("ProcessGDBRemote::EnableBreakpointSite (size_id = %" PRIu64 + ") address = 0x%" PRIx64, + site_id, (uint64_t)addr); - // We will reach here when the stub gives an unsupported response to a hardware breakpoint - if (log) - log->Printf("Hardware breakpoints are unsupported"); + // Breakpoint already exists and is enabled + if (bp_site->IsEnabled()) { + if (log) + log->Printf("ProcessGDBRemote::EnableBreakpointSite (size_id = %" PRIu64 + ") address = 0x%" PRIx64 " -- SUCCESS (already enabled)", + site_id, (uint64_t)addr); + return error; + } + + // Get the software breakpoint trap opcode size + const size_t bp_op_size = GetSoftwareBreakpointTrapOpcode(bp_site); + + // SupportsGDBStoppointPacket() simply checks a boolean, indicating if this + // breakpoint type + // is supported by the remote stub. These are set to true by default, and + // later set to false + // only after we receive an unimplemented response when sending a breakpoint + // packet. This means + // initially that unless we were specifically instructed to use a hardware + // breakpoint, LLDB will + // attempt to set a software breakpoint. HardwareRequired() also queries a + // boolean variable which + // indicates if the user specifically asked for hardware breakpoints. If true + // then we will + // skip over software breakpoints. + if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointSoftware) && + (!bp_site->HardwareRequired())) { + // Try to send off a software breakpoint packet ($Z0) + uint8_t error_no = m_gdb_comm.SendGDBStoppointTypePacket( + eBreakpointSoftware, true, addr, bp_op_size); + if (error_no == 0) { + // The breakpoint was placed successfully + bp_site->SetEnabled(true); + bp_site->SetType(BreakpointSite::eExternal); + return error; + } + + // SendGDBStoppointTypePacket() will return an error if it was unable to set + // this + // breakpoint. We need to differentiate between a error specific to placing + // this breakpoint + // or if we have learned that this breakpoint type is unsupported. To do + // this, we + // must test the support boolean for this breakpoint type to see if it now + // indicates that + // this breakpoint type is unsupported. If they are still supported then we + // should return + // with the error code. If they are now unsupported, then we would like to + // fall through + // and try another form of breakpoint. + if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointSoftware)) { + if (error_no != UINT8_MAX) + error.SetErrorStringWithFormat( + "error: %d sending the breakpoint request", errno); + else + error.SetErrorString("error sending the breakpoint request"); + return error; + } + + // We reach here when software breakpoints have been found to be + // unsupported. For future + // calls to set a breakpoint, we will not attempt to set a breakpoint with a + // type that is + // known not to be supported. + if (log) + log->Printf("Software breakpoints are unsupported"); + + // So we will fall through and try a hardware breakpoint + } + + // The process of setting a hardware breakpoint is much the same as above. We + // check the + // supported boolean for this breakpoint type, and if it is thought to be + // supported then we + // will try to set this breakpoint with a hardware breakpoint. + if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointHardware)) { + // Try to send off a hardware breakpoint packet ($Z1) + uint8_t error_no = m_gdb_comm.SendGDBStoppointTypePacket( + eBreakpointHardware, true, addr, bp_op_size); + if (error_no == 0) { + // The breakpoint was placed successfully + bp_site->SetEnabled(true); + bp_site->SetType(BreakpointSite::eHardware); + return error; + } + + // Check if the error was something other then an unsupported breakpoint + // type + if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointHardware)) { + // Unable to set this hardware breakpoint + if (error_no != UINT8_MAX) + error.SetErrorStringWithFormat( + "error: %d sending the hardware breakpoint request " + "(hardware breakpoint resources might be exhausted or unavailable)", + error_no); + else + error.SetErrorString("error sending the hardware breakpoint request " + "(hardware breakpoint resources " + "might be exhausted or unavailable)"); + return error; + } + + // We will reach here when the stub gives an unsupported response to a + // hardware breakpoint + if (log) + log->Printf("Hardware breakpoints are unsupported"); - // Finally we will falling through to a #trap style breakpoint - } + // Finally we will falling through to a #trap style breakpoint + } - // Don't fall through when hardware breakpoints were specifically requested - if (bp_site->HardwareRequired()) - { - error.SetErrorString("hardware breakpoints are not supported"); - return error; - } + // Don't fall through when hardware breakpoints were specifically requested + if (bp_site->HardwareRequired()) { + error.SetErrorString("hardware breakpoints are not supported"); + return error; + } - // As a last resort we want to place a manual breakpoint. An instruction - // is placed into the process memory using memory write packets. - return EnableSoftwareBreakpoint(bp_site); + // As a last resort we want to place a manual breakpoint. An instruction + // is placed into the process memory using memory write packets. + return EnableSoftwareBreakpoint(bp_site); } -Error -ProcessGDBRemote::DisableBreakpointSite (BreakpointSite *bp_site) -{ - Error error; - assert (bp_site != NULL); - addr_t addr = bp_site->GetLoadAddress(); - user_id_t site_id = bp_site->GetID(); - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_BREAKPOINTS)); - if (log) - log->Printf ("ProcessGDBRemote::DisableBreakpointSite (site_id = %" PRIu64 ") addr = 0x%8.8" PRIx64, site_id, (uint64_t)addr); - - if (bp_site->IsEnabled()) - { - const size_t bp_op_size = GetSoftwareBreakpointTrapOpcode (bp_site); +Error ProcessGDBRemote::DisableBreakpointSite(BreakpointSite *bp_site) { + Error error; + assert(bp_site != NULL); + addr_t addr = bp_site->GetLoadAddress(); + user_id_t site_id = bp_site->GetID(); + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_BREAKPOINTS)); + if (log) + log->Printf("ProcessGDBRemote::DisableBreakpointSite (site_id = %" PRIu64 + ") addr = 0x%8.8" PRIx64, + site_id, (uint64_t)addr); + + if (bp_site->IsEnabled()) { + const size_t bp_op_size = GetSoftwareBreakpointTrapOpcode(bp_site); - BreakpointSite::Type bp_type = bp_site->GetType(); - switch (bp_type) - { - case BreakpointSite::eSoftware: - error = DisableSoftwareBreakpoint (bp_site); - break; + BreakpointSite::Type bp_type = bp_site->GetType(); + switch (bp_type) { + case BreakpointSite::eSoftware: + error = DisableSoftwareBreakpoint(bp_site); + break; - case BreakpointSite::eHardware: - if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointHardware, false, addr, bp_op_size)) - error.SetErrorToGenericError(); - break; + case BreakpointSite::eHardware: + if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointHardware, false, + addr, bp_op_size)) + error.SetErrorToGenericError(); + break; - case BreakpointSite::eExternal: - { - GDBStoppointType stoppoint_type; - if (bp_site->IsHardware()) - stoppoint_type = eBreakpointHardware; - else - stoppoint_type = eBreakpointSoftware; + case BreakpointSite::eExternal: { + GDBStoppointType stoppoint_type; + if (bp_site->IsHardware()) + stoppoint_type = eBreakpointHardware; + else + stoppoint_type = eBreakpointSoftware; - if (m_gdb_comm.SendGDBStoppointTypePacket(stoppoint_type, false, addr, bp_op_size)) - error.SetErrorToGenericError(); - } - break; - } - if (error.Success()) - bp_site->SetEnabled(false); - } - else - { - if (log) - log->Printf ("ProcessGDBRemote::DisableBreakpointSite (site_id = %" PRIu64 ") addr = 0x%8.8" PRIx64 " -- SUCCESS (already disabled)", site_id, (uint64_t)addr); - return error; + if (m_gdb_comm.SendGDBStoppointTypePacket(stoppoint_type, false, addr, + bp_op_size)) + error.SetErrorToGenericError(); + } break; } - if (error.Success()) - error.SetErrorToGenericError(); + bp_site->SetEnabled(false); + } else { + if (log) + log->Printf("ProcessGDBRemote::DisableBreakpointSite (site_id = %" PRIu64 + ") addr = 0x%8.8" PRIx64 " -- SUCCESS (already disabled)", + site_id, (uint64_t)addr); return error; + } + + if (error.Success()) + error.SetErrorToGenericError(); + return error; } // Pre-requisite: wp != NULL. -static GDBStoppointType -GetGDBStoppointType (Watchpoint *wp) -{ - assert(wp); - bool watch_read = wp->WatchpointRead(); - bool watch_write = wp->WatchpointWrite(); - - // watch_read and watch_write cannot both be false. - assert(watch_read || watch_write); - if (watch_read && watch_write) - return eWatchpointReadWrite; - else if (watch_read) - return eWatchpointRead; - else // Must be watch_write, then. - return eWatchpointWrite; +static GDBStoppointType GetGDBStoppointType(Watchpoint *wp) { + assert(wp); + bool watch_read = wp->WatchpointRead(); + bool watch_write = wp->WatchpointWrite(); + + // watch_read and watch_write cannot both be false. + assert(watch_read || watch_write); + if (watch_read && watch_write) + return eWatchpointReadWrite; + else if (watch_read) + return eWatchpointRead; + else // Must be watch_write, then. + return eWatchpointWrite; } -Error -ProcessGDBRemote::EnableWatchpoint (Watchpoint *wp, bool notify) -{ - Error error; - if (wp) - { - user_id_t watchID = wp->GetID(); - addr_t addr = wp->GetLoadAddress(); - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_WATCHPOINTS)); - if (log) - log->Printf ("ProcessGDBRemote::EnableWatchpoint(watchID = %" PRIu64 ")", watchID); - if (wp->IsEnabled()) - { - if (log) - log->Printf("ProcessGDBRemote::EnableWatchpoint(watchID = %" PRIu64 ") addr = 0x%8.8" PRIx64 ": watchpoint already enabled.", watchID, (uint64_t)addr); - return error; - } - - GDBStoppointType type = GetGDBStoppointType(wp); - // Pass down an appropriate z/Z packet... - if (m_gdb_comm.SupportsGDBStoppointPacket (type)) - { - if (m_gdb_comm.SendGDBStoppointTypePacket(type, true, addr, wp->GetByteSize()) == 0) - { - wp->SetEnabled(true, notify); - return error; - } - else - error.SetErrorString("sending gdb watchpoint packet failed"); - } - else - error.SetErrorString("watchpoints not supported"); - } - else - { - error.SetErrorString("Watchpoint argument was NULL."); - } - if (error.Success()) - error.SetErrorToGenericError(); - return error; +Error ProcessGDBRemote::EnableWatchpoint(Watchpoint *wp, bool notify) { + Error error; + if (wp) { + user_id_t watchID = wp->GetID(); + addr_t addr = wp->GetLoadAddress(); + Log *log( + ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_WATCHPOINTS)); + if (log) + log->Printf("ProcessGDBRemote::EnableWatchpoint(watchID = %" PRIu64 ")", + watchID); + if (wp->IsEnabled()) { + if (log) + log->Printf("ProcessGDBRemote::EnableWatchpoint(watchID = %" PRIu64 + ") addr = 0x%8.8" PRIx64 ": watchpoint already enabled.", + watchID, (uint64_t)addr); + return error; + } + + GDBStoppointType type = GetGDBStoppointType(wp); + // Pass down an appropriate z/Z packet... + if (m_gdb_comm.SupportsGDBStoppointPacket(type)) { + if (m_gdb_comm.SendGDBStoppointTypePacket(type, true, addr, + wp->GetByteSize()) == 0) { + wp->SetEnabled(true, notify); + return error; + } else + error.SetErrorString("sending gdb watchpoint packet failed"); + } else + error.SetErrorString("watchpoints not supported"); + } else { + error.SetErrorString("Watchpoint argument was NULL."); + } + if (error.Success()) + error.SetErrorToGenericError(); + return error; } -Error -ProcessGDBRemote::DisableWatchpoint (Watchpoint *wp, bool notify) -{ - Error error; - if (wp) - { - user_id_t watchID = wp->GetID(); - - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_WATCHPOINTS)); +Error ProcessGDBRemote::DisableWatchpoint(Watchpoint *wp, bool notify) { + Error error; + if (wp) { + user_id_t watchID = wp->GetID(); - addr_t addr = wp->GetLoadAddress(); + Log *log( + ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_WATCHPOINTS)); - if (log) - log->Printf ("ProcessGDBRemote::DisableWatchpoint (watchID = %" PRIu64 ") addr = 0x%8.8" PRIx64, watchID, (uint64_t)addr); - - if (!wp->IsEnabled()) - { - if (log) - log->Printf ("ProcessGDBRemote::DisableWatchpoint (watchID = %" PRIu64 ") addr = 0x%8.8" PRIx64 " -- SUCCESS (already disabled)", watchID, (uint64_t)addr); - // See also 'class WatchpointSentry' within StopInfo.cpp. - // This disabling attempt might come from the user-supplied actions, we'll route it in order for - // the watchpoint object to intelligently process this action. - wp->SetEnabled(false, notify); - return error; - } + addr_t addr = wp->GetLoadAddress(); - if (wp->IsHardware()) - { - GDBStoppointType type = GetGDBStoppointType(wp); - // Pass down an appropriate z/Z packet... - if (m_gdb_comm.SendGDBStoppointTypePacket(type, false, addr, wp->GetByteSize()) == 0) - { - wp->SetEnabled(false, notify); - return error; - } - else - error.SetErrorString("sending gdb watchpoint packet failed"); - } - // TODO: clear software watchpoints if we implement them - } - else - { - error.SetErrorString("Watchpoint argument was NULL."); - } - if (error.Success()) - error.SetErrorToGenericError(); - return error; + if (log) + log->Printf("ProcessGDBRemote::DisableWatchpoint (watchID = %" PRIu64 + ") addr = 0x%8.8" PRIx64, + watchID, (uint64_t)addr); + + if (!wp->IsEnabled()) { + if (log) + log->Printf("ProcessGDBRemote::DisableWatchpoint (watchID = %" PRIu64 + ") addr = 0x%8.8" PRIx64 " -- SUCCESS (already disabled)", + watchID, (uint64_t)addr); + // See also 'class WatchpointSentry' within StopInfo.cpp. + // This disabling attempt might come from the user-supplied actions, we'll + // route it in order for + // the watchpoint object to intelligently process this action. + wp->SetEnabled(false, notify); + return error; + } + + if (wp->IsHardware()) { + GDBStoppointType type = GetGDBStoppointType(wp); + // Pass down an appropriate z/Z packet... + if (m_gdb_comm.SendGDBStoppointTypePacket(type, false, addr, + wp->GetByteSize()) == 0) { + wp->SetEnabled(false, notify); + return error; + } else + error.SetErrorString("sending gdb watchpoint packet failed"); + } + // TODO: clear software watchpoints if we implement them + } else { + error.SetErrorString("Watchpoint argument was NULL."); + } + if (error.Success()) + error.SetErrorToGenericError(); + return error; } -void -ProcessGDBRemote::Clear() -{ - m_flags = 0; - m_thread_list_real.Clear(); - m_thread_list.Clear(); +void ProcessGDBRemote::Clear() { + m_flags = 0; + m_thread_list_real.Clear(); + m_thread_list.Clear(); } -Error -ProcessGDBRemote::DoSignal (int signo) -{ - Error error; - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); - if (log) - log->Printf ("ProcessGDBRemote::DoSignal (signal = %d)", signo); +Error ProcessGDBRemote::DoSignal(int signo) { + Error error; + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + if (log) + log->Printf("ProcessGDBRemote::DoSignal (signal = %d)", signo); - if (!m_gdb_comm.SendAsyncSignal (signo)) - error.SetErrorStringWithFormat("failed to send signal %i", signo); - return error; + if (!m_gdb_comm.SendAsyncSignal(signo)) + error.SetErrorStringWithFormat("failed to send signal %i", signo); + return error; } -Error -ProcessGDBRemote::EstablishConnectionIfNeeded (const ProcessInfo &process_info) -{ - // Make sure we aren't already connected? - if (m_gdb_comm.IsConnected()) - return Error(); - - PlatformSP platform_sp (GetTarget ().GetPlatform ()); - if (platform_sp && !platform_sp->IsHost ()) - return Error("Lost debug server connection"); +Error ProcessGDBRemote::EstablishConnectionIfNeeded( + const ProcessInfo &process_info) { + // Make sure we aren't already connected? + if (m_gdb_comm.IsConnected()) + return Error(); - auto error = LaunchAndConnectToDebugserver (process_info); - if (error.Fail()) - { - const char *error_string = error.AsCString(); - if (error_string == nullptr) - error_string = "unable to launch " DEBUGSERVER_BASENAME; - } - return error; + PlatformSP platform_sp(GetTarget().GetPlatform()); + if (platform_sp && !platform_sp->IsHost()) + return Error("Lost debug server connection"); + + auto error = LaunchAndConnectToDebugserver(process_info); + if (error.Fail()) { + const char *error_string = error.AsCString(); + if (error_string == nullptr) + error_string = "unable to launch " DEBUGSERVER_BASENAME; + } + return error; } +#if defined(__APPLE__) +#define USE_SOCKETPAIR_FOR_LOCAL_CONNECTION 1 +#endif -Error -ProcessGDBRemote::LaunchAndConnectToDebugserver (const ProcessInfo &process_info) -{ - using namespace std::placeholders; // For _1, _2, etc. - - Error error; - if (m_debugserver_pid == LLDB_INVALID_PROCESS_ID) - { - // If we locate debugserver, keep that located version around - static FileSpec g_debugserver_file_spec; - - ProcessLaunchInfo debugserver_launch_info; - // Make debugserver run in its own session so signals generated by - // special terminal key sequences (^C) don't affect debugserver. - debugserver_launch_info.SetLaunchInSeparateProcessGroup(true); - - const std::weak_ptr<ProcessGDBRemote> this_wp = std::static_pointer_cast<ProcessGDBRemote>(shared_from_this()); - debugserver_launch_info.SetMonitorProcessCallback(std::bind(MonitorDebugserverProcess, this_wp, _1, _2, _3, _4), - false); - debugserver_launch_info.SetUserID(process_info.GetUserID()); - -#if defined (__APPLE__) && (defined (__arm__) || defined (__arm64__) || defined (__aarch64__)) - // On iOS, still do a local connection using a random port - const char *hostname = "127.0.0.1"; - uint16_t port = get_random_port (); +#ifdef USE_SOCKETPAIR_FOR_LOCAL_CONNECTION +static bool SetCloexecFlag(int fd) { +#if defined(FD_CLOEXEC) + int flags = ::fcntl(fd, F_GETFD); + if (flags == -1) + return false; + return (::fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == 0); #else - // Set hostname being NULL to do the reverse connect where debugserver - // will bind to port zero and it will communicate back to us the port - // that we will connect to - const char *hostname = nullptr; - uint16_t port = 0; + return false; +#endif +} #endif - StreamString url_str; - const char* url = nullptr; - if (hostname != nullptr) - { - url_str.Printf("%s:%u", hostname, port); - url = url_str.GetData(); - } +Error ProcessGDBRemote::LaunchAndConnectToDebugserver( + const ProcessInfo &process_info) { + using namespace std::placeholders; // For _1, _2, etc. + + Error error; + if (m_debugserver_pid == LLDB_INVALID_PROCESS_ID) { + // If we locate debugserver, keep that located version around + static FileSpec g_debugserver_file_spec; + + ProcessLaunchInfo debugserver_launch_info; + // Make debugserver run in its own session so signals generated by + // special terminal key sequences (^C) don't affect debugserver. + debugserver_launch_info.SetLaunchInSeparateProcessGroup(true); + + const std::weak_ptr<ProcessGDBRemote> this_wp = + std::static_pointer_cast<ProcessGDBRemote>(shared_from_this()); + debugserver_launch_info.SetMonitorProcessCallback( + std::bind(MonitorDebugserverProcess, this_wp, _1, _2, _3, _4), false); + debugserver_launch_info.SetUserID(process_info.GetUserID()); + + int communication_fd = -1; +#ifdef USE_SOCKETPAIR_FOR_LOCAL_CONNECTION + // Auto close the sockets we might open up unless everything goes OK. This + // helps us not leak file descriptors when things go wrong. + lldb_utility::CleanUp<int, int> our_socket(-1, -1, close); + lldb_utility::CleanUp<int, int> gdb_socket(-1, -1, close); + + // Use a socketpair on Apple for now until other platforms can verify it + // works and is fast enough + { + int sockets[2]; /* the pair of socket descriptors */ + if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) == -1) { + error.SetErrorToErrno(); + return error; + } - error = m_gdb_comm.StartDebugserverProcess (url, - GetTarget().GetPlatform().get(), - debugserver_launch_info, - &port); + our_socket.set(sockets[0]); + gdb_socket.set(sockets[1]); + } - if (error.Success ()) - m_debugserver_pid = debugserver_launch_info.GetProcessID(); - else - m_debugserver_pid = LLDB_INVALID_PROCESS_ID; + // Don't let any child processes inherit our communication socket + SetCloexecFlag(our_socket.get()); + communication_fd = gdb_socket.get(); +#endif - if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID) - StartAsyncThread (); + error = m_gdb_comm.StartDebugserverProcess( + nullptr, GetTarget().GetPlatform().get(), debugserver_launch_info, + nullptr, nullptr, communication_fd); - if (error.Fail()) - { - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); + if (error.Success()) + m_debugserver_pid = debugserver_launch_info.GetProcessID(); + else + m_debugserver_pid = LLDB_INVALID_PROCESS_ID; + + if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID) { +#ifdef USE_SOCKETPAIR_FOR_LOCAL_CONNECTION + // Our process spawned correctly, we can now set our connection to use our + // end of the socket pair + m_gdb_comm.SetConnection( + new ConnectionFileDescriptor(our_socket.release(), true)); +#endif + StartAsyncThread(); + } - if (log) - log->Printf("failed to start debugserver process: %s", error.AsCString()); - return error; - } + if (error.Fail()) { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); - if (m_gdb_comm.IsConnected()) - { - // Finish the connection process by doing the handshake without connecting (send NULL URL) - ConnectToDebugserver (NULL); - } - else - { - StreamString connect_url; - connect_url.Printf("connect://%s:%u", hostname, port); - error = ConnectToDebugserver (connect_url.GetString().c_str()); - } + if (log) + log->Printf("failed to start debugserver process: %s", + error.AsCString()); + return error; + } + if (m_gdb_comm.IsConnected()) { + // Finish the connection process by doing the handshake without connecting + // (send NULL URL) + ConnectToDebugserver(""); + } else { + error.SetErrorString("connection failed"); } - return error; + } + return error; } -bool -ProcessGDBRemote::MonitorDebugserverProcess(std::weak_ptr<ProcessGDBRemote> process_wp, lldb::pid_t debugserver_pid, - 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)); - const bool handled = true; - - if (log) - log->Printf("ProcessGDBRemote::%s(process_wp, pid=%" PRIu64 ", signo=%i (0x%x), exit_status=%i)", __FUNCTION__, - debugserver_pid, signo, signo, exit_status); - - std::shared_ptr<ProcessGDBRemote> process_sp = process_wp.lock(); - if (log) - log->Printf("ProcessGDBRemote::%s(process = %p)", __FUNCTION__, static_cast<void *>(process_sp.get())); - if (!process_sp || process_sp->m_debugserver_pid != debugserver_pid) - return handled; - - // Sleep for a half a second to make sure our inferior process has - // time to set its exit status before we set it incorrectly when - // both the debugserver and the inferior process shut down. - usleep(500000); - // If our process hasn't yet exited, debugserver might have died. - // If the process did exit, then we are reaping it. - const StateType state = process_sp->GetState(); - - if (state != eStateInvalid && state != eStateUnloaded && state != eStateExited && state != eStateDetached) - { - char error_str[1024]; - if (signo) - { - const char *signal_cstr = process_sp->GetUnixSignals()->GetSignalAsCString(signo); - if (signal_cstr) - ::snprintf(error_str, sizeof(error_str), DEBUGSERVER_BASENAME " died with signal %s", signal_cstr); - else - ::snprintf(error_str, sizeof(error_str), DEBUGSERVER_BASENAME " died with signal %i", signo); - } - else - { - ::snprintf(error_str, sizeof(error_str), DEBUGSERVER_BASENAME " died with an exit status of 0x%8.8x", - exit_status); - } +bool ProcessGDBRemote::MonitorDebugserverProcess( + std::weak_ptr<ProcessGDBRemote> process_wp, lldb::pid_t debugserver_pid, + 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)); + const bool handled = true; + + if (log) + log->Printf("ProcessGDBRemote::%s(process_wp, pid=%" PRIu64 + ", signo=%i (0x%x), exit_status=%i)", + __FUNCTION__, debugserver_pid, signo, signo, exit_status); + + std::shared_ptr<ProcessGDBRemote> process_sp = process_wp.lock(); + if (log) + log->Printf("ProcessGDBRemote::%s(process = %p)", __FUNCTION__, + static_cast<void *>(process_sp.get())); + if (!process_sp || process_sp->m_debugserver_pid != debugserver_pid) + return handled; - process_sp->SetExitStatus(-1, error_str); + // Sleep for a half a second to make sure our inferior process has + // time to set its exit status before we set it incorrectly when + // both the debugserver and the inferior process shut down. + usleep(500000); + // If our process hasn't yet exited, debugserver might have died. + // If the process did exit, then we are reaping it. + const StateType state = process_sp->GetState(); + + if (state != eStateInvalid && state != eStateUnloaded && + state != eStateExited && state != eStateDetached) { + char error_str[1024]; + if (signo) { + const char *signal_cstr = + process_sp->GetUnixSignals()->GetSignalAsCString(signo); + if (signal_cstr) + ::snprintf(error_str, sizeof(error_str), + DEBUGSERVER_BASENAME " died with signal %s", signal_cstr); + else + ::snprintf(error_str, sizeof(error_str), + DEBUGSERVER_BASENAME " died with signal %i", signo); + } else { + ::snprintf(error_str, sizeof(error_str), + DEBUGSERVER_BASENAME " died with an exit status of 0x%8.8x", + exit_status); } - // Debugserver has exited we need to let our ProcessGDBRemote - // know that it no longer has a debugserver instance - process_sp->m_debugserver_pid = LLDB_INVALID_PROCESS_ID; - return handled; + + process_sp->SetExitStatus(-1, error_str); + } + // Debugserver has exited we need to let our ProcessGDBRemote + // know that it no longer has a debugserver instance + process_sp->m_debugserver_pid = LLDB_INVALID_PROCESS_ID; + return handled; } -void -ProcessGDBRemote::KillDebugserverProcess () -{ - m_gdb_comm.Disconnect(); - if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID) - { - Host::Kill (m_debugserver_pid, SIGINT); - m_debugserver_pid = LLDB_INVALID_PROCESS_ID; - } +void ProcessGDBRemote::KillDebugserverProcess() { + m_gdb_comm.Disconnect(); + if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID) { + Host::Kill(m_debugserver_pid, SIGINT); + m_debugserver_pid = LLDB_INVALID_PROCESS_ID; + } } -void -ProcessGDBRemote::Initialize() -{ - static std::once_flag g_once_flag; +void ProcessGDBRemote::Initialize() { + static std::once_flag g_once_flag; - std::call_once(g_once_flag, []() - { - PluginManager::RegisterPlugin (GetPluginNameStatic(), - GetPluginDescriptionStatic(), - CreateInstance, - DebuggerInitialize); - }); + std::call_once(g_once_flag, []() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance, + DebuggerInitialize); + }); } -void -ProcessGDBRemote::DebuggerInitialize (Debugger &debugger) -{ - if (!PluginManager::GetSettingForProcessPlugin(debugger, PluginProperties::GetSettingName())) - { - const bool is_global_setting = true; - PluginManager::CreateSettingForProcessPlugin (debugger, - GetGlobalPluginProperties()->GetValueProperties(), - ConstString ("Properties for the gdb-remote process plug-in."), - is_global_setting); - } +void ProcessGDBRemote::DebuggerInitialize(Debugger &debugger) { + if (!PluginManager::GetSettingForProcessPlugin( + debugger, PluginProperties::GetSettingName())) { + const bool is_global_setting = true; + PluginManager::CreateSettingForProcessPlugin( + debugger, GetGlobalPluginProperties()->GetValueProperties(), + ConstString("Properties for the gdb-remote process plug-in."), + is_global_setting); + } } -bool -ProcessGDBRemote::StartAsyncThread () -{ - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); +bool ProcessGDBRemote::StartAsyncThread() { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); - if (log) - log->Printf ("ProcessGDBRemote::%s ()", __FUNCTION__); + if (log) + log->Printf("ProcessGDBRemote::%s ()", __FUNCTION__); - 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). + 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.process.gdb-remote.async>", ProcessGDBRemote::AsyncThread, this, NULL); - } - else if (log) - log->Printf("ProcessGDBRemote::%s () - Called when Async thread was already running.", __FUNCTION__); + m_async_thread = + ThreadLauncher::LaunchThread("<lldb.process.gdb-remote.async>", + ProcessGDBRemote::AsyncThread, this, NULL); + } else if (log) + log->Printf("ProcessGDBRemote::%s () - Called when Async thread was " + "already running.", + __FUNCTION__); - return m_async_thread.IsJoinable(); + return m_async_thread.IsJoinable(); } -void -ProcessGDBRemote::StopAsyncThread () -{ - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); +void ProcessGDBRemote::StopAsyncThread() { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); - if (log) - log->Printf ("ProcessGDBRemote::%s ()", __FUNCTION__); + if (log) + log->Printf("ProcessGDBRemote::%s ()", __FUNCTION__); - std::lock_guard<std::recursive_mutex> guard(m_async_thread_state_mutex); - if (m_async_thread.IsJoinable()) - { - m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncThreadShouldExit); + std::lock_guard<std::recursive_mutex> guard(m_async_thread_state_mutex); + if (m_async_thread.IsJoinable()) { + m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncThreadShouldExit); - // This will shut down the async thread. - m_gdb_comm.Disconnect(); // Disconnect from the debug server. + // This will shut down the async thread. + m_gdb_comm.Disconnect(); // Disconnect from the debug server. - // Stop the stdio thread - m_async_thread.Join(nullptr); - m_async_thread.Reset(); - } - else if (log) - log->Printf("ProcessGDBRemote::%s () - Called when Async thread was not running.", __FUNCTION__); + // Stop the stdio thread + m_async_thread.Join(nullptr); + m_async_thread.Reset(); + } else if (log) + log->Printf( + "ProcessGDBRemote::%s () - Called when Async thread was not running.", + __FUNCTION__); } -bool -ProcessGDBRemote::HandleNotifyPacket (StringExtractorGDBRemote &packet) -{ - // get the packet at a string - const std::string &pkt = packet.GetStringRef(); - // skip %stop: - StringExtractorGDBRemote stop_info(pkt.c_str() + 5); - - // pass as a thread stop info packet - SetLastStopPacket(stop_info); - - // check for more stop reasons - HandleStopReplySequence(); - - // if the process is stopped then we need to fake a resume - // so that we can stop properly with the new break. This - // is possible due to SetPrivateState() broadcasting the - // state change as a side effect. - if (GetPrivateState() == lldb::StateType::eStateStopped) - { - SetPrivateState(lldb::StateType::eStateRunning); - } +bool ProcessGDBRemote::HandleNotifyPacket(StringExtractorGDBRemote &packet) { + // get the packet at a string + const std::string &pkt = packet.GetStringRef(); + // skip %stop: + StringExtractorGDBRemote stop_info(pkt.c_str() + 5); - // since we have some stopped packets we can halt the process - SetPrivateState(lldb::StateType::eStateStopped); + // pass as a thread stop info packet + SetLastStopPacket(stop_info); - return true; + // check for more stop reasons + HandleStopReplySequence(); + + // if the process is stopped then we need to fake a resume + // so that we can stop properly with the new break. This + // is possible due to SetPrivateState() broadcasting the + // state change as a side effect. + if (GetPrivateState() == lldb::StateType::eStateStopped) { + SetPrivateState(lldb::StateType::eStateRunning); + } + + // since we have some stopped packets we can halt the process + SetPrivateState(lldb::StateType::eStateStopped); + + return true; } -thread_result_t -ProcessGDBRemote::AsyncThread (void *arg) -{ - ProcessGDBRemote *process = (ProcessGDBRemote*) arg; +thread_result_t ProcessGDBRemote::AsyncThread(void *arg) { + ProcessGDBRemote *process = (ProcessGDBRemote *)arg; - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); - if (log) - log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") thread starting...", __FUNCTION__, arg, process->GetID()); + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + if (log) + log->Printf("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 + ") thread starting...", + __FUNCTION__, arg, process->GetID()); - EventSP event_sp; - bool done = false; - while (!done) - { + EventSP event_sp; + bool done = false; + while (!done) { + if (log) + log->Printf("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 + ") listener.WaitForEvent (NULL, event_sp)...", + __FUNCTION__, arg, process->GetID()); + if (process->m_async_listener_sp->GetEvent(event_sp, llvm::None)) { + const uint32_t event_type = event_sp->GetType(); + if (event_sp->BroadcasterIs(&process->m_async_broadcaster)) { if (log) - log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") listener.WaitForEvent (NULL, event_sp)...", __FUNCTION__, arg, process->GetID()); - if (process->m_async_listener_sp->WaitForEvent (NULL, event_sp)) - { - const uint32_t event_type = event_sp->GetType(); - if (event_sp->BroadcasterIs (&process->m_async_broadcaster)) - { - if (log) - log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") Got an event of type: %d...", __FUNCTION__, arg, process->GetID(), event_type); - - switch (event_type) - { - case eBroadcastBitAsyncContinue: - { - const EventDataBytes *continue_packet = EventDataBytes::GetEventDataFromEvent(event_sp.get()); - - if (continue_packet) - { - const char *continue_cstr = (const char *)continue_packet->GetBytes (); - const size_t continue_cstr_len = continue_packet->GetByteSize (); - if (log) - log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") got eBroadcastBitAsyncContinue: %s", __FUNCTION__, arg, process->GetID(), continue_cstr); - - if (::strstr (continue_cstr, "vAttach") == NULL) - process->SetPrivateState(eStateRunning); - StringExtractorGDBRemote response; - - // If in Non-Stop-Mode - if (process->GetTarget().GetNonStopModeEnabled()) - { - // send the vCont packet - if (!process->GetGDBRemote().SendvContPacket(process, continue_cstr, continue_cstr_len, response)) - { - // Something went wrong - done = true; - break; - } - } - // If in All-Stop-Mode - else - { - StateType stop_state = process->GetGDBRemote().SendContinuePacketAndWaitForResponse (process, continue_cstr, continue_cstr_len, response); - - // We need to immediately clear the thread ID list so we are sure to get a valid list of threads. - // The thread ID list might be contained within the "response", or the stop reply packet that - // caused the stop. So clear it now before we give the stop reply packet to the process - // using the process->SetLastStopPacket()... - process->ClearThreadIDList (); - - switch (stop_state) - { - case eStateStopped: - case eStateCrashed: - case eStateSuspended: - process->SetLastStopPacket (response); - process->SetPrivateState (stop_state); - break; - - case eStateExited: - { - process->SetLastStopPacket (response); - process->ClearThreadIDList(); - response.SetFilePos(1); - - int exit_status = response.GetHexU8(); - const char *desc_cstr = NULL; - StringExtractor extractor; - std::string desc_string; - if (response.GetBytesLeft() > 0 && response.GetChar('-') == ';') - { - std::string desc_token; - while (response.GetNameColonValue (desc_token, desc_string)) - { - if (desc_token == "description") - { - extractor.GetStringRef().swap(desc_string); - extractor.SetFilePos(0); - extractor.GetHexByteString (desc_string); - desc_cstr = desc_string.c_str(); - } - } - } - process->SetExitStatus(exit_status, desc_cstr); - done = true; - break; - } - case eStateInvalid: - { - // Check to see if we were trying to attach and if we got back - // the "E87" error code from debugserver -- this indicates that - // the process is not debuggable. Return a slightly more helpful - // error message about why the attach failed. - if (::strstr (continue_cstr, "vAttach") != NULL - && response.GetError() == 0x87) - { - process->SetExitStatus(-1, "cannot attach to process due to System Integrity Protection"); - } - // E01 code from vAttach means that the attach failed - if (::strstr (continue_cstr, "vAttach") != NULL - && response.GetError() == 0x1) - { - process->SetExitStatus(-1, "unable to attach"); - } - else - { - process->SetExitStatus(-1, "lost connection"); - } - break; - } - - default: - process->SetPrivateState (stop_state); - break; - } // switch(stop_state) - } // else // if in All-stop-mode - } // if (continue_packet) - } // case eBroadcastBitAysncContinue - break; - - case eBroadcastBitAsyncThreadShouldExit: - if (log) - log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") got eBroadcastBitAsyncThreadShouldExit...", __FUNCTION__, arg, process->GetID()); - done = true; - break; - - default: - if (log) - log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") got unknown event 0x%8.8x", __FUNCTION__, arg, process->GetID(), event_type); - done = true; - break; - } + log->Printf("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 + ") Got an event of type: %d...", + __FUNCTION__, arg, process->GetID(), event_type); + + switch (event_type) { + case eBroadcastBitAsyncContinue: { + const EventDataBytes *continue_packet = + EventDataBytes::GetEventDataFromEvent(event_sp.get()); + + if (continue_packet) { + const char *continue_cstr = + (const char *)continue_packet->GetBytes(); + const size_t continue_cstr_len = continue_packet->GetByteSize(); + if (log) + log->Printf("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 + ") got eBroadcastBitAsyncContinue: %s", + __FUNCTION__, arg, process->GetID(), continue_cstr); + + if (::strstr(continue_cstr, "vAttach") == NULL) + process->SetPrivateState(eStateRunning); + StringExtractorGDBRemote response; + + // If in Non-Stop-Mode + if (process->GetTarget().GetNonStopModeEnabled()) { + // send the vCont packet + if (!process->GetGDBRemote().SendvContPacket( + llvm::StringRef(continue_cstr, continue_cstr_len), + response)) { + // Something went wrong + done = true; + break; + } } - else if (event_sp->BroadcasterIs (&process->m_gdb_comm)) - { - switch (event_type) - { - case Communication::eBroadcastBitReadThreadDidExit: - process->SetExitStatus (-1, "lost connection"); - done = true; - break; - - case GDBRemoteCommunication::eBroadcastBitGdbReadThreadGotNotify: - { - lldb_private::Event *event = event_sp.get(); - const EventDataBytes *continue_packet = EventDataBytes::GetEventDataFromEvent(event); - StringExtractorGDBRemote notify((const char*)continue_packet->GetBytes()); - // Hand this over to the process to handle - process->HandleNotifyPacket(notify); - break; - } - - default: - if (log) - log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") got unknown event 0x%8.8x", __FUNCTION__, arg, process->GetID(), event_type); - done = true; - break; + // If in All-Stop-Mode + else { + StateType stop_state = + process->GetGDBRemote().SendContinuePacketAndWaitForResponse( + *process, *process->GetUnixSignals(), + llvm::StringRef(continue_cstr, continue_cstr_len), + response); + + // We need to immediately clear the thread ID list so we are sure + // to get a valid list of threads. + // The thread ID list might be contained within the "response", or + // the stop reply packet that + // caused the stop. So clear it now before we give the stop reply + // packet to the process + // using the process->SetLastStopPacket()... + process->ClearThreadIDList(); + + switch (stop_state) { + case eStateStopped: + case eStateCrashed: + case eStateSuspended: + process->SetLastStopPacket(response); + process->SetPrivateState(stop_state); + break; + + case eStateExited: { + process->SetLastStopPacket(response); + process->ClearThreadIDList(); + response.SetFilePos(1); + + int exit_status = response.GetHexU8(); + std::string desc_string; + if (response.GetBytesLeft() > 0 && + response.GetChar('-') == ';') { + llvm::StringRef desc_str; + llvm::StringRef desc_token; + while (response.GetNameColonValue(desc_token, desc_str)) { + if (desc_token != "description") + continue; + StringExtractor extractor(desc_str); + extractor.GetHexByteString(desc_string); + } } - } + process->SetExitStatus(exit_status, desc_string.c_str()); + done = true; + break; + } + case eStateInvalid: { + // Check to see if we were trying to attach and if we got back + // the "E87" error code from debugserver -- this indicates that + // the process is not debuggable. Return a slightly more + // helpful + // error message about why the attach failed. + if (::strstr(continue_cstr, "vAttach") != NULL && + response.GetError() == 0x87) { + process->SetExitStatus(-1, "cannot attach to process due to " + "System Integrity Protection"); + } + // E01 code from vAttach means that the attach failed + if (::strstr(continue_cstr, "vAttach") != NULL && + response.GetError() == 0x1) { + process->SetExitStatus(-1, "unable to attach"); + } else { + process->SetExitStatus(-1, "lost connection"); + } + break; + } + + default: + process->SetPrivateState(stop_state); + break; + } // switch(stop_state) + } // else // if in All-stop-mode + } // if (continue_packet) + } // case eBroadcastBitAysncContinue + break; + + case eBroadcastBitAsyncThreadShouldExit: + if (log) + log->Printf("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 + ") got eBroadcastBitAsyncThreadShouldExit...", + __FUNCTION__, arg, process->GetID()); + done = true; + break; + + default: + if (log) + log->Printf("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 + ") got unknown event 0x%8.8x", + __FUNCTION__, arg, process->GetID(), event_type); + done = true; + break; } - else - { - if (log) - log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") listener.WaitForEvent (NULL, event_sp) => false", __FUNCTION__, arg, process->GetID()); - done = true; + } else if (event_sp->BroadcasterIs(&process->m_gdb_comm)) { + switch (event_type) { + case Communication::eBroadcastBitReadThreadDidExit: + process->SetExitStatus(-1, "lost connection"); + done = true; + break; + + case GDBRemoteCommunication::eBroadcastBitGdbReadThreadGotNotify: { + lldb_private::Event *event = event_sp.get(); + const EventDataBytes *continue_packet = + EventDataBytes::GetEventDataFromEvent(event); + StringExtractorGDBRemote notify( + (const char *)continue_packet->GetBytes()); + // Hand this over to the process to handle + process->HandleNotifyPacket(notify); + break; + } + + default: + if (log) + log->Printf("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 + ") got unknown event 0x%8.8x", + __FUNCTION__, arg, process->GetID(), event_type); + done = true; + break; } + } + } else { + if (log) + log->Printf("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 + ") listener.WaitForEvent (NULL, event_sp) => false", + __FUNCTION__, arg, process->GetID()); + done = true; } + } - if (log) - log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") thread exiting...", __FUNCTION__, arg, process->GetID()); + if (log) + log->Printf("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 + ") thread exiting...", + __FUNCTION__, arg, process->GetID()); - return NULL; + return NULL; } -//uint32_t -//ProcessGDBRemote::ListProcessesMatchingName (const char *name, StringList &matches, std::vector<lldb::pid_t> &pids) +// uint32_t +// ProcessGDBRemote::ListProcessesMatchingName (const char *name, StringList +// &matches, std::vector<lldb::pid_t> &pids) //{ -// // If we are planning to launch the debugserver remotely, then we need to fire up a debugserver -// // process and ask it for the list of processes. But if we are local, we can let the Host do it. +// // If we are planning to launch the debugserver remotely, then we need to +// fire up a debugserver +// // process and ask it for the list of processes. But if we are local, we +// can let the Host do it. // if (m_local_debugserver) // { // return Host::ListProcessesMatchingName (name, matches, pids); @@ -4070,189 +3729,240 @@ ProcessGDBRemote::AsyncThread (void *arg) // //} // -bool -ProcessGDBRemote::NewThreadNotifyBreakpointHit (void *baton, - StoppointCallbackContext *context, - lldb::user_id_t break_id, - lldb::user_id_t break_loc_id) -{ - // I don't think I have to do anything here, just make sure I notice the new thread when it starts to - // run so I can stop it if that's what I want to do. - Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - if (log) - log->Printf("Hit New Thread Notification breakpoint."); - return false; +bool ProcessGDBRemote::NewThreadNotifyBreakpointHit( + void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id, + lldb::user_id_t break_loc_id) { + // I don't think I have to do anything here, just make sure I notice the new + // thread when it starts to + // run so I can stop it if that's what I want to do. + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + if (log) + log->Printf("Hit New Thread Notification breakpoint."); + return false; } - -bool -ProcessGDBRemote::StartNoticingNewThreads() -{ - Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - if (m_thread_create_bp_sp) - { +bool ProcessGDBRemote::StartNoticingNewThreads() { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + if (m_thread_create_bp_sp) { + if (log && log->GetVerbose()) + log->Printf("Enabled noticing new thread breakpoint."); + m_thread_create_bp_sp->SetEnabled(true); + } else { + PlatformSP platform_sp(GetTarget().GetPlatform()); + if (platform_sp) { + m_thread_create_bp_sp = + platform_sp->SetThreadCreationBreakpoint(GetTarget()); + if (m_thread_create_bp_sp) { if (log && log->GetVerbose()) - log->Printf("Enabled noticing new thread breakpoint."); - m_thread_create_bp_sp->SetEnabled(true); - } - else - { - PlatformSP platform_sp (GetTarget().GetPlatform()); - if (platform_sp) - { - m_thread_create_bp_sp = platform_sp->SetThreadCreationBreakpoint(GetTarget()); - if (m_thread_create_bp_sp) - { - if (log && log->GetVerbose()) - log->Printf("Successfully created new thread notification breakpoint %i", m_thread_create_bp_sp->GetID()); - m_thread_create_bp_sp->SetCallback (ProcessGDBRemote::NewThreadNotifyBreakpointHit, this, true); - } - else - { - if (log) - log->Printf("Failed to create new thread notification breakpoint."); - } - } + log->Printf( + "Successfully created new thread notification breakpoint %i", + m_thread_create_bp_sp->GetID()); + m_thread_create_bp_sp->SetCallback( + ProcessGDBRemote::NewThreadNotifyBreakpointHit, this, true); + } else { + if (log) + log->Printf("Failed to create new thread notification breakpoint."); + } } - return m_thread_create_bp_sp.get() != NULL; + } + return m_thread_create_bp_sp.get() != NULL; } -bool -ProcessGDBRemote::StopNoticingNewThreads() -{ - Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - if (log && log->GetVerbose()) - log->Printf ("Disabling new thread notification breakpoint."); +bool ProcessGDBRemote::StopNoticingNewThreads() { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + if (log && log->GetVerbose()) + log->Printf("Disabling new thread notification breakpoint."); - if (m_thread_create_bp_sp) - m_thread_create_bp_sp->SetEnabled(false); + if (m_thread_create_bp_sp) + m_thread_create_bp_sp->SetEnabled(false); - return true; + return true; } -DynamicLoader * -ProcessGDBRemote::GetDynamicLoader () -{ - if (m_dyld_ap.get() == NULL) - m_dyld_ap.reset (DynamicLoader::FindPlugin(this, NULL)); - return m_dyld_ap.get(); +DynamicLoader *ProcessGDBRemote::GetDynamicLoader() { + if (m_dyld_ap.get() == NULL) + m_dyld_ap.reset(DynamicLoader::FindPlugin(this, NULL)); + return m_dyld_ap.get(); } -Error -ProcessGDBRemote::SendEventData(const char *data) -{ - int return_value; - bool was_supported; +Error ProcessGDBRemote::SendEventData(const char *data) { + int return_value; + bool was_supported; - Error error; + Error error; - return_value = m_gdb_comm.SendLaunchEventDataPacket (data, &was_supported); - if (return_value != 0) - { - if (!was_supported) - error.SetErrorString("Sending events is not supported for this process."); - else - error.SetErrorStringWithFormat("Error sending event data: %d.", return_value); - } - return error; + return_value = m_gdb_comm.SendLaunchEventDataPacket(data, &was_supported); + if (return_value != 0) { + if (!was_supported) + error.SetErrorString("Sending events is not supported for this process."); + else + error.SetErrorStringWithFormat("Error sending event data: %d.", + return_value); + } + return error; } -const DataBufferSP -ProcessGDBRemote::GetAuxvData() -{ - DataBufferSP buf; - if (m_gdb_comm.GetQXferAuxvReadSupported()) - { - std::string response_string; - if (m_gdb_comm.SendPacketsAndConcatenateResponses("qXfer:auxv:read::", response_string) == GDBRemoteCommunication::PacketResult::Success) - buf.reset(new DataBufferHeap(response_string.c_str(), response_string.length())); - } - return buf; +const DataBufferSP ProcessGDBRemote::GetAuxvData() { + DataBufferSP buf; + if (m_gdb_comm.GetQXferAuxvReadSupported()) { + std::string response_string; + if (m_gdb_comm.SendPacketsAndConcatenateResponses("qXfer:auxv:read::", + response_string) == + GDBRemoteCommunication::PacketResult::Success) + buf.reset(new DataBufferHeap(response_string.c_str(), + response_string.length())); + } + return buf; } StructuredData::ObjectSP -ProcessGDBRemote::GetExtendedInfoForThread (lldb::tid_t tid) -{ - StructuredData::ObjectSP object_sp; +ProcessGDBRemote::GetExtendedInfoForThread(lldb::tid_t tid) { + StructuredData::ObjectSP object_sp; - if (m_gdb_comm.GetThreadExtendedInfoSupported()) - { - StructuredData::ObjectSP args_dict(new StructuredData::Dictionary()); - SystemRuntime *runtime = GetSystemRuntime(); - if (runtime) - { - runtime->AddThreadExtendedInfoPacketHints (args_dict); - } - args_dict->GetAsDictionary()->AddIntegerItem ("thread", tid); + if (m_gdb_comm.GetThreadExtendedInfoSupported()) { + StructuredData::ObjectSP args_dict(new StructuredData::Dictionary()); + SystemRuntime *runtime = GetSystemRuntime(); + if (runtime) { + runtime->AddThreadExtendedInfoPacketHints(args_dict); + } + args_dict->GetAsDictionary()->AddIntegerItem("thread", tid); - StreamString packet; - packet << "jThreadExtendedInfo:"; - args_dict->Dump (packet); + StreamString packet; + packet << "jThreadExtendedInfo:"; + args_dict->Dump(packet, false); - // FIXME the final character of a JSON dictionary, '}', is the escape - // character in gdb-remote binary mode. lldb currently doesn't escape - // these characters in its packet output -- so we add the quoted version - // of the } character here manually in case we talk to a debugserver which - // un-escapes the characters at packet read time. - packet << (char) (0x7d ^ 0x20); + // FIXME the final character of a JSON dictionary, '}', is the escape + // character in gdb-remote binary mode. lldb currently doesn't escape + // these characters in its packet output -- so we add the quoted version + // of the } character here manually in case we talk to a debugserver which + // un-escapes the characters at packet read time. + packet << (char)(0x7d ^ 0x20); - StringExtractorGDBRemote response; - response.SetResponseValidatorToJSON(); - if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetData(), packet.GetSize(), response, false) == GDBRemoteCommunication::PacketResult::Success) - { - StringExtractorGDBRemote::ResponseType response_type = response.GetResponseType(); - if (response_type == StringExtractorGDBRemote::eResponse) - { - if (!response.Empty()) - { - object_sp = StructuredData::ParseJSON (response.GetStringRef()); - } - } + StringExtractorGDBRemote response; + response.SetResponseValidatorToJSON(); + if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response, + false) == + GDBRemoteCommunication::PacketResult::Success) { + StringExtractorGDBRemote::ResponseType response_type = + response.GetResponseType(); + if (response_type == StringExtractorGDBRemote::eResponse) { + if (!response.Empty()) { + object_sp = StructuredData::ParseJSON(response.GetStringRef()); } + } } - return object_sp; + } + return object_sp; +} + +StructuredData::ObjectSP ProcessGDBRemote::GetLoadedDynamicLibrariesInfos( + lldb::addr_t image_list_address, lldb::addr_t image_count) { + + StructuredData::ObjectSP args_dict(new StructuredData::Dictionary()); + args_dict->GetAsDictionary()->AddIntegerItem("image_list_address", + image_list_address); + args_dict->GetAsDictionary()->AddIntegerItem("image_count", image_count); + + return GetLoadedDynamicLibrariesInfos_sender(args_dict); +} + +StructuredData::ObjectSP ProcessGDBRemote::GetLoadedDynamicLibrariesInfos() { + StructuredData::ObjectSP args_dict(new StructuredData::Dictionary()); + + args_dict->GetAsDictionary()->AddBooleanItem("fetch_all_solibs", true); + + return GetLoadedDynamicLibrariesInfos_sender(args_dict); +} + +StructuredData::ObjectSP ProcessGDBRemote::GetLoadedDynamicLibrariesInfos( + const std::vector<lldb::addr_t> &load_addresses) { + StructuredData::ObjectSP args_dict(new StructuredData::Dictionary()); + StructuredData::ArraySP addresses(new StructuredData::Array); + + for (auto addr : load_addresses) { + StructuredData::ObjectSP addr_sp(new StructuredData::Integer(addr)); + addresses->AddItem(addr_sp); + } + + args_dict->GetAsDictionary()->AddItem("solib_addresses", addresses); + + return GetLoadedDynamicLibrariesInfos_sender(args_dict); } StructuredData::ObjectSP -ProcessGDBRemote::GetLoadedDynamicLibrariesInfos (lldb::addr_t image_list_address, lldb::addr_t image_count) -{ - StructuredData::ObjectSP object_sp; +ProcessGDBRemote::GetLoadedDynamicLibrariesInfos_sender( + StructuredData::ObjectSP args_dict) { + StructuredData::ObjectSP object_sp; - if (m_gdb_comm.GetLoadedDynamicLibrariesInfosSupported()) - { - // Scope for the scoped timeout object - GDBRemoteCommunication::ScopedTimeout timeout (m_gdb_comm, 10); + if (m_gdb_comm.GetLoadedDynamicLibrariesInfosSupported()) { + // Scope for the scoped timeout object + GDBRemoteCommunication::ScopedTimeout timeout(m_gdb_comm, + std::chrono::seconds(10)); - StructuredData::ObjectSP args_dict(new StructuredData::Dictionary()); - args_dict->GetAsDictionary()->AddIntegerItem ("image_list_address", image_list_address); - args_dict->GetAsDictionary()->AddIntegerItem ("image_count", image_count); + StreamString packet; + packet << "jGetLoadedDynamicLibrariesInfos:"; + args_dict->Dump(packet, false); - StreamString packet; - packet << "jGetLoadedDynamicLibrariesInfos:"; - args_dict->Dump (packet); + // FIXME the final character of a JSON dictionary, '}', is the escape + // character in gdb-remote binary mode. lldb currently doesn't escape + // these characters in its packet output -- so we add the quoted version + // of the } character here manually in case we talk to a debugserver which + // un-escapes the characters at packet read time. + packet << (char)(0x7d ^ 0x20); - // FIXME the final character of a JSON dictionary, '}', is the escape - // character in gdb-remote binary mode. lldb currently doesn't escape - // these characters in its packet output -- so we add the quoted version - // of the } character here manually in case we talk to a debugserver which - // un-escapes the characters at packet read time. - packet << (char) (0x7d ^ 0x20); + StringExtractorGDBRemote response; + response.SetResponseValidatorToJSON(); + if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response, + false) == + GDBRemoteCommunication::PacketResult::Success) { + StringExtractorGDBRemote::ResponseType response_type = + response.GetResponseType(); + if (response_type == StringExtractorGDBRemote::eResponse) { + if (!response.Empty()) { + object_sp = StructuredData::ParseJSON(response.GetStringRef()); + } + } + } + } + return object_sp; +} - StringExtractorGDBRemote response; - response.SetResponseValidatorToJSON(); - if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetData(), packet.GetSize(), response, false) == GDBRemoteCommunication::PacketResult::Success) - { - StringExtractorGDBRemote::ResponseType response_type = response.GetResponseType(); - if (response_type == StringExtractorGDBRemote::eResponse) - { - if (!response.Empty()) - { - object_sp = StructuredData::ParseJSON (response.GetStringRef()); - } - } +StructuredData::ObjectSP ProcessGDBRemote::GetSharedCacheInfo() { + StructuredData::ObjectSP object_sp; + StructuredData::ObjectSP args_dict(new StructuredData::Dictionary()); + + if (m_gdb_comm.GetSharedCacheInfoSupported()) { + StreamString packet; + packet << "jGetSharedCacheInfo:"; + args_dict->Dump(packet, false); + + // FIXME the final character of a JSON dictionary, '}', is the escape + // character in gdb-remote binary mode. lldb currently doesn't escape + // these characters in its packet output -- so we add the quoted version + // of the } character here manually in case we talk to a debugserver which + // un-escapes the characters at packet read time. + packet << (char)(0x7d ^ 0x20); + + StringExtractorGDBRemote response; + response.SetResponseValidatorToJSON(); + if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response, + false) == + GDBRemoteCommunication::PacketResult::Success) { + StringExtractorGDBRemote::ResponseType response_type = + response.GetResponseType(); + if (response_type == StringExtractorGDBRemote::eResponse) { + if (!response.Empty()) { + object_sp = StructuredData::ParseJSON(response.GetStringRef()); } + } } - return object_sp; + } + return object_sp; +} + +Error ProcessGDBRemote::ConfigureStructuredData( + const ConstString &type_name, const StructuredData::ObjectSP &config_sp) { + return m_gdb_comm.ConfigureRemoteStructuredData(type_name, config_sp); } // Establish the largest memory read/write payloads we should use. @@ -4264,100 +3974,103 @@ ProcessGDBRemote::GetLoadedDynamicLibrariesInfos (lldb::addr_t image_list_addres // If the remote stub doesn't advertise a max packet size, use a // conservative default. -void -ProcessGDBRemote::GetMaxMemorySize() -{ - const uint64_t reasonable_largeish_default = 128 * 1024; - const uint64_t conservative_default = 512; +void ProcessGDBRemote::GetMaxMemorySize() { + const uint64_t reasonable_largeish_default = 128 * 1024; + const uint64_t conservative_default = 512; - if (m_max_memory_size == 0) - { - uint64_t stub_max_size = m_gdb_comm.GetRemoteMaxPacketSize(); - if (stub_max_size != UINT64_MAX && stub_max_size != 0) - { - // Save the stub's claimed maximum packet size - m_remote_stub_max_memory_size = stub_max_size; + if (m_max_memory_size == 0) { + uint64_t stub_max_size = m_gdb_comm.GetRemoteMaxPacketSize(); + if (stub_max_size != UINT64_MAX && stub_max_size != 0) { + // Save the stub's claimed maximum packet size + m_remote_stub_max_memory_size = stub_max_size; - // Even if the stub says it can support ginormous packets, - // don't exceed our reasonable largeish default packet size. - if (stub_max_size > reasonable_largeish_default) - { - stub_max_size = reasonable_largeish_default; - } + // Even if the stub says it can support ginormous packets, + // don't exceed our reasonable largeish default packet size. + if (stub_max_size > reasonable_largeish_default) { + stub_max_size = reasonable_largeish_default; + } - m_max_memory_size = stub_max_size; - } - else - { - m_max_memory_size = conservative_default; - } + m_max_memory_size = stub_max_size; + } else { + m_max_memory_size = conservative_default; } + } } -void -ProcessGDBRemote::SetUserSpecifiedMaxMemoryTransferSize (uint64_t user_specified_max) -{ - if (user_specified_max != 0) - { - GetMaxMemorySize (); - - if (m_remote_stub_max_memory_size != 0) - { - if (m_remote_stub_max_memory_size < user_specified_max) - { - m_max_memory_size = m_remote_stub_max_memory_size; // user specified a packet size too big, go as big - // as the remote stub says we can go. - } - else - { - m_max_memory_size = user_specified_max; // user's packet size is good - } - } - else - { - m_max_memory_size = user_specified_max; // user's packet size is probably fine - } +void ProcessGDBRemote::SetUserSpecifiedMaxMemoryTransferSize( + uint64_t user_specified_max) { + if (user_specified_max != 0) { + GetMaxMemorySize(); + + if (m_remote_stub_max_memory_size != 0) { + if (m_remote_stub_max_memory_size < user_specified_max) { + m_max_memory_size = m_remote_stub_max_memory_size; // user specified a + // packet size too + // big, go as big + // as the remote stub says we can go. + } else { + m_max_memory_size = user_specified_max; // user's packet size is good + } + } else { + m_max_memory_size = + user_specified_max; // user's packet size is probably fine } + } } -bool -ProcessGDBRemote::GetModuleSpec(const FileSpec& module_file_spec, - const ArchSpec& arch, - ModuleSpec &module_spec) -{ - Log *log = GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PLATFORM); +bool ProcessGDBRemote::GetModuleSpec(const FileSpec &module_file_spec, + const ArchSpec &arch, + ModuleSpec &module_spec) { + Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM); - if (!m_gdb_comm.GetModuleInfo (module_file_spec, arch, module_spec)) - { - if (log) - log->Printf ("ProcessGDBRemote::%s - failed to get module info for %s:%s", - __FUNCTION__, module_file_spec.GetPath ().c_str (), - arch.GetTriple ().getTriple ().c_str ()); - return false; - } + const ModuleCacheKey key(module_file_spec.GetPath(), + arch.GetTriple().getTriple()); + auto cached = m_cached_module_specs.find(key); + if (cached != m_cached_module_specs.end()) { + module_spec = cached->second; + return bool(module_spec); + } + if (!m_gdb_comm.GetModuleInfo(module_file_spec, arch, module_spec)) { if (log) - { - StreamString stream; - module_spec.Dump (stream); - log->Printf ("ProcessGDBRemote::%s - got module info for (%s:%s) : %s", - __FUNCTION__, module_file_spec.GetPath ().c_str (), - arch.GetTriple ().getTriple ().c_str (), stream.GetString ().c_str ()); - } + log->Printf("ProcessGDBRemote::%s - failed to get module info for %s:%s", + __FUNCTION__, module_file_spec.GetPath().c_str(), + arch.GetTriple().getTriple().c_str()); + return false; + } + + if (log) { + StreamString stream; + module_spec.Dump(stream); + log->Printf("ProcessGDBRemote::%s - got module info for (%s:%s) : %s", + __FUNCTION__, module_file_spec.GetPath().c_str(), + arch.GetTriple().getTriple().c_str(), stream.GetData()); + } + + m_cached_module_specs[key] = module_spec; + return true; +} - return true; +void ProcessGDBRemote::PrefetchModuleSpecs( + llvm::ArrayRef<FileSpec> module_file_specs, const llvm::Triple &triple) { + auto module_specs = m_gdb_comm.GetModulesInfo(module_file_specs, triple); + if (module_specs) { + for (const FileSpec &spec : module_file_specs) + m_cached_module_specs[ModuleCacheKey(spec.GetPath(), + triple.getTriple())] = ModuleSpec(); + for (const ModuleSpec &spec : *module_specs) + m_cached_module_specs[ModuleCacheKey(spec.GetFileSpec().GetPath(), + triple.getTriple())] = spec; + } } -bool -ProcessGDBRemote::GetHostOSVersion(uint32_t &major, - uint32_t &minor, - uint32_t &update) -{ - if (m_gdb_comm.GetOSVersion(major, minor, update)) - return true; - // We failed to get the host OS version, defer to the base - // implementation to correctly invalidate the arguments. - return Process::GetHostOSVersion(major, minor, update); +bool ProcessGDBRemote::GetHostOSVersion(uint32_t &major, uint32_t &minor, + uint32_t &update) { + if (m_gdb_comm.GetOSVersion(major, minor, update)) + return true; + // We failed to get the host OS version, defer to the base + // implementation to correctly invalidate the arguments. + return Process::GetHostOSVersion(major, minor, update); } namespace { @@ -4365,29 +4078,29 @@ namespace { typedef std::vector<std::string> stringVec; typedef std::vector<struct GdbServerRegisterInfo> GDBServerRegisterVec; -struct RegisterSetInfo -{ - ConstString name; +struct RegisterSetInfo { + ConstString name; }; typedef std::map<uint32_t, RegisterSetInfo> RegisterSetMap; -struct GdbServerTargetInfo -{ - std::string arch; - std::string osabi; - stringVec includes; - RegisterSetMap reg_set_map; - XMLNode feature_node; +struct GdbServerTargetInfo { + std::string arch; + std::string osabi; + stringVec includes; + RegisterSetMap reg_set_map; + XMLNode feature_node; }; -bool -ParseRegisters (XMLNode feature_node, GdbServerTargetInfo &target_info, GDBRemoteDynamicRegisterInfo &dyn_reg_info, ABISP abi_sp, uint32_t &cur_reg_num, uint32_t ®_offset) -{ - if (!feature_node) - return false; +bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info, + GDBRemoteDynamicRegisterInfo &dyn_reg_info, ABISP abi_sp, + uint32_t &cur_reg_num, uint32_t ®_offset) { + if (!feature_node) + return false; - feature_node.ForEachChildElementWithName("reg", [&target_info, &dyn_reg_info, &cur_reg_num, ®_offset, &abi_sp](const XMLNode ®_node) -> bool { + feature_node.ForEachChildElementWithName( + "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; @@ -4398,931 +4111,1038 @@ ParseRegisters (XMLNode feature_node, GdbServerTargetInfo &target_info, GDBRemot std::vector<uint8_t> dwarf_opcode_bytes; bool encoding_set = false; bool format_set = false; - RegisterInfo reg_info = { NULL, // Name - NULL, // Alt name - 0, // byte size - reg_offset, // offset - eEncodingUint, // encoding - eFormatHex, // format + RegisterInfo reg_info = { + NULL, // Name + NULL, // Alt name + 0, // byte size + reg_offset, // offset + eEncodingUint, // encoding + eFormatHex, // format { LLDB_INVALID_REGNUM, // eh_frame reg num LLDB_INVALID_REGNUM, // DWARF reg num LLDB_INVALID_REGNUM, // generic reg num - cur_reg_num, // process plugin reg num - cur_reg_num // native register number + cur_reg_num, // process plugin reg num + cur_reg_num // native register number }, NULL, NULL, - NULL, // Dwarf Expression opcode bytes pointer - 0 // Dwarf Expression opcode bytes length + NULL, // Dwarf Expression opcode bytes pointer + 0 // Dwarf Expression opcode bytes length }; - reg_node.ForEachAttribute([&target_info, &gdb_group, &gdb_type, ®_name, &alt_name, &set_name, &value_regs, &invalidate_regs, &encoding_set, &format_set, ®_info, &cur_reg_num, ®_offset, &dwarf_opcode_bytes](const llvm::StringRef &name, const llvm::StringRef &value) -> bool { - if (name == "name") - { - reg_name.SetString(value); - } - else if (name == "bitsize") - { - reg_info.byte_size = StringConvert::ToUInt32(value.data(), 0, 0) / CHAR_BIT; - } - else if (name == "type") - { - gdb_type = value.str(); - } - else if (name == "group") - { - gdb_group = value.str(); - } - else if (name == "regnum") - { - const uint32_t regnum = StringConvert::ToUInt32(value.data(), LLDB_INVALID_REGNUM, 0); - if (regnum != LLDB_INVALID_REGNUM) - { - reg_info.kinds[eRegisterKindProcessPlugin] = regnum; - } - } - else if (name == "offset") - { - reg_offset = StringConvert::ToUInt32(value.data(), UINT32_MAX, 0); - } - else if (name == "altname") - { - alt_name.SetString(value); - } - else if (name == "encoding") - { - encoding_set = true; - reg_info.encoding = Args::StringToEncoding (value.data(), eEncodingUint); - } - else if (name == "format") - { - format_set = true; - Format format = eFormatInvalid; - if (Args::StringToFormat (value.data(), format, NULL).Success()) - reg_info.format = format; - else if (value == "vector-sint8") - reg_info.format = eFormatVectorOfSInt8; - else if (value == "vector-uint8") - reg_info.format = eFormatVectorOfUInt8; - else if (value == "vector-sint16") - reg_info.format = eFormatVectorOfSInt16; - else if (value == "vector-uint16") - reg_info.format = eFormatVectorOfUInt16; - else if (value == "vector-sint32") - reg_info.format = eFormatVectorOfSInt32; - else if (value == "vector-uint32") - reg_info.format = eFormatVectorOfUInt32; - else if (value == "vector-float32") - reg_info.format = eFormatVectorOfFloat32; - else if (value == "vector-uint128") - reg_info.format = eFormatVectorOfUInt128; - } - else if (name == "group_id") - { - const uint32_t set_id = StringConvert::ToUInt32(value.data(), UINT32_MAX, 0); - RegisterSetMap::const_iterator pos = target_info.reg_set_map.find(set_id); - if (pos != target_info.reg_set_map.end()) - set_name = pos->second.name; - } - else if (name == "gcc_regnum" || name == "ehframe_regnum") - { - reg_info.kinds[eRegisterKindEHFrame] = StringConvert::ToUInt32(value.data(), LLDB_INVALID_REGNUM, 0); - } - else if (name == "dwarf_regnum") - { - reg_info.kinds[eRegisterKindDWARF] = StringConvert::ToUInt32(value.data(), LLDB_INVALID_REGNUM, 0); - } - else if (name == "generic") - { - reg_info.kinds[eRegisterKindGeneric] = Args::StringToGenericRegister(value.data()); - } - else if (name == "value_regnums") - { - SplitCommaSeparatedRegisterNumberString(value, value_regs, 0); - } - else if (name == "invalidate_regnums") - { - SplitCommaSeparatedRegisterNumberString(value, invalidate_regs, 0); - } - else if (name == "dynamic_size_dwarf_expr_bytes") - { - StringExtractor opcode_extractor; - std::string opcode_string = value.str (); - size_t dwarf_opcode_len = opcode_string.length () / 2; - assert (dwarf_opcode_len > 0); - - dwarf_opcode_bytes.resize (dwarf_opcode_len); - reg_info.dynamic_size_dwarf_len = dwarf_opcode_len; - opcode_extractor.GetStringRef ().swap (opcode_string); - uint32_t ret_val = opcode_extractor.GetHexBytesAvail (dwarf_opcode_bytes.data (), - dwarf_opcode_len); - assert (dwarf_opcode_len == ret_val); - - reg_info.dynamic_size_dwarf_expr_bytes = dwarf_opcode_bytes.data (); - } - else - { - printf("unhandled attribute %s = %s\n", name.data(), value.data()); + reg_node.ForEachAttribute([&target_info, &gdb_group, &gdb_type, + ®_name, &alt_name, &set_name, &value_regs, + &invalidate_regs, &encoding_set, &format_set, + ®_info, &cur_reg_num, ®_offset, + &dwarf_opcode_bytes]( + const llvm::StringRef &name, + const llvm::StringRef &value) -> bool { + if (name == "name") { + reg_name.SetString(value); + } else if (name == "bitsize") { + reg_info.byte_size = + StringConvert::ToUInt32(value.data(), 0, 0) / CHAR_BIT; + } else if (name == "type") { + gdb_type = value.str(); + } else if (name == "group") { + gdb_group = value.str(); + } else if (name == "regnum") { + const uint32_t regnum = + StringConvert::ToUInt32(value.data(), LLDB_INVALID_REGNUM, 0); + if (regnum != LLDB_INVALID_REGNUM) { + reg_info.kinds[eRegisterKindProcessPlugin] = regnum; } - return true; // Keep iterating through all attributes + } else if (name == "offset") { + reg_offset = StringConvert::ToUInt32(value.data(), UINT32_MAX, 0); + } else if (name == "altname") { + alt_name.SetString(value); + } else if (name == "encoding") { + encoding_set = true; + reg_info.encoding = Args::StringToEncoding(value, eEncodingUint); + } else if (name == "format") { + format_set = true; + Format format = eFormatInvalid; + if (Args::StringToFormat(value.data(), format, NULL).Success()) + reg_info.format = format; + else if (value == "vector-sint8") + reg_info.format = eFormatVectorOfSInt8; + else if (value == "vector-uint8") + reg_info.format = eFormatVectorOfUInt8; + else if (value == "vector-sint16") + reg_info.format = eFormatVectorOfSInt16; + else if (value == "vector-uint16") + reg_info.format = eFormatVectorOfUInt16; + else if (value == "vector-sint32") + reg_info.format = eFormatVectorOfSInt32; + else if (value == "vector-uint32") + reg_info.format = eFormatVectorOfUInt32; + else if (value == "vector-float32") + reg_info.format = eFormatVectorOfFloat32; + else if (value == "vector-uint64") + reg_info.format = eFormatVectorOfUInt64; + else if (value == "vector-uint128") + reg_info.format = eFormatVectorOfUInt128; + } else if (name == "group_id") { + const uint32_t set_id = + StringConvert::ToUInt32(value.data(), UINT32_MAX, 0); + RegisterSetMap::const_iterator pos = + target_info.reg_set_map.find(set_id); + if (pos != target_info.reg_set_map.end()) + set_name = pos->second.name; + } else if (name == "gcc_regnum" || name == "ehframe_regnum") { + reg_info.kinds[eRegisterKindEHFrame] = + StringConvert::ToUInt32(value.data(), LLDB_INVALID_REGNUM, 0); + } else if (name == "dwarf_regnum") { + reg_info.kinds[eRegisterKindDWARF] = + StringConvert::ToUInt32(value.data(), LLDB_INVALID_REGNUM, 0); + } else if (name == "generic") { + reg_info.kinds[eRegisterKindGeneric] = + Args::StringToGenericRegister(value); + } else if (name == "value_regnums") { + SplitCommaSeparatedRegisterNumberString(value, value_regs, 0); + } else if (name == "invalidate_regnums") { + SplitCommaSeparatedRegisterNumberString(value, invalidate_regs, 0); + } else if (name == "dynamic_size_dwarf_expr_bytes") { + StringExtractor opcode_extractor; + std::string opcode_string = value.str(); + size_t dwarf_opcode_len = opcode_string.length() / 2; + assert(dwarf_opcode_len > 0); + + dwarf_opcode_bytes.resize(dwarf_opcode_len); + reg_info.dynamic_size_dwarf_len = dwarf_opcode_len; + opcode_extractor.GetStringRef().swap(opcode_string); + uint32_t ret_val = + opcode_extractor.GetHexBytesAvail(dwarf_opcode_bytes); + assert(dwarf_opcode_len == ret_val); + + reg_info.dynamic_size_dwarf_expr_bytes = dwarf_opcode_bytes.data(); + } else { + printf("unhandled attribute %s = %s\n", name.data(), value.data()); + } + return true; // Keep iterating through all attributes }); - if (!gdb_type.empty() && !(encoding_set || format_set)) - { - if (gdb_type.find("int") == 0) - { - reg_info.format = eFormatHex; - reg_info.encoding = eEncodingUint; - } - else if (gdb_type == "data_ptr" || gdb_type == "code_ptr") - { - reg_info.format = eFormatAddressInfo; - reg_info.encoding = eEncodingUint; - } - else if (gdb_type == "i387_ext" || gdb_type == "float") - { - reg_info.format = eFormatFloat; - reg_info.encoding = eEncodingIEEE754; - } + if (!gdb_type.empty() && !(encoding_set || format_set)) { + if (gdb_type.find("int") == 0) { + reg_info.format = eFormatHex; + reg_info.encoding = eEncodingUint; + } else if (gdb_type == "data_ptr" || gdb_type == "code_ptr") { + reg_info.format = eFormatAddressInfo; + reg_info.encoding = eEncodingUint; + } else if (gdb_type == "i387_ext" || gdb_type == "float") { + reg_info.format = eFormatFloat; + reg_info.encoding = eEncodingIEEE754; + } } - // Only update the register set name if we didn't get a "reg_set" attribute. + // Only update the register set name if we didn't get a "reg_set" + // attribute. // "set_name" will be empty if we didn't have a "reg_set" attribute. if (!set_name && !gdb_group.empty()) - set_name.SetCString(gdb_group.c_str()); + set_name.SetCString(gdb_group.c_str()); reg_info.byte_offset = reg_offset; - assert (reg_info.byte_size != 0); + assert(reg_info.byte_size != 0); reg_offset += reg_info.byte_size; - if (!value_regs.empty()) - { - value_regs.push_back(LLDB_INVALID_REGNUM); - reg_info.value_regs = value_regs.data(); + if (!value_regs.empty()) { + value_regs.push_back(LLDB_INVALID_REGNUM); + reg_info.value_regs = value_regs.data(); } - if (!invalidate_regs.empty()) - { - invalidate_regs.push_back(LLDB_INVALID_REGNUM); - reg_info.invalidate_regs = invalidate_regs.data(); + if (!invalidate_regs.empty()) { + invalidate_regs.push_back(LLDB_INVALID_REGNUM); + reg_info.invalidate_regs = invalidate_regs.data(); } ++cur_reg_num; - AugmentRegisterInfoViaABI (reg_info, reg_name, abi_sp); + AugmentRegisterInfoViaABI(reg_info, reg_name, abi_sp); dyn_reg_info.AddRegister(reg_info, reg_name, alt_name, set_name); return true; // Keep iterating through all "reg" elements - }); - return true; + }); + return true; } } // namespace {} - // query the target of gdb-remote for extended target information // return: 'true' on success // 'false' on failure -bool -ProcessGDBRemote::GetGDBServerRegisterInfo (ArchSpec &arch_to_use) -{ - // Make sure LLDB has an XML parser it can use first - if (!XMLDocument::XMLEnabled()) - return false; - - // redirect libxml2's error handler since the default prints to stdout - - GDBRemoteCommunicationClient & comm = m_gdb_comm; - - // check that we have extended feature read support - if ( !comm.GetQXferFeaturesReadSupported( ) ) - return false; - - // request the target xml file - std::string raw; - lldb_private::Error lldberr; - if (!comm.ReadExtFeature(ConstString("features"), - ConstString("target.xml"), - raw, - lldberr)) - { - return false; - } +bool ProcessGDBRemote::GetGDBServerRegisterInfo(ArchSpec &arch_to_use) { + // Make sure LLDB has an XML parser it can use first + if (!XMLDocument::XMLEnabled()) + return false; + // redirect libxml2's error handler since the default prints to stdout - XMLDocument xml_document; + GDBRemoteCommunicationClient &comm = m_gdb_comm; - if (xml_document.ParseMemory(raw.c_str(), raw.size(), "target.xml")) - { - GdbServerTargetInfo target_info; + // check that we have extended feature read support + if (!comm.GetQXferFeaturesReadSupported()) + return false; - XMLNode target_node = xml_document.GetRootElement("target"); - if (target_node) - { - XMLNode feature_node; - target_node.ForEachChildElement([&target_info, this, &feature_node](const XMLNode &node) -> bool - { - llvm::StringRef name = node.GetName(); - if (name == "architecture") - { - node.GetElementText(target_info.arch); - } - else if (name == "osabi") - { - node.GetElementText(target_info.osabi); - } - else if (name == "xi:include" || name == "include") - { - llvm::StringRef href = node.GetAttributeValue("href"); - if (!href.empty()) - target_info.includes.push_back(href.str()); - } - else if (name == "feature") - { - feature_node = node; - } - else if (name == "groups") - { - node.ForEachChildElementWithName("group", [&target_info](const XMLNode &node) -> bool { - uint32_t set_id = UINT32_MAX; - RegisterSetInfo set_info; - - node.ForEachAttribute([&set_id, &set_info](const llvm::StringRef &name, const llvm::StringRef &value) -> bool { - if (name == "id") - set_id = StringConvert::ToUInt32(value.data(), UINT32_MAX, 0); - if (name == "name") - set_info.name = ConstString(value); - return true; // Keep iterating through all attributes - }); - - if (set_id != UINT32_MAX) - target_info.reg_set_map[set_id] = set_info; - return true; // Keep iterating through all "group" elements + // request the target xml file + std::string raw; + lldb_private::Error lldberr; + if (!comm.ReadExtFeature(ConstString("features"), ConstString("target.xml"), + raw, lldberr)) { + return false; + } + + XMLDocument xml_document; + + if (xml_document.ParseMemory(raw.c_str(), raw.size(), "target.xml")) { + GdbServerTargetInfo target_info; + + XMLNode target_node = xml_document.GetRootElement("target"); + if (target_node) { + XMLNode feature_node; + target_node.ForEachChildElement([&target_info, this, &feature_node]( + const XMLNode &node) -> bool { + llvm::StringRef name = node.GetName(); + if (name == "architecture") { + node.GetElementText(target_info.arch); + } else if (name == "osabi") { + node.GetElementText(target_info.osabi); + } else if (name == "xi:include" || name == "include") { + llvm::StringRef href = node.GetAttributeValue("href"); + if (!href.empty()) + target_info.includes.push_back(href.str()); + } else if (name == "feature") { + feature_node = node; + } else if (name == "groups") { + node.ForEachChildElementWithName( + "group", [&target_info](const XMLNode &node) -> bool { + uint32_t set_id = UINT32_MAX; + RegisterSetInfo set_info; + + node.ForEachAttribute( + [&set_id, &set_info](const llvm::StringRef &name, + const llvm::StringRef &value) -> bool { + if (name == "id") + set_id = StringConvert::ToUInt32(value.data(), + UINT32_MAX, 0); + if (name == "name") + set_info.name = ConstString(value); + return true; // Keep iterating through all attributes }); - } - return true; // Keep iterating through all children of the target_node - }); - - // Initialize these outside of ParseRegisters, since they should not be reset inside each include feature - uint32_t cur_reg_num = 0; - uint32_t reg_offset = 0; - - // Don't use Process::GetABI, this code gets called from DidAttach, and in that context we haven't - // set the Target's architecture yet, so the ABI is also potentially incorrect. - ABISP abi_to_use_sp = ABI::FindPlugin(arch_to_use); - if (feature_node) - { - ParseRegisters(feature_node, target_info, this->m_register_info, abi_to_use_sp, cur_reg_num, reg_offset); - } - for (const auto &include : target_info.includes) - { - // request register file - std::string xml_data; - if (!comm.ReadExtFeature(ConstString("features"), - ConstString(include), - xml_data, - lldberr)) - continue; - - XMLDocument include_xml_document; - include_xml_document.ParseMemory(xml_data.data(), xml_data.size(), include.c_str()); - XMLNode include_feature_node = include_xml_document.GetRootElement("feature"); - if (include_feature_node) - { - ParseRegisters(include_feature_node, target_info, this->m_register_info, abi_to_use_sp, cur_reg_num, reg_offset); - } - } - this->m_register_info.Finalize(arch_to_use); + if (set_id != UINT32_MAX) + target_info.reg_set_map[set_id] = set_info; + return true; // Keep iterating through all "group" elements + }); + } + return true; // Keep iterating through all children of the target_node + }); + + // Initialize these outside of ParseRegisters, since they should not be + // reset inside each include feature + uint32_t cur_reg_num = 0; + uint32_t reg_offset = 0; + + // Don't use Process::GetABI, this code gets called from DidAttach, and in + // that context we haven't + // set the Target's architecture yet, so the ABI is also potentially + // incorrect. + ABISP abi_to_use_sp = ABI::FindPlugin(arch_to_use); + if (feature_node) { + ParseRegisters(feature_node, target_info, this->m_register_info, + abi_to_use_sp, cur_reg_num, reg_offset); + } + + for (const auto &include : target_info.includes) { + // request register file + std::string xml_data; + if (!comm.ReadExtFeature(ConstString("features"), ConstString(include), + xml_data, lldberr)) + continue; + + XMLDocument include_xml_document; + include_xml_document.ParseMemory(xml_data.data(), xml_data.size(), + include.c_str()); + XMLNode include_feature_node = + include_xml_document.GetRootElement("feature"); + if (include_feature_node) { + ParseRegisters(include_feature_node, target_info, + this->m_register_info, abi_to_use_sp, cur_reg_num, + reg_offset); } + } + this->m_register_info.Finalize(arch_to_use); } + } - return m_register_info.GetNumRegisters() > 0; + return m_register_info.GetNumRegisters() > 0; } -Error -ProcessGDBRemote::GetLoadedModuleList (LoadedModuleInfoList & list) -{ - // Make sure LLDB has an XML parser it can use first - if (!XMLDocument::XMLEnabled()) - return Error (0, ErrorType::eErrorTypeGeneric); +Error ProcessGDBRemote::GetLoadedModuleList(LoadedModuleInfoList &list) { + // Make sure LLDB has an XML parser it can use first + if (!XMLDocument::XMLEnabled()) + return Error(0, ErrorType::eErrorTypeGeneric); - Log *log = GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS); - if (log) - log->Printf ("ProcessGDBRemote::%s", __FUNCTION__); + Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS); + if (log) + log->Printf("ProcessGDBRemote::%s", __FUNCTION__); - GDBRemoteCommunicationClient & comm = m_gdb_comm; + GDBRemoteCommunicationClient &comm = m_gdb_comm; - // check that we have extended feature read support - if (comm.GetQXferLibrariesSVR4ReadSupported ()) { - list.clear (); + // check that we have extended feature read support + if (comm.GetQXferLibrariesSVR4ReadSupported()) { + list.clear(); - // request the loaded library list - std::string raw; - lldb_private::Error lldberr; + // request the loaded library list + std::string raw; + lldb_private::Error lldberr; - if (!comm.ReadExtFeature (ConstString ("libraries-svr4"), ConstString (""), raw, lldberr)) - return Error (0, ErrorType::eErrorTypeGeneric); + if (!comm.ReadExtFeature(ConstString("libraries-svr4"), ConstString(""), + raw, lldberr)) + return Error(0, ErrorType::eErrorTypeGeneric); - // parse the xml file in memory - if (log) - log->Printf ("parsing: %s", raw.c_str()); - XMLDocument doc; + // parse the xml file in memory + if (log) + log->Printf("parsing: %s", raw.c_str()); + XMLDocument doc; - if (!doc.ParseMemory(raw.c_str(), raw.size(), "noname.xml")) - return Error (0, ErrorType::eErrorTypeGeneric); + if (!doc.ParseMemory(raw.c_str(), raw.size(), "noname.xml")) + return Error(0, ErrorType::eErrorTypeGeneric); - XMLNode root_element = doc.GetRootElement("library-list-svr4"); - if (!root_element) - return Error(); + XMLNode root_element = doc.GetRootElement("library-list-svr4"); + if (!root_element) + return Error(); - // main link map structure - llvm::StringRef main_lm = root_element.GetAttributeValue("main-lm"); - if (!main_lm.empty()) - { - list.m_link_map = StringConvert::ToUInt64(main_lm.data(), LLDB_INVALID_ADDRESS, 0); - } + // main link map structure + llvm::StringRef main_lm = root_element.GetAttributeValue("main-lm"); + if (!main_lm.empty()) { + list.m_link_map = + StringConvert::ToUInt64(main_lm.data(), LLDB_INVALID_ADDRESS, 0); + } - root_element.ForEachChildElementWithName("library", [log, &list](const XMLNode &library) -> bool { + root_element.ForEachChildElementWithName( + "library", [log, &list](const XMLNode &library) -> bool { - LoadedModuleInfoList::LoadedModuleInfo module; + LoadedModuleInfoList::LoadedModuleInfo module; - library.ForEachAttribute([log, &module](const llvm::StringRef &name, const llvm::StringRef &value) -> bool { + library.ForEachAttribute( + [log, &module](const llvm::StringRef &name, + const llvm::StringRef &value) -> bool { if (name == "name") - module.set_name (value.str()); - else if (name == "lm") - { - // the address of the link_map struct. - module.set_link_map(StringConvert::ToUInt64(value.data(), LLDB_INVALID_ADDRESS, 0)); - } - else if (name == "l_addr") - { - // the displacement as read from the field 'l_addr' of the link_map struct. - module.set_base(StringConvert::ToUInt64(value.data(), LLDB_INVALID_ADDRESS, 0)); - // base address is always a displacement, not an absolute value. - module.set_base_is_offset(true); - } - else if (name == "l_ld") - { - // the memory address of the libraries PT_DYAMIC section. - module.set_dynamic(StringConvert::ToUInt64(value.data(), LLDB_INVALID_ADDRESS, 0)); + module.set_name(value.str()); + else if (name == "lm") { + // the address of the link_map struct. + module.set_link_map(StringConvert::ToUInt64( + value.data(), LLDB_INVALID_ADDRESS, 0)); + } else if (name == "l_addr") { + // the displacement as read from the field 'l_addr' of the + // link_map struct. + module.set_base(StringConvert::ToUInt64( + value.data(), LLDB_INVALID_ADDRESS, 0)); + // base address is always a displacement, not an absolute + // value. + module.set_base_is_offset(true); + } else if (name == "l_ld") { + // the memory address of the libraries PT_DYAMIC section. + module.set_dynamic(StringConvert::ToUInt64( + value.data(), LLDB_INVALID_ADDRESS, 0)); } return true; // Keep iterating over all properties of "library" - }); - - if (log) - { - std::string name; - lldb::addr_t lm=0, base=0, ld=0; - bool base_is_offset; - - module.get_name (name); - module.get_link_map (lm); - module.get_base (base); - module.get_base_is_offset (base_is_offset); - module.get_dynamic (ld); - - log->Printf ("found (link_map:0x%08" PRIx64 ", base:0x%08" PRIx64 "[%s], ld:0x%08" PRIx64 ", name:'%s')", lm, base, (base_is_offset ? "offset" : "absolute"), ld, name.c_str()); - } - - list.add (module); - return true; // Keep iterating over all "library" elements in the root node + }); + + if (log) { + std::string name; + lldb::addr_t lm = 0, base = 0, ld = 0; + bool base_is_offset; + + module.get_name(name); + module.get_link_map(lm); + module.get_base(base); + module.get_base_is_offset(base_is_offset); + module.get_dynamic(ld); + + log->Printf("found (link_map:0x%08" PRIx64 ", base:0x%08" PRIx64 + "[%s], ld:0x%08" PRIx64 ", name:'%s')", + lm, base, (base_is_offset ? "offset" : "absolute"), ld, + name.c_str()); + } + + list.add(module); + return true; // Keep iterating over all "library" elements in the root + // node }); - if (log) - log->Printf ("found %" PRId32 " modules in total", (int) list.m_list.size()); - } else if (comm.GetQXferLibrariesReadSupported ()) { - list.clear (); - - // request the loaded library list - std::string raw; - lldb_private::Error lldberr; - - if (!comm.ReadExtFeature (ConstString ("libraries"), ConstString (""), raw, lldberr)) - return Error (0, ErrorType::eErrorTypeGeneric); - - if (log) - log->Printf ("parsing: %s", raw.c_str()); - XMLDocument doc; - - if (!doc.ParseMemory(raw.c_str(), raw.size(), "noname.xml")) - return Error (0, ErrorType::eErrorTypeGeneric); - - XMLNode root_element = doc.GetRootElement("library-list"); - if (!root_element) - return Error(); - - root_element.ForEachChildElementWithName("library", [log, &list](const XMLNode &library) -> bool { - LoadedModuleInfoList::LoadedModuleInfo module; - - llvm::StringRef name = library.GetAttributeValue("name"); - module.set_name(name.str()); + if (log) + log->Printf("found %" PRId32 " modules in total", + (int)list.m_list.size()); + } else if (comm.GetQXferLibrariesReadSupported()) { + list.clear(); - // The base address of a given library will be the address of its - // first section. Most remotes send only one section for Windows - // targets for example. - const XMLNode §ion = library.FindFirstChildElementWithName("section"); - llvm::StringRef address = section.GetAttributeValue("address"); - module.set_base(StringConvert::ToUInt64(address.data(), LLDB_INVALID_ADDRESS, 0)); - // These addresses are absolute values. - module.set_base_is_offset(false); + // request the loaded library list + std::string raw; + lldb_private::Error lldberr; - if (log) - { - std::string name; - lldb::addr_t base = 0; - bool base_is_offset; - module.get_name (name); - module.get_base (base); - module.get_base_is_offset (base_is_offset); - - log->Printf ("found (base:0x%08" PRIx64 "[%s], name:'%s')", base, (base_is_offset ? "offset" : "absolute"), name.c_str()); - } + if (!comm.ReadExtFeature(ConstString("libraries"), ConstString(""), raw, + lldberr)) + return Error(0, ErrorType::eErrorTypeGeneric); - list.add (module); - return true; // Keep iterating over all "library" elements in the root node + if (log) + log->Printf("parsing: %s", raw.c_str()); + XMLDocument doc; + + if (!doc.ParseMemory(raw.c_str(), raw.size(), "noname.xml")) + return Error(0, ErrorType::eErrorTypeGeneric); + + XMLNode root_element = doc.GetRootElement("library-list"); + if (!root_element) + return Error(); + + root_element.ForEachChildElementWithName( + "library", [log, &list](const XMLNode &library) -> bool { + LoadedModuleInfoList::LoadedModuleInfo module; + + llvm::StringRef name = library.GetAttributeValue("name"); + module.set_name(name.str()); + + // The base address of a given library will be the address of its + // first section. Most remotes send only one section for Windows + // targets for example. + const XMLNode §ion = + library.FindFirstChildElementWithName("section"); + llvm::StringRef address = section.GetAttributeValue("address"); + module.set_base( + StringConvert::ToUInt64(address.data(), LLDB_INVALID_ADDRESS, 0)); + // These addresses are absolute values. + module.set_base_is_offset(false); + + if (log) { + std::string name; + lldb::addr_t base = 0; + bool base_is_offset; + module.get_name(name); + module.get_base(base); + module.get_base_is_offset(base_is_offset); + + log->Printf("found (base:0x%08" PRIx64 "[%s], name:'%s')", base, + (base_is_offset ? "offset" : "absolute"), name.c_str()); + } + + list.add(module); + return true; // Keep iterating over all "library" elements in the root + // node }); - if (log) - log->Printf ("found %" PRId32 " modules in total", (int) list.m_list.size()); - } else { - return Error (0, ErrorType::eErrorTypeGeneric); - } + if (log) + log->Printf("found %" PRId32 " modules in total", + (int)list.m_list.size()); + } else { + return Error(0, ErrorType::eErrorTypeGeneric); + } - return Error(); + return Error(); } -lldb::ModuleSP -ProcessGDBRemote::LoadModuleAtAddress (const FileSpec &file, lldb::addr_t link_map, - lldb::addr_t base_addr, bool value_is_offset) -{ - DynamicLoader *loader = GetDynamicLoader(); - if (!loader) - return nullptr; +lldb::ModuleSP ProcessGDBRemote::LoadModuleAtAddress(const FileSpec &file, + lldb::addr_t link_map, + lldb::addr_t base_addr, + bool value_is_offset) { + DynamicLoader *loader = GetDynamicLoader(); + if (!loader) + return nullptr; - return loader->LoadModuleAtAddress(file, link_map, base_addr, value_is_offset); + return loader->LoadModuleAtAddress(file, link_map, base_addr, + value_is_offset); } -size_t -ProcessGDBRemote::LoadModules (LoadedModuleInfoList &module_list) -{ - using lldb_private::process_gdb_remote::ProcessGDBRemote; - - // request a list of loaded libraries from GDBServer - if (GetLoadedModuleList (module_list).Fail()) - return 0; +size_t ProcessGDBRemote::LoadModules(LoadedModuleInfoList &module_list) { + using lldb_private::process_gdb_remote::ProcessGDBRemote; - // get a list of all the modules - ModuleList new_modules; + // request a list of loaded libraries from GDBServer + if (GetLoadedModuleList(module_list).Fail()) + return 0; - for (LoadedModuleInfoList::LoadedModuleInfo & modInfo : module_list.m_list) - { - std::string mod_name; - lldb::addr_t mod_base; - lldb::addr_t link_map; - bool mod_base_is_offset; - - bool valid = true; - valid &= modInfo.get_name (mod_name); - valid &= modInfo.get_base (mod_base); - valid &= modInfo.get_base_is_offset (mod_base_is_offset); - if (!valid) - continue; - - if (!modInfo.get_link_map (link_map)) - link_map = LLDB_INVALID_ADDRESS; - - FileSpec file (mod_name.c_str(), true); - lldb::ModuleSP module_sp = LoadModuleAtAddress (file, link_map, mod_base, - mod_base_is_offset); - - if (module_sp.get()) - new_modules.Append (module_sp); - } + // get a list of all the modules + ModuleList new_modules; + + for (LoadedModuleInfoList::LoadedModuleInfo &modInfo : module_list.m_list) { + std::string mod_name; + lldb::addr_t mod_base; + lldb::addr_t link_map; + bool mod_base_is_offset; + + bool valid = true; + valid &= modInfo.get_name(mod_name); + valid &= modInfo.get_base(mod_base); + valid &= modInfo.get_base_is_offset(mod_base_is_offset); + if (!valid) + continue; + + if (!modInfo.get_link_map(link_map)) + link_map = LLDB_INVALID_ADDRESS; + + FileSpec file(mod_name, true); + lldb::ModuleSP module_sp = + LoadModuleAtAddress(file, link_map, mod_base, mod_base_is_offset); + + if (module_sp.get()) + new_modules.Append(module_sp); + } + + if (new_modules.GetSize() > 0) { + ModuleList removed_modules; + Target &target = GetTarget(); + ModuleList &loaded_modules = m_process->GetTarget().GetImages(); + + for (size_t i = 0; i < loaded_modules.GetSize(); ++i) { + const lldb::ModuleSP loaded_module = loaded_modules.GetModuleAtIndex(i); + + bool found = false; + for (size_t j = 0; j < new_modules.GetSize(); ++j) { + if (new_modules.GetModuleAtIndex(j).get() == loaded_module.get()) + found = true; + } + + // The main executable will never be included in libraries-svr4, don't + // remove it + if (!found && + loaded_module.get() != target.GetExecutableModulePointer()) { + removed_modules.Append(loaded_module); + } + } + + loaded_modules.Remove(removed_modules); + m_process->GetTarget().ModulesDidUnload(removed_modules, false); + + new_modules.ForEach([&target](const lldb::ModuleSP module_sp) -> bool { + lldb_private::ObjectFile *obj = module_sp->GetObjectFile(); + if (!obj) + return true; - if (new_modules.GetSize() > 0) - { - ModuleList removed_modules; - Target &target = GetTarget(); - ModuleList &loaded_modules = m_process->GetTarget().GetImages(); + if (obj->GetType() != ObjectFile::Type::eTypeExecutable) + return true; - for (size_t i = 0; i < loaded_modules.GetSize(); ++i) - { - const lldb::ModuleSP loaded_module = loaded_modules.GetModuleAtIndex(i); + lldb::ModuleSP module_copy_sp = module_sp; + target.SetExecutableModule(module_copy_sp, false); + return false; + }); - bool found = false; - for (size_t j = 0; j < new_modules.GetSize(); ++j) - { - if (new_modules.GetModuleAtIndex(j).get() == loaded_module.get()) - found = true; - } + loaded_modules.AppendIfNeeded(new_modules); + m_process->GetTarget().ModulesDidLoad(new_modules); + } - // The main executable will never be included in libraries-svr4, don't remove it - if (!found && loaded_module.get() != target.GetExecutableModulePointer()) - { - removed_modules.Append (loaded_module); - } - } - - loaded_modules.Remove (removed_modules); - m_process->GetTarget().ModulesDidUnload (removed_modules, false); + return new_modules.GetSize(); +} - new_modules.ForEach ([&target](const lldb::ModuleSP module_sp) -> bool - { - lldb_private::ObjectFile * obj = module_sp->GetObjectFile (); - if (!obj) - return true; +size_t ProcessGDBRemote::LoadModules() { + LoadedModuleInfoList module_list; + return LoadModules(module_list); +} - if (obj->GetType () != ObjectFile::Type::eTypeExecutable) - return true; +Error ProcessGDBRemote::GetFileLoadAddress(const FileSpec &file, + bool &is_loaded, + lldb::addr_t &load_addr) { + is_loaded = false; + load_addr = LLDB_INVALID_ADDRESS; + + std::string file_path = file.GetPath(false); + if (file_path.empty()) + return Error("Empty file name specified"); + + StreamString packet; + packet.PutCString("qFileLoadAddress:"); + packet.PutCStringAsRawHex8(file_path.c_str()); + + StringExtractorGDBRemote response; + if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response, + false) != + GDBRemoteCommunication::PacketResult::Success) + return Error("Sending qFileLoadAddress packet failed"); + + if (response.IsErrorResponse()) { + if (response.GetError() == 1) { + // The file is not loaded into the inferior + is_loaded = false; + load_addr = LLDB_INVALID_ADDRESS; + return Error(); + } + + return Error( + "Fetching file load address from remote server returned an error"); + } + + if (response.IsNormalResponse()) { + is_loaded = true; + load_addr = response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS); + return Error(); + } - lldb::ModuleSP module_copy_sp = module_sp; - target.SetExecutableModule (module_copy_sp, false); - return false; - }); + return Error("Unknown error happened during sending the load address packet"); +} - loaded_modules.AppendIfNeeded (new_modules); - m_process->GetTarget().ModulesDidLoad (new_modules); - } +void ProcessGDBRemote::ModulesDidLoad(ModuleList &module_list) { + // We must call the lldb_private::Process::ModulesDidLoad () first before we + // do anything + Process::ModulesDidLoad(module_list); - return new_modules.GetSize(); + // After loading shared libraries, we can ask our remote GDB server if + // it needs any symbols. + m_gdb_comm.ServeSymbolLookups(this); } -size_t -ProcessGDBRemote::LoadModules () -{ - LoadedModuleInfoList module_list; - return LoadModules (module_list); +void ProcessGDBRemote::HandleAsyncStdout(llvm::StringRef out) { + AppendSTDOUT(out.data(), out.size()); } -Error -ProcessGDBRemote::GetFileLoadAddress(const FileSpec& file, bool& is_loaded, lldb::addr_t& load_addr) -{ - is_loaded = false; - load_addr = LLDB_INVALID_ADDRESS; - - std::string file_path = file.GetPath(false); - if (file_path.empty ()) - return Error("Empty file name specified"); - - StreamString packet; - packet.PutCString("qFileLoadAddress:"); - packet.PutCStringAsRawHex8(file_path.c_str()); - - StringExtractorGDBRemote response; - if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), response, false) != GDBRemoteCommunication::PacketResult::Success) - return Error("Sending qFileLoadAddress packet failed"); +static const char *end_delimiter = "--end--;"; +static const int end_delimiter_len = 8; + +void ProcessGDBRemote::HandleAsyncMisc(llvm::StringRef data) { + std::string input = data.str(); // '1' to move beyond 'A' + if (m_partial_profile_data.length() > 0) { + m_partial_profile_data.append(input); + input = m_partial_profile_data; + m_partial_profile_data.clear(); + } + + size_t found, pos = 0, len = input.length(); + while ((found = input.find(end_delimiter, pos)) != std::string::npos) { + StringExtractorGDBRemote profileDataExtractor( + input.substr(pos, found).c_str()); + std::string profile_data = + HarmonizeThreadIdsForProfileData(profileDataExtractor); + BroadcastAsyncProfileData(profile_data); + + pos = found + end_delimiter_len; + } + + if (pos < len) { + // Last incomplete chunk. + m_partial_profile_data = input.substr(pos); + } +} - if (response.IsErrorResponse()) - { - if (response.GetError() == 1) - { - // The file is not loaded into the inferior - is_loaded = false; - load_addr = LLDB_INVALID_ADDRESS; - return Error(); +std::string ProcessGDBRemote::HarmonizeThreadIdsForProfileData( + StringExtractorGDBRemote &profileDataExtractor) { + std::map<uint64_t, uint32_t> new_thread_id_to_used_usec_map; + std::string output; + llvm::raw_string_ostream output_stream(output); + llvm::StringRef name, value; + + // Going to assuming thread_used_usec comes first, else bail out. + while (profileDataExtractor.GetNameColonValue(name, value)) { + if (name.compare("thread_used_id") == 0) { + StringExtractor threadIDHexExtractor(value); + uint64_t thread_id = threadIDHexExtractor.GetHexMaxU64(false, 0); + + bool has_used_usec = false; + uint32_t curr_used_usec = 0; + llvm::StringRef usec_name, usec_value; + uint32_t input_file_pos = profileDataExtractor.GetFilePos(); + if (profileDataExtractor.GetNameColonValue(usec_name, usec_value)) { + if (usec_name.equals("thread_used_usec")) { + has_used_usec = true; + usec_value.getAsInteger(0, curr_used_usec); + } else { + // We didn't find what we want, it is probably + // an older version. Bail out. + profileDataExtractor.SetFilePos(input_file_pos); + } + } + + if (has_used_usec) { + uint32_t prev_used_usec = 0; + std::map<uint64_t, uint32_t>::iterator iterator = + m_thread_id_to_used_usec_map.find(thread_id); + if (iterator != m_thread_id_to_used_usec_map.end()) { + prev_used_usec = m_thread_id_to_used_usec_map[thread_id]; } - return Error("Fetching file load address from remote server returned an error"); - } + uint32_t real_used_usec = curr_used_usec - prev_used_usec; + // A good first time record is one that runs for at least 0.25 sec + bool good_first_time = + (prev_used_usec == 0) && (real_used_usec > 250000); + bool good_subsequent_time = + (prev_used_usec > 0) && + ((real_used_usec > 0) || (HasAssignedIndexIDToThread(thread_id))); + + if (good_first_time || good_subsequent_time) { + // We try to avoid doing too many index id reservation, + // resulting in fast increase of index ids. + + output_stream << name << ":"; + int32_t index_id = AssignIndexIDToThread(thread_id); + output_stream << index_id << ";"; + + output_stream << usec_name << ":" << usec_value << ";"; + } else { + // Skip past 'thread_used_name'. + llvm::StringRef local_name, local_value; + profileDataExtractor.GetNameColonValue(local_name, local_value); + } - if (response.IsNormalResponse()) - { - is_loaded = true; - load_addr = response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS); - return Error(); + // Store current time as previous time so that they can be compared + // later. + new_thread_id_to_used_usec_map[thread_id] = curr_used_usec; + } else { + // Bail out and use old string. + output_stream << name << ":" << value << ";"; + } + } else { + output_stream << name << ":" << value << ";"; } + } + output_stream << end_delimiter; + m_thread_id_to_used_usec_map = new_thread_id_to_used_usec_map; - return Error("Unknown error happened during sending the load address packet"); + return output_stream.str(); } +void ProcessGDBRemote::HandleStopReply() { + if (GetStopID() != 0) + return; -void -ProcessGDBRemote::ModulesDidLoad (ModuleList &module_list) -{ - // We must call the lldb_private::Process::ModulesDidLoad () first before we do anything - Process::ModulesDidLoad (module_list); - - // After loading shared libraries, we can ask our remote GDB server if - // it needs any symbols. - m_gdb_comm.ServeSymbolLookups(this); + if (GetID() == LLDB_INVALID_PROCESS_ID) { + lldb::pid_t pid = m_gdb_comm.GetCurrentProcessID(); + if (pid != LLDB_INVALID_PROCESS_ID) + SetID(pid); + } + BuildDynamicRegisterInfo(true); } - -class CommandObjectProcessGDBRemoteSpeedTest: public CommandObjectParsed -{ -public: - CommandObjectProcessGDBRemoteSpeedTest(CommandInterpreter &interpreter) : - CommandObjectParsed (interpreter, - "process plugin packet speed-test", - "Tests packet speeds of various sizes to determine the performance characteristics of the GDB remote connection. ", - NULL), - m_option_group (interpreter), - m_num_packets (LLDB_OPT_SET_1, false, "count", 'c', 0, eArgTypeCount, "The number of packets to send of each varying size (default is 1000).", 1000), - m_max_send (LLDB_OPT_SET_1, false, "max-send", 's', 0, eArgTypeCount, "The maximum number of bytes to send in a packet. Sizes increase in powers of 2 while the size is less than or equal to this option value. (default 1024).", 1024), - m_max_recv (LLDB_OPT_SET_1, false, "max-receive", 'r', 0, eArgTypeCount, "The maximum number of bytes to receive in a packet. Sizes increase in powers of 2 while the size is less than or equal to this option value. (default 1024).", 1024), - m_json (LLDB_OPT_SET_1, false, "json", 'j', "Print the output as JSON data for easy parsing.", false, true) - { - m_option_group.Append (&m_num_packets, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); - m_option_group.Append (&m_max_send, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); - m_option_group.Append (&m_max_recv, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); - m_option_group.Append (&m_json, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); - m_option_group.Finalize(); - } - - ~CommandObjectProcessGDBRemoteSpeedTest () - { +static const char *const s_async_json_packet_prefix = "JSON-async:"; + +static StructuredData::ObjectSP +ParseStructuredDataPacket(llvm::StringRef packet) { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + + if (!packet.consume_front(s_async_json_packet_prefix)) { + if (log) { + log->Printf( + "GDBRemoteCommmunicationClientBase::%s() received $J packet " + "but was not a StructuredData packet: packet starts with " + "%s", + __FUNCTION__, + packet.slice(0, strlen(s_async_json_packet_prefix)).str().c_str()); + } + return StructuredData::ObjectSP(); + } + + // This is an asynchronous JSON packet, destined for a + // StructuredDataPlugin. + StructuredData::ObjectSP json_sp = StructuredData::ParseJSON(packet); + if (log) { + if (json_sp) { + StreamString json_str; + json_sp->Dump(json_str); + json_str.Flush(); + log->Printf("ProcessGDBRemote::%s() " + "received Async StructuredData packet: %s", + __FUNCTION__, json_str.GetData()); + } else { + log->Printf("ProcessGDBRemote::%s" + "() received StructuredData packet:" + " parse failure", + __FUNCTION__); } + } + return json_sp; +} +void ProcessGDBRemote::HandleAsyncStructuredDataPacket(llvm::StringRef data) { + auto structured_data_sp = ParseStructuredDataPacket(data); + if (structured_data_sp) + RouteAsyncStructuredData(structured_data_sp); +} - Options * - GetOptions () override - { - return &m_option_group; +class CommandObjectProcessGDBRemoteSpeedTest : public CommandObjectParsed { +public: + CommandObjectProcessGDBRemoteSpeedTest(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "process plugin packet speed-test", + "Tests packet speeds of various sizes to determine " + "the performance characteristics of the GDB remote " + "connection. ", + NULL), + m_option_group(), + m_num_packets(LLDB_OPT_SET_1, false, "count", 'c', 0, eArgTypeCount, + "The number of packets to send of each varying size " + "(default is 1000).", + 1000), + m_max_send(LLDB_OPT_SET_1, false, "max-send", 's', 0, eArgTypeCount, + "The maximum number of bytes to send in a packet. Sizes " + "increase in powers of 2 while the size is less than or " + "equal to this option value. (default 1024).", + 1024), + m_max_recv(LLDB_OPT_SET_1, false, "max-receive", 'r', 0, eArgTypeCount, + "The maximum number of bytes to receive in a packet. Sizes " + "increase in powers of 2 while the size is less than or " + "equal to this option value. (default 1024).", + 1024), + m_json(LLDB_OPT_SET_1, false, "json", 'j', + "Print the output as JSON data for easy parsing.", false, true) { + m_option_group.Append(&m_num_packets, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); + m_option_group.Append(&m_max_send, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); + m_option_group.Append(&m_max_recv, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); + m_option_group.Append(&m_json, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); + m_option_group.Finalize(); + } + + ~CommandObjectProcessGDBRemoteSpeedTest() {} + + Options *GetOptions() override { return &m_option_group; } + + bool DoExecute(Args &command, CommandReturnObject &result) override { + const size_t argc = command.GetArgumentCount(); + if (argc == 0) { + ProcessGDBRemote *process = + (ProcessGDBRemote *)m_interpreter.GetExecutionContext() + .GetProcessPtr(); + if (process) { + StreamSP output_stream_sp( + m_interpreter.GetDebugger().GetAsyncOutputStream()); + result.SetImmediateOutputStream(output_stream_sp); + + const uint32_t num_packets = + (uint32_t)m_num_packets.GetOptionValue().GetCurrentValue(); + const uint64_t max_send = m_max_send.GetOptionValue().GetCurrentValue(); + const uint64_t max_recv = m_max_recv.GetOptionValue().GetCurrentValue(); + const bool json = m_json.GetOptionValue().GetCurrentValue(); + const uint64_t k_recv_amount = + 4 * 1024 * 1024; // Receive amount in bytes + process->GetGDBRemote().TestPacketSpeed( + num_packets, max_send, max_recv, k_recv_amount, json, + output_stream_sp ? *output_stream_sp : result.GetOutputStream()); + result.SetStatus(eReturnStatusSuccessFinishResult); + return true; + } + } else { + result.AppendErrorWithFormat("'%s' takes no arguments", + m_cmd_name.c_str()); } + result.SetStatus(eReturnStatusFailed); + return false; + } - bool - DoExecute (Args& command, CommandReturnObject &result) override - { - const size_t argc = command.GetArgumentCount(); - if (argc == 0) - { - ProcessGDBRemote *process = (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr(); - if (process) - { - StreamSP output_stream_sp (m_interpreter.GetDebugger().GetAsyncOutputStream()); - result.SetImmediateOutputStream (output_stream_sp); - - const uint32_t num_packets = (uint32_t)m_num_packets.GetOptionValue().GetCurrentValue(); - const uint64_t max_send = m_max_send.GetOptionValue().GetCurrentValue(); - const uint64_t max_recv = m_max_recv.GetOptionValue().GetCurrentValue(); - const bool json = m_json.GetOptionValue().GetCurrentValue(); - if (output_stream_sp) - process->GetGDBRemote().TestPacketSpeed (num_packets, max_send, max_recv, json, *output_stream_sp); - else - { - process->GetGDBRemote().TestPacketSpeed (num_packets, max_send, max_recv, json, result.GetOutputStream()); - } - result.SetStatus (eReturnStatusSuccessFinishResult); - return true; - } - } - else - { - result.AppendErrorWithFormat ("'%s' takes no arguments", m_cmd_name.c_str()); - } - result.SetStatus (eReturnStatusFailed); - return false; - } protected: - OptionGroupOptions m_option_group; - OptionGroupUInt64 m_num_packets; - OptionGroupUInt64 m_max_send; - OptionGroupUInt64 m_max_recv; - OptionGroupBoolean m_json; - + OptionGroupOptions m_option_group; + OptionGroupUInt64 m_num_packets; + OptionGroupUInt64 m_max_send; + OptionGroupUInt64 m_max_recv; + OptionGroupBoolean m_json; }; -class CommandObjectProcessGDBRemotePacketHistory : public CommandObjectParsed -{ +class CommandObjectProcessGDBRemotePacketHistory : public CommandObjectParsed { private: - public: - CommandObjectProcessGDBRemotePacketHistory(CommandInterpreter &interpreter) : - CommandObjectParsed (interpreter, - "process plugin packet history", - "Dumps the packet history buffer. ", - NULL) - { - } - - ~CommandObjectProcessGDBRemotePacketHistory () - { - } - - bool - DoExecute (Args& command, CommandReturnObject &result) override - { - const size_t argc = command.GetArgumentCount(); - if (argc == 0) - { - ProcessGDBRemote *process = (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr(); - if (process) - { - process->GetGDBRemote().DumpHistory(result.GetOutputStream()); - result.SetStatus (eReturnStatusSuccessFinishResult); - return true; - } - } - else - { - result.AppendErrorWithFormat ("'%s' takes no arguments", m_cmd_name.c_str()); - } - result.SetStatus (eReturnStatusFailed); - return false; + CommandObjectProcessGDBRemotePacketHistory(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "process plugin packet history", + "Dumps the packet history buffer. ", NULL) {} + + ~CommandObjectProcessGDBRemotePacketHistory() {} + + bool DoExecute(Args &command, CommandReturnObject &result) override { + const size_t argc = command.GetArgumentCount(); + if (argc == 0) { + ProcessGDBRemote *process = + (ProcessGDBRemote *)m_interpreter.GetExecutionContext() + .GetProcessPtr(); + if (process) { + process->GetGDBRemote().DumpHistory(result.GetOutputStream()); + result.SetStatus(eReturnStatusSuccessFinishResult); + return true; + } + } else { + result.AppendErrorWithFormat("'%s' takes no arguments", + m_cmd_name.c_str()); } + result.SetStatus(eReturnStatusFailed); + return false; + } }; -class CommandObjectProcessGDBRemotePacketXferSize : public CommandObjectParsed -{ +class CommandObjectProcessGDBRemotePacketXferSize : public CommandObjectParsed { private: - public: - CommandObjectProcessGDBRemotePacketXferSize(CommandInterpreter &interpreter) : - CommandObjectParsed (interpreter, - "process plugin packet xfer-size", - "Maximum size that lldb will try to read/write one one chunk.", - NULL) - { - } - - ~CommandObjectProcessGDBRemotePacketXferSize () - { - } - - bool - DoExecute (Args& command, CommandReturnObject &result) override - { - const size_t argc = command.GetArgumentCount(); - if (argc == 0) - { - result.AppendErrorWithFormat ("'%s' takes an argument to specify the max amount to be transferred when reading/writing", m_cmd_name.c_str()); - result.SetStatus (eReturnStatusFailed); - return false; - } - - ProcessGDBRemote *process = (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr(); - if (process) - { - const char *packet_size = command.GetArgumentAtIndex(0); - errno = 0; - uint64_t user_specified_max = strtoul (packet_size, NULL, 10); - if (errno == 0 && user_specified_max != 0) - { - process->SetUserSpecifiedMaxMemoryTransferSize (user_specified_max); - result.SetStatus (eReturnStatusSuccessFinishResult); - return true; - } - } - result.SetStatus (eReturnStatusFailed); - return false; + CommandObjectProcessGDBRemotePacketXferSize(CommandInterpreter &interpreter) + : CommandObjectParsed( + interpreter, "process plugin packet xfer-size", + "Maximum size that lldb will try to read/write one one chunk.", + NULL) {} + + ~CommandObjectProcessGDBRemotePacketXferSize() {} + + bool DoExecute(Args &command, CommandReturnObject &result) override { + const size_t argc = command.GetArgumentCount(); + if (argc == 0) { + result.AppendErrorWithFormat("'%s' takes an argument to specify the max " + "amount to be transferred when " + "reading/writing", + m_cmd_name.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + + ProcessGDBRemote *process = + (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr(); + if (process) { + const char *packet_size = command.GetArgumentAtIndex(0); + errno = 0; + uint64_t user_specified_max = strtoul(packet_size, NULL, 10); + if (errno == 0 && user_specified_max != 0) { + process->SetUserSpecifiedMaxMemoryTransferSize(user_specified_max); + result.SetStatus(eReturnStatusSuccessFinishResult); + return true; + } } + result.SetStatus(eReturnStatusFailed); + return false; + } }; - -class CommandObjectProcessGDBRemotePacketSend : public CommandObjectParsed -{ +class CommandObjectProcessGDBRemotePacketSend : public CommandObjectParsed { private: - public: - CommandObjectProcessGDBRemotePacketSend(CommandInterpreter &interpreter) : - CommandObjectParsed (interpreter, - "process plugin packet send", - "Send a custom packet through the GDB remote protocol and print the answer. " - "The packet header and footer will automatically be added to the packet prior to sending and stripped from the result.", - NULL) - { - } - - ~CommandObjectProcessGDBRemotePacketSend () - { - } - - bool - DoExecute (Args& command, CommandReturnObject &result) override - { - const size_t argc = command.GetArgumentCount(); - if (argc == 0) - { - result.AppendErrorWithFormat ("'%s' takes a one or more packet content arguments", m_cmd_name.c_str()); - result.SetStatus (eReturnStatusFailed); - return false; + CommandObjectProcessGDBRemotePacketSend(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "process plugin packet send", + "Send a custom packet through the GDB remote " + "protocol and print the answer. " + "The packet header and footer will automatically " + "be added to the packet prior to sending and " + "stripped from the result.", + NULL) {} + + ~CommandObjectProcessGDBRemotePacketSend() {} + + bool DoExecute(Args &command, CommandReturnObject &result) override { + const size_t argc = command.GetArgumentCount(); + if (argc == 0) { + result.AppendErrorWithFormat( + "'%s' takes a one or more packet content arguments", + m_cmd_name.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + + ProcessGDBRemote *process = + (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr(); + if (process) { + for (size_t i = 0; i < argc; ++i) { + const char *packet_cstr = command.GetArgumentAtIndex(0); + bool send_async = true; + StringExtractorGDBRemote response; + process->GetGDBRemote().SendPacketAndWaitForResponse( + packet_cstr, response, send_async); + result.SetStatus(eReturnStatusSuccessFinishResult); + Stream &output_strm = result.GetOutputStream(); + output_strm.Printf(" packet: %s\n", packet_cstr); + std::string &response_str = response.GetStringRef(); + + if (strstr(packet_cstr, "qGetProfileData") != NULL) { + response_str = process->HarmonizeThreadIdsForProfileData(response); } - ProcessGDBRemote *process = (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr(); - if (process) - { - for (size_t i=0; i<argc; ++ i) - { - const char *packet_cstr = command.GetArgumentAtIndex(0); - bool send_async = true; - StringExtractorGDBRemote response; - process->GetGDBRemote().SendPacketAndWaitForResponse(packet_cstr, response, send_async); - result.SetStatus (eReturnStatusSuccessFinishResult); - Stream &output_strm = result.GetOutputStream(); - output_strm.Printf (" packet: %s\n", packet_cstr); - std::string &response_str = response.GetStringRef(); - - if (strstr(packet_cstr, "qGetProfileData") != NULL) - { - response_str = process->GetGDBRemote().HarmonizeThreadIdsForProfileData(process, response); - } - - if (response_str.empty()) - output_strm.PutCString ("response: \nerror: UNIMPLEMENTED\n"); - else - output_strm.Printf ("response: %s\n", response.GetStringRef().c_str()); - } - } - return true; + if (response_str.empty()) + output_strm.PutCString("response: \nerror: UNIMPLEMENTED\n"); + else + output_strm.Printf("response: %s\n", response.GetStringRef().c_str()); + } } + return true; + } }; -class CommandObjectProcessGDBRemotePacketMonitor : public CommandObjectRaw -{ +class CommandObjectProcessGDBRemotePacketMonitor : public CommandObjectRaw { private: - public: - CommandObjectProcessGDBRemotePacketMonitor(CommandInterpreter &interpreter) : - CommandObjectRaw (interpreter, - "process plugin packet monitor", - "Send a qRcmd packet through the GDB remote protocol and print the response." - "The argument passed to this command will be hex encoded into a valid 'qRcmd' packet, sent and the response will be printed.", - NULL) - { - } - - ~CommandObjectProcessGDBRemotePacketMonitor () - { - } - - bool - DoExecute (const char *command, CommandReturnObject &result) override - { - if (command == NULL || command[0] == '\0') - { - result.AppendErrorWithFormat ("'%s' takes a command string argument", m_cmd_name.c_str()); - result.SetStatus (eReturnStatusFailed); - return false; - } - - ProcessGDBRemote *process = (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr(); - if (process) - { - StreamString packet; - packet.PutCString("qRcmd,"); - packet.PutBytesAsRawHex8(command, strlen(command)); - const char *packet_cstr = packet.GetString().c_str(); - - bool send_async = true; - StringExtractorGDBRemote response; - process->GetGDBRemote().SendPacketAndWaitForResponse(packet_cstr, response, send_async); - result.SetStatus (eReturnStatusSuccessFinishResult); - Stream &output_strm = result.GetOutputStream(); - output_strm.Printf (" packet: %s\n", packet_cstr); - const std::string &response_str = response.GetStringRef(); - - if (response_str.empty()) - output_strm.PutCString ("response: \nerror: UNIMPLEMENTED\n"); - else - output_strm.Printf ("response: %s\n", response.GetStringRef().c_str()); - } - return true; + CommandObjectProcessGDBRemotePacketMonitor(CommandInterpreter &interpreter) + : CommandObjectRaw(interpreter, "process plugin packet monitor", + "Send a qRcmd packet through the GDB remote protocol " + "and print the response." + "The argument passed to this command will be hex " + "encoded into a valid 'qRcmd' packet, sent and the " + "response will be printed.") {} + + ~CommandObjectProcessGDBRemotePacketMonitor() {} + + bool DoExecute(const char *command, CommandReturnObject &result) override { + if (command == NULL || command[0] == '\0') { + result.AppendErrorWithFormat("'%s' takes a command string argument", + m_cmd_name.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + + ProcessGDBRemote *process = + (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr(); + if (process) { + StreamString packet; + packet.PutCString("qRcmd,"); + packet.PutBytesAsRawHex8(command, strlen(command)); + + bool send_async = true; + StringExtractorGDBRemote response; + process->GetGDBRemote().SendPacketAndWaitForResponse( + packet.GetString(), response, send_async); + result.SetStatus(eReturnStatusSuccessFinishResult); + Stream &output_strm = result.GetOutputStream(); + output_strm.Printf(" packet: %s\n", packet.GetData()); + const std::string &response_str = response.GetStringRef(); + + if (response_str.empty()) + output_strm.PutCString("response: \nerror: UNIMPLEMENTED\n"); + else + output_strm.Printf("response: %s\n", response.GetStringRef().c_str()); } + return true; + } }; -class CommandObjectProcessGDBRemotePacket : public CommandObjectMultiword -{ +class CommandObjectProcessGDBRemotePacket : public CommandObjectMultiword { private: - public: - CommandObjectProcessGDBRemotePacket(CommandInterpreter &interpreter) : - CommandObjectMultiword (interpreter, - "process plugin packet", - "Commands that deal with GDB remote packets.", - NULL) - { - LoadSubCommand ("history", CommandObjectSP (new CommandObjectProcessGDBRemotePacketHistory (interpreter))); - LoadSubCommand ("send", CommandObjectSP (new CommandObjectProcessGDBRemotePacketSend (interpreter))); - LoadSubCommand ("monitor", CommandObjectSP (new CommandObjectProcessGDBRemotePacketMonitor (interpreter))); - LoadSubCommand ("xfer-size", CommandObjectSP (new CommandObjectProcessGDBRemotePacketXferSize (interpreter))); - LoadSubCommand ("speed-test", CommandObjectSP (new CommandObjectProcessGDBRemoteSpeedTest (interpreter))); - } - - ~CommandObjectProcessGDBRemotePacket () - { - } + CommandObjectProcessGDBRemotePacket(CommandInterpreter &interpreter) + : CommandObjectMultiword(interpreter, "process plugin packet", + "Commands that deal with GDB remote packets.", + NULL) { + LoadSubCommand( + "history", + CommandObjectSP( + new CommandObjectProcessGDBRemotePacketHistory(interpreter))); + LoadSubCommand( + "send", CommandObjectSP( + new CommandObjectProcessGDBRemotePacketSend(interpreter))); + LoadSubCommand( + "monitor", + CommandObjectSP( + new CommandObjectProcessGDBRemotePacketMonitor(interpreter))); + LoadSubCommand( + "xfer-size", + CommandObjectSP( + new CommandObjectProcessGDBRemotePacketXferSize(interpreter))); + LoadSubCommand("speed-test", + CommandObjectSP(new CommandObjectProcessGDBRemoteSpeedTest( + interpreter))); + } + + ~CommandObjectProcessGDBRemotePacket() {} }; -class CommandObjectMultiwordProcessGDBRemote : public CommandObjectMultiword -{ +class CommandObjectMultiwordProcessGDBRemote : public CommandObjectMultiword { public: - CommandObjectMultiwordProcessGDBRemote(CommandInterpreter &interpreter) - : CommandObjectMultiword(interpreter, "process plugin", "Commands for operating on a ProcessGDBRemote process.", - "process plugin <subcommand> [<subcommand-options>]") - { - LoadSubCommand ("packet", CommandObjectSP (new CommandObjectProcessGDBRemotePacket (interpreter))); - } - - ~CommandObjectMultiwordProcessGDBRemote () - { - } + CommandObjectMultiwordProcessGDBRemote(CommandInterpreter &interpreter) + : CommandObjectMultiword( + interpreter, "process plugin", + "Commands for operating on a ProcessGDBRemote process.", + "process plugin <subcommand> [<subcommand-options>]") { + LoadSubCommand( + "packet", + CommandObjectSP(new CommandObjectProcessGDBRemotePacket(interpreter))); + } + + ~CommandObjectMultiwordProcessGDBRemote() {} }; -CommandObject * -ProcessGDBRemote::GetPluginCommandObject() -{ - if (!m_command_sp) - m_command_sp.reset (new CommandObjectMultiwordProcessGDBRemote (GetTarget().GetDebugger().GetCommandInterpreter())); - return m_command_sp.get(); +CommandObject *ProcessGDBRemote::GetPluginCommandObject() { + if (!m_command_sp) + m_command_sp.reset(new CommandObjectMultiwordProcessGDBRemote( + GetTarget().GetDebugger().GetCommandInterpreter())); + return m_command_sp.get(); } diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 6d37396..6423abc 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -24,462 +24,425 @@ #include "lldb/Core/Broadcaster.h" #include "lldb/Core/ConstString.h" #include "lldb/Core/Error.h" +#include "lldb/Core/LoadedModuleInfoList.h" +#include "lldb/Core/ModuleSpec.h" #include "lldb/Core/StreamString.h" #include "lldb/Core/StringList.h" #include "lldb/Core/StructuredData.h" #include "lldb/Core/ThreadSafeValue.h" -#include "lldb/Core/LoadedModuleInfoList.h" #include "lldb/Host/HostThread.h" -#include "lldb/lldb-private-forward.h" -#include "lldb/Utility/StringExtractor.h" #include "lldb/Target/Process.h" #include "lldb/Target/Thread.h" +#include "lldb/Utility/StringExtractor.h" +#include "lldb/lldb-private-forward.h" #include "GDBRemoteCommunicationClient.h" #include "GDBRemoteRegisterContext.h" +#include "llvm/ADT/DenseMap.h" + namespace lldb_private { namespace process_gdb_remote { class ThreadGDBRemote; -class ProcessGDBRemote : public Process -{ +class ProcessGDBRemote : public Process, + private GDBRemoteClientBase::ContinueDelegate { public: - ProcessGDBRemote(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp); + ProcessGDBRemote(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp); - ~ProcessGDBRemote() override; + ~ProcessGDBRemote() override; - static lldb::ProcessSP - CreateInstance (lldb::TargetSP target_sp, - lldb::ListenerSP listener_sp, - const FileSpec *crash_file_path); + static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp, + lldb::ListenerSP listener_sp, + const FileSpec *crash_file_path); - static void - Initialize(); + static void Initialize(); - static void - DebuggerInitialize (Debugger &debugger); + static void DebuggerInitialize(Debugger &debugger); - static void - Terminate(); + static void Terminate(); - static ConstString - GetPluginNameStatic(); + static ConstString GetPluginNameStatic(); - static const char * - GetPluginDescriptionStatic(); + static const char *GetPluginDescriptionStatic(); - //------------------------------------------------------------------ - // Check if a given Process - //------------------------------------------------------------------ - bool - CanDebug (lldb::TargetSP target_sp, bool plugin_specified_by_name) override; + //------------------------------------------------------------------ + // Check if a given Process + //------------------------------------------------------------------ + bool CanDebug(lldb::TargetSP target_sp, + bool plugin_specified_by_name) override; - CommandObject * - GetPluginCommandObject() override; + CommandObject *GetPluginCommandObject() override; - //------------------------------------------------------------------ - // Creating a new process, or attaching to an existing one - //------------------------------------------------------------------ - Error - WillLaunch (Module* module) override; + //------------------------------------------------------------------ + // Creating a new process, or attaching to an existing one + //------------------------------------------------------------------ + Error WillLaunch(Module *module) override; - Error - DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info) override; + Error DoLaunch(Module *exe_module, ProcessLaunchInfo &launch_info) override; - void - DidLaunch () override; - - Error - WillAttachToProcessWithID (lldb::pid_t pid) override; - - Error - WillAttachToProcessWithName (const char *process_name, bool wait_for_launch) override; + void DidLaunch() override; - Error - DoConnectRemote (Stream *strm, const char *remote_url) override; - - Error - WillLaunchOrAttach (); - - Error - DoAttachToProcessWithID (lldb::pid_t pid, const ProcessAttachInfo &attach_info) override; - - Error - DoAttachToProcessWithName (const char *process_name, - const ProcessAttachInfo &attach_info) override; - - void - DidAttach (ArchSpec &process_arch) override; - - //------------------------------------------------------------------ - // PluginInterface protocol - //------------------------------------------------------------------ - ConstString - GetPluginName() override; - - uint32_t - GetPluginVersion() override; - - //------------------------------------------------------------------ - // Process Control - //------------------------------------------------------------------ - Error - WillResume () override; - - Error - DoResume () override; - - Error - DoHalt (bool &caused_stop) override; - - Error - DoDetach (bool keep_stopped) override; - - bool - DetachRequiresHalt() override { return true; } - - Error - DoSignal (int signal) override; - - Error - DoDestroy () override; - - void - RefreshStateAfterStop() override; - - void - SetUnixSignals(const lldb::UnixSignalsSP &signals_sp); - - //------------------------------------------------------------------ - // Process Queries - //------------------------------------------------------------------ - bool - IsAlive () override; - - lldb::addr_t - GetImageInfoAddress() override; - - void - WillPublicStop () override; - - //------------------------------------------------------------------ - // Process Memory - //------------------------------------------------------------------ - size_t - DoReadMemory (lldb::addr_t addr, void *buf, size_t size, Error &error) override; - - size_t - DoWriteMemory (lldb::addr_t addr, const void *buf, size_t size, Error &error) override; - - lldb::addr_t - DoAllocateMemory (size_t size, uint32_t permissions, Error &error) override; - - Error - GetMemoryRegionInfo (lldb::addr_t load_addr, MemoryRegionInfo ®ion_info) override; - - Error - DoDeallocateMemory (lldb::addr_t ptr) override; - - //------------------------------------------------------------------ - // Process STDIO - //------------------------------------------------------------------ - size_t - PutSTDIN (const char *buf, size_t buf_size, Error &error) override; - - //---------------------------------------------------------------------- - // Process Breakpoints - //---------------------------------------------------------------------- - Error - EnableBreakpointSite (BreakpointSite *bp_site) override; - - Error - DisableBreakpointSite (BreakpointSite *bp_site) override; - - //---------------------------------------------------------------------- - // Process Watchpoints - //---------------------------------------------------------------------- - Error - EnableWatchpoint (Watchpoint *wp, bool notify = true) override; - - Error - DisableWatchpoint (Watchpoint *wp, bool notify = true) override; - - Error - GetWatchpointSupportInfo (uint32_t &num) override; - - Error - GetWatchpointSupportInfo (uint32_t &num, bool& after) override; - - bool - StartNoticingNewThreads() override; - - bool - StopNoticingNewThreads() override; - - GDBRemoteCommunicationClient & - GetGDBRemote() - { - return m_gdb_comm; - } - - Error - SendEventData(const char *data) override; + Error WillAttachToProcessWithID(lldb::pid_t pid) override; + + Error WillAttachToProcessWithName(const char *process_name, + bool wait_for_launch) override; + + Error DoConnectRemote(Stream *strm, llvm::StringRef remote_url) override; + + Error WillLaunchOrAttach(); + + Error DoAttachToProcessWithID(lldb::pid_t pid, + const ProcessAttachInfo &attach_info) override; + + Error + DoAttachToProcessWithName(const char *process_name, + const ProcessAttachInfo &attach_info) override; + + void DidAttach(ArchSpec &process_arch) override; + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + ConstString GetPluginName() override; + + uint32_t GetPluginVersion() override; + + //------------------------------------------------------------------ + // Process Control + //------------------------------------------------------------------ + Error WillResume() override; + + Error DoResume() override; + + Error DoHalt(bool &caused_stop) override; + + Error DoDetach(bool keep_stopped) override; + + bool DetachRequiresHalt() override { return true; } + + Error DoSignal(int signal) override; + + Error DoDestroy() override; + + void RefreshStateAfterStop() override; + + void SetUnixSignals(const lldb::UnixSignalsSP &signals_sp); + + //------------------------------------------------------------------ + // Process Queries + //------------------------------------------------------------------ + bool IsAlive() override; + + lldb::addr_t GetImageInfoAddress() override; + + void WillPublicStop() override; + + //------------------------------------------------------------------ + // Process Memory + //------------------------------------------------------------------ + size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size, + Error &error) override; + + size_t DoWriteMemory(lldb::addr_t addr, const void *buf, size_t size, + Error &error) override; + + lldb::addr_t DoAllocateMemory(size_t size, uint32_t permissions, + Error &error) override; + + Error GetMemoryRegionInfo(lldb::addr_t load_addr, + MemoryRegionInfo ®ion_info) override; - //---------------------------------------------------------------------- - // Override DidExit so we can disconnect from the remote GDB server - //---------------------------------------------------------------------- - void - DidExit () override; + Error DoDeallocateMemory(lldb::addr_t ptr) override; - void - SetUserSpecifiedMaxMemoryTransferSize (uint64_t user_specified_max); + //------------------------------------------------------------------ + // Process STDIO + //------------------------------------------------------------------ + size_t PutSTDIN(const char *buf, size_t buf_size, Error &error) override; - bool - GetModuleSpec(const FileSpec& module_file_spec, - const ArchSpec& arch, - ModuleSpec &module_spec) override; + //---------------------------------------------------------------------- + // Process Breakpoints + //---------------------------------------------------------------------- + Error EnableBreakpointSite(BreakpointSite *bp_site) override; - bool - GetHostOSVersion(uint32_t &major, - uint32_t &minor, - uint32_t &update) override; + Error DisableBreakpointSite(BreakpointSite *bp_site) override; - size_t - LoadModules(LoadedModuleInfoList &module_list) override; + //---------------------------------------------------------------------- + // Process Watchpoints + //---------------------------------------------------------------------- + Error EnableWatchpoint(Watchpoint *wp, bool notify = true) override; - size_t - LoadModules() override; + Error DisableWatchpoint(Watchpoint *wp, bool notify = true) override; - Error - GetFileLoadAddress(const FileSpec& file, bool& is_loaded, lldb::addr_t& load_addr) override; + Error GetWatchpointSupportInfo(uint32_t &num) override; - void - ModulesDidLoad (ModuleList &module_list) override; + Error GetWatchpointSupportInfo(uint32_t &num, bool &after) override; - StructuredData::ObjectSP - GetLoadedDynamicLibrariesInfos (lldb::addr_t image_list_address, lldb::addr_t image_count) override; + bool StartNoticingNewThreads() override; + + bool StopNoticingNewThreads() override; + + GDBRemoteCommunicationClient &GetGDBRemote() { return m_gdb_comm; } + + Error SendEventData(const char *data) override; + + //---------------------------------------------------------------------- + // Override DidExit so we can disconnect from the remote GDB server + //---------------------------------------------------------------------- + void DidExit() override; + + void SetUserSpecifiedMaxMemoryTransferSize(uint64_t user_specified_max); + + bool GetModuleSpec(const FileSpec &module_file_spec, const ArchSpec &arch, + ModuleSpec &module_spec) override; + + void PrefetchModuleSpecs(llvm::ArrayRef<FileSpec> module_file_specs, + const llvm::Triple &triple) override; + + bool GetHostOSVersion(uint32_t &major, uint32_t &minor, + uint32_t &update) override; + + size_t LoadModules(LoadedModuleInfoList &module_list) override; + + size_t LoadModules() override; + + Error GetFileLoadAddress(const FileSpec &file, bool &is_loaded, + lldb::addr_t &load_addr) override; + + void ModulesDidLoad(ModuleList &module_list) override; + + StructuredData::ObjectSP + GetLoadedDynamicLibrariesInfos(lldb::addr_t image_list_address, + lldb::addr_t image_count) override; + + Error + ConfigureStructuredData(const ConstString &type_name, + const StructuredData::ObjectSP &config_sp) override; + + StructuredData::ObjectSP GetLoadedDynamicLibrariesInfos() override; + + StructuredData::ObjectSP GetLoadedDynamicLibrariesInfos( + const std::vector<lldb::addr_t> &load_addresses) override; + + StructuredData::ObjectSP + GetLoadedDynamicLibrariesInfos_sender(StructuredData::ObjectSP args); + + StructuredData::ObjectSP GetSharedCacheInfo() override; + + std::string HarmonizeThreadIdsForProfileData( + StringExtractorGDBRemote &inputStringExtractor); protected: - friend class ThreadGDBRemote; - friend class GDBRemoteCommunicationClient; - friend class GDBRemoteRegisterContext; - - //------------------------------------------------------------------ - /// Broadcaster event bits definitions. - //------------------------------------------------------------------ - enum - { - eBroadcastBitAsyncContinue = (1 << 0), - eBroadcastBitAsyncThreadShouldExit = (1 << 1), - eBroadcastBitAsyncThreadDidExit = (1 << 2) - }; - - Flags m_flags; // Process specific flags (see eFlags enums) - GDBRemoteCommunicationClient m_gdb_comm; - std::atomic<lldb::pid_t> m_debugserver_pid; - std::vector<StringExtractorGDBRemote> m_stop_packet_stack; // The stop packet stack replaces the last stop packet variable - std::recursive_mutex m_last_stop_packet_mutex; - GDBRemoteDynamicRegisterInfo m_register_info; - Broadcaster m_async_broadcaster; - lldb::ListenerSP m_async_listener_sp; - HostThread m_async_thread; - std::recursive_mutex m_async_thread_state_mutex; - typedef std::vector<lldb::tid_t> tid_collection; - typedef std::vector< std::pair<lldb::tid_t,int> > tid_sig_collection; - typedef std::map<lldb::addr_t, lldb::addr_t> MMapMap; - typedef std::map<uint32_t, std::string> ExpeditedRegisterMap; - tid_collection m_thread_ids; // Thread IDs for all threads. This list gets updated after stopping - std::vector<lldb::addr_t> m_thread_pcs; // PC values for all the threads. - StructuredData::ObjectSP m_jstopinfo_sp; // Stop info only for any threads that have valid stop infos - StructuredData::ObjectSP m_jthreadsinfo_sp; // Full stop info, expedited registers and memory for all threads if "jThreadsInfo" packet is supported - tid_collection m_continue_c_tids; // 'c' for continue - tid_sig_collection m_continue_C_tids; // 'C' for continue with signal - tid_collection m_continue_s_tids; // 's' for step - tid_sig_collection m_continue_S_tids; // 'S' for step with signal - uint64_t m_max_memory_size; // The maximum number of bytes to read/write when reading and writing memory - uint64_t m_remote_stub_max_memory_size; // The maximum memory size the remote gdb stub can handle - MMapMap m_addr_to_mmap_size; - lldb::BreakpointSP m_thread_create_bp_sp; - bool m_waiting_for_attach; - bool m_destroy_tried_resuming; - lldb::CommandObjectSP m_command_sp; - int64_t m_breakpoint_pc_offset; - lldb::tid_t m_initial_tid; // The initial thread ID, given by stub on attach - - //---------------------------------------------------------------------- - // Accessors - //---------------------------------------------------------------------- - bool - IsRunning ( lldb::StateType state ) - { - return state == lldb::eStateRunning || IsStepping(state); - } + friend class ThreadGDBRemote; + friend class GDBRemoteCommunicationClient; + friend class GDBRemoteRegisterContext; + + //------------------------------------------------------------------ + /// Broadcaster event bits definitions. + //------------------------------------------------------------------ + enum { + eBroadcastBitAsyncContinue = (1 << 0), + eBroadcastBitAsyncThreadShouldExit = (1 << 1), + eBroadcastBitAsyncThreadDidExit = (1 << 2) + }; - bool - IsStepping ( lldb::StateType state) - { - return state == lldb::eStateStepping; - } + Flags m_flags; // Process specific flags (see eFlags enums) + GDBRemoteCommunicationClient m_gdb_comm; + std::atomic<lldb::pid_t> m_debugserver_pid; + std::vector<StringExtractorGDBRemote> m_stop_packet_stack; // The stop packet + // stack replaces + // the last stop + // packet variable + std::recursive_mutex m_last_stop_packet_mutex; + GDBRemoteDynamicRegisterInfo m_register_info; + Broadcaster m_async_broadcaster; + lldb::ListenerSP m_async_listener_sp; + HostThread m_async_thread; + std::recursive_mutex m_async_thread_state_mutex; + typedef std::vector<lldb::tid_t> tid_collection; + typedef std::vector<std::pair<lldb::tid_t, int>> tid_sig_collection; + typedef std::map<lldb::addr_t, lldb::addr_t> MMapMap; + typedef std::map<uint32_t, std::string> ExpeditedRegisterMap; + tid_collection m_thread_ids; // Thread IDs for all threads. This list gets + // updated after stopping + std::vector<lldb::addr_t> m_thread_pcs; // PC values for all the threads. + StructuredData::ObjectSP m_jstopinfo_sp; // Stop info only for any threads + // that have valid stop infos + StructuredData::ObjectSP m_jthreadsinfo_sp; // Full stop info, expedited + // registers and memory for all + // threads if "jThreadsInfo" + // packet is supported + tid_collection m_continue_c_tids; // 'c' for continue + tid_sig_collection m_continue_C_tids; // 'C' for continue with signal + tid_collection m_continue_s_tids; // 's' for step + tid_sig_collection m_continue_S_tids; // 'S' for step with signal + uint64_t m_max_memory_size; // The maximum number of bytes to read/write when + // reading and writing memory + uint64_t m_remote_stub_max_memory_size; // The maximum memory size the remote + // gdb stub can handle + MMapMap m_addr_to_mmap_size; + lldb::BreakpointSP m_thread_create_bp_sp; + bool m_waiting_for_attach; + bool m_destroy_tried_resuming; + lldb::CommandObjectSP m_command_sp; + int64_t m_breakpoint_pc_offset; + lldb::tid_t m_initial_tid; // The initial thread ID, given by stub on attach - bool - CanResume ( lldb::StateType state) - { - return state == lldb::eStateStopped; - } + //---------------------------------------------------------------------- + // Accessors + //---------------------------------------------------------------------- + bool IsRunning(lldb::StateType state) { + return state == lldb::eStateRunning || IsStepping(state); + } - bool - HasExited (lldb::StateType state) - { - return state == lldb::eStateExited; - } + bool IsStepping(lldb::StateType state) { + return state == lldb::eStateStepping; + } - bool - ProcessIDIsValid ( ) const; + bool CanResume(lldb::StateType state) { return state == lldb::eStateStopped; } - void - Clear ( ); + bool HasExited(lldb::StateType state) { return state == lldb::eStateExited; } - Flags & - GetFlags () - { - return m_flags; - } + bool ProcessIDIsValid() const; - const Flags & - GetFlags () const - { - return m_flags; - } + void Clear(); + + Flags &GetFlags() { return m_flags; } - bool - UpdateThreadList (ThreadList &old_thread_list, - ThreadList &new_thread_list) override; + const Flags &GetFlags() const { return m_flags; } - Error - EstablishConnectionIfNeeded (const ProcessInfo &process_info); + bool UpdateThreadList(ThreadList &old_thread_list, + ThreadList &new_thread_list) override; - Error - LaunchAndConnectToDebugserver (const ProcessInfo &process_info); + Error EstablishConnectionIfNeeded(const ProcessInfo &process_info); - void - KillDebugserverProcess (); + Error LaunchAndConnectToDebugserver(const ProcessInfo &process_info); - void - BuildDynamicRegisterInfo (bool force); + void KillDebugserverProcess(); - void - SetLastStopPacket (const StringExtractorGDBRemote &response); + void BuildDynamicRegisterInfo(bool force); - bool - ParsePythonTargetDefinition(const FileSpec &target_definition_fspec); + void SetLastStopPacket(const StringExtractorGDBRemote &response); - const lldb::DataBufferSP - GetAuxvData() override; + bool ParsePythonTargetDefinition(const FileSpec &target_definition_fspec); - StructuredData::ObjectSP - GetExtendedInfoForThread (lldb::tid_t tid); + const lldb::DataBufferSP GetAuxvData() override; - void - GetMaxMemorySize(); + StructuredData::ObjectSP GetExtendedInfoForThread(lldb::tid_t tid); - bool - CalculateThreadStopInfo (ThreadGDBRemote *thread); + void GetMaxMemorySize(); - size_t - UpdateThreadPCsFromStopReplyThreadsValue (std::string &value); + bool CalculateThreadStopInfo(ThreadGDBRemote *thread); - size_t - UpdateThreadIDsFromStopReplyThreadsValue (std::string &value); + size_t UpdateThreadPCsFromStopReplyThreadsValue(std::string &value); - bool - HandleNotifyPacket(StringExtractorGDBRemote &packet); + size_t UpdateThreadIDsFromStopReplyThreadsValue(std::string &value); - bool - StartAsyncThread (); + bool HandleNotifyPacket(StringExtractorGDBRemote &packet); - void - StopAsyncThread (); + bool StartAsyncThread(); - static lldb::thread_result_t - AsyncThread (void *arg); + void StopAsyncThread(); - static bool - MonitorDebugserverProcess(std::weak_ptr<ProcessGDBRemote> process_wp, lldb::pid_t pid, bool exited, int signo, - int exit_status); + static lldb::thread_result_t AsyncThread(void *arg); - lldb::StateType - SetThreadStopInfo (StringExtractor& stop_packet); + static bool + MonitorDebugserverProcess(std::weak_ptr<ProcessGDBRemote> process_wp, + lldb::pid_t pid, bool exited, int signo, + int exit_status); - bool - GetThreadStopInfoFromJSON (ThreadGDBRemote *thread, const StructuredData::ObjectSP &thread_infos_sp); + lldb::StateType SetThreadStopInfo(StringExtractor &stop_packet); - lldb::ThreadSP - SetThreadStopInfo (StructuredData::Dictionary *thread_dict); + bool + GetThreadStopInfoFromJSON(ThreadGDBRemote *thread, + const StructuredData::ObjectSP &thread_infos_sp); - lldb::ThreadSP - SetThreadStopInfo (lldb::tid_t tid, - ExpeditedRegisterMap &expedited_register_map, - uint8_t signo, - const std::string &thread_name, - const std::string &reason, - const std::string &description, - uint32_t exc_type, - const std::vector<lldb::addr_t> &exc_data, - lldb::addr_t thread_dispatch_qaddr, - bool queue_vars_valid, - lldb_private::LazyBool associated_with_libdispatch_queue, - lldb::addr_t dispatch_queue_t, - std::string &queue_name, - lldb::QueueKind queue_kind, - uint64_t queue_serial); + lldb::ThreadSP SetThreadStopInfo(StructuredData::Dictionary *thread_dict); - void - HandleStopReplySequence (); + lldb::ThreadSP + SetThreadStopInfo(lldb::tid_t tid, + ExpeditedRegisterMap &expedited_register_map, uint8_t signo, + const std::string &thread_name, const std::string &reason, + const std::string &description, uint32_t exc_type, + const std::vector<lldb::addr_t> &exc_data, + lldb::addr_t thread_dispatch_qaddr, bool queue_vars_valid, + lldb_private::LazyBool associated_with_libdispatch_queue, + lldb::addr_t dispatch_queue_t, std::string &queue_name, + lldb::QueueKind queue_kind, uint64_t queue_serial); - void - ClearThreadIDList (); + void HandleStopReplySequence(); - bool - UpdateThreadIDList (); + void ClearThreadIDList(); - void - DidLaunchOrAttach (ArchSpec& process_arch); + bool UpdateThreadIDList(); - Error - ConnectToDebugserver (const char *host_port); + void DidLaunchOrAttach(ArchSpec &process_arch); - const char * - GetDispatchQueueNameForThread (lldb::addr_t thread_dispatch_qaddr, - std::string &dispatch_queue_name); + Error ConnectToDebugserver(llvm::StringRef host_port); - DynamicLoader * - GetDynamicLoader () override; + const char *GetDispatchQueueNameForThread(lldb::addr_t thread_dispatch_qaddr, + std::string &dispatch_queue_name); - // Query remote GDBServer for register information - bool - GetGDBServerRegisterInfo (ArchSpec &arch); + DynamicLoader *GetDynamicLoader() override; - // Query remote GDBServer for a detailed loaded library list - Error - GetLoadedModuleList (LoadedModuleInfoList &); + // Query remote GDBServer for register information + bool GetGDBServerRegisterInfo(ArchSpec &arch); - lldb::ModuleSP - LoadModuleAtAddress (const FileSpec &file, lldb::addr_t link_map, lldb::addr_t base_addr, - bool value_is_offset); + // Query remote GDBServer for a detailed loaded library list + Error GetLoadedModuleList(LoadedModuleInfoList &); + + lldb::ModuleSP LoadModuleAtAddress(const FileSpec &file, + lldb::addr_t link_map, + lldb::addr_t base_addr, + bool value_is_offset); private: - //------------------------------------------------------------------ - // For ProcessGDBRemote only - //------------------------------------------------------------------ - static bool - NewThreadNotifyBreakpointHit (void *baton, - StoppointCallbackContext *context, - lldb::user_id_t break_id, - lldb::user_id_t break_loc_id); - - DISALLOW_COPY_AND_ASSIGN (ProcessGDBRemote); + //------------------------------------------------------------------ + // For ProcessGDBRemote only + //------------------------------------------------------------------ + std::string m_partial_profile_data; + std::map<uint64_t, uint32_t> m_thread_id_to_used_usec_map; + + static bool NewThreadNotifyBreakpointHit(void *baton, + StoppointCallbackContext *context, + lldb::user_id_t break_id, + lldb::user_id_t break_loc_id); + + //------------------------------------------------------------------ + // ContinueDelegate interface + //------------------------------------------------------------------ + void HandleAsyncStdout(llvm::StringRef out) override; + void HandleAsyncMisc(llvm::StringRef data) override; + void HandleStopReply() override; + void HandleAsyncStructuredDataPacket(llvm::StringRef data) override; + + using ModuleCacheKey = std::pair<std::string, std::string>; + // KeyInfo for the cached module spec DenseMap. + // The invariant is that all real keys will have the file and architecture + // set. + // The empty key has an empty file and an empty arch. + // The tombstone key has an invalid arch and an empty file. + // The comparison and hash functions take the file name and architecture + // triple into account. + struct ModuleCacheInfo { + static ModuleCacheKey getEmptyKey() { return ModuleCacheKey(); } + + static ModuleCacheKey getTombstoneKey() { return ModuleCacheKey("", "T"); } + + static unsigned getHashValue(const ModuleCacheKey &key) { + return llvm::hash_combine(key.first, key.second); + } + + static bool isEqual(const ModuleCacheKey &LHS, const ModuleCacheKey &RHS) { + return LHS == RHS; + } + }; + + llvm::DenseMap<ModuleCacheKey, ModuleSpec, ModuleCacheInfo> + m_cached_module_specs; + + DISALLOW_COPY_AND_ASSIGN(ProcessGDBRemote); }; } // namespace process_gdb_remote diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp index d4726ad..899037a 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp @@ -11,8 +11,8 @@ #include <mutex> -#include "lldb/Interpreter/Args.h" #include "lldb/Core/StreamFile.h" +#include "lldb/Interpreter/Args.h" #include "ProcessGDBRemote.h" @@ -20,196 +20,198 @@ using namespace lldb; using namespace lldb_private; using namespace lldb_private::process_gdb_remote; - // We want to avoid global constructors where code needs to be run so here we // control access to our static g_log_sp by hiding it in a singleton function -// that will construct the static g_lob_sp the first time this function is +// that will construct the static g_lob_sp the first time this function is // called. static bool g_log_enabled = false; -static Log * g_log = NULL; -static Log * -GetLog () -{ - if (!g_log_enabled) - return NULL; - return g_log; +static Log *g_log = NULL; +static Log *GetLog() { + if (!g_log_enabled) + return NULL; + return g_log; } -void -ProcessGDBRemoteLog::Initialize() -{ - static ConstString g_name("gdb-remote"); - static std::once_flag g_once_flag; - - std::call_once(g_once_flag, [](){ - Log::Callbacks log_callbacks = { - DisableLog, - EnableLog, - ListLogCategories - }; - - Log::RegisterLogChannel (g_name, log_callbacks); - }); -} +void ProcessGDBRemoteLog::Initialize() { + static ConstString g_name("gdb-remote"); + static std::once_flag g_once_flag; -Log * -ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (uint32_t mask) -{ - Log *log(GetLog ()); - if (log && mask) - { - uint32_t log_mask = log->GetMask().Get(); - if ((log_mask & mask) != mask) - return NULL; - } - return log; + std::call_once(g_once_flag, []() { + Log::Callbacks log_callbacks = {DisableLog, EnableLog, ListLogCategories}; + + Log::RegisterLogChannel(g_name, log_callbacks); + }); } -Log * -ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (uint32_t mask) -{ - Log *log(GetLog ()); - if (log && log->GetMask().Get() & mask) - return log; - return NULL; +Log *ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(uint32_t mask) { + Log *log(GetLog()); + if (log && mask) { + uint32_t log_mask = log->GetMask().Get(); + if ((log_mask & mask) != mask) + return NULL; + } + return log; } -void -ProcessGDBRemoteLog::DisableLog (const char **categories, Stream *feedback_strm) -{ - Log *log (GetLog ()); - if (log) - { - uint32_t flag_bits = 0; - - if (categories[0] != NULL) - { - flag_bits = log->GetMask().Get(); - for (size_t i = 0; categories[i] != NULL; ++i) - { - const char *arg = categories[i]; - - - if (::strcasecmp (arg, "all") == 0 ) flag_bits &= ~GDBR_LOG_ALL; - else if (::strcasecmp (arg, "async") == 0 ) flag_bits &= ~GDBR_LOG_ASYNC; - else if (::strncasecmp (arg, "break", 5) == 0 ) flag_bits &= ~GDBR_LOG_BREAKPOINTS; - else if (::strncasecmp (arg, "comm", 4) == 0 ) flag_bits &= ~GDBR_LOG_COMM; - else if (::strcasecmp (arg, "default") == 0 ) flag_bits &= ~GDBR_LOG_DEFAULT; - else if (::strcasecmp (arg, "packets") == 0 ) flag_bits &= ~GDBR_LOG_PACKETS; - else if (::strcasecmp (arg, "memory") == 0 ) flag_bits &= ~GDBR_LOG_MEMORY; - else if (::strcasecmp (arg, "data-short") == 0 ) flag_bits &= ~GDBR_LOG_MEMORY_DATA_SHORT; - else if (::strcasecmp (arg, "data-long") == 0 ) flag_bits &= ~GDBR_LOG_MEMORY_DATA_LONG; - else if (::strcasecmp (arg, "process") == 0 ) flag_bits &= ~GDBR_LOG_PROCESS; - else if (::strcasecmp (arg, "step") == 0 ) flag_bits &= ~GDBR_LOG_STEP; - else if (::strcasecmp (arg, "thread") == 0 ) flag_bits &= ~GDBR_LOG_THREAD; - else if (::strcasecmp (arg, "verbose") == 0 ) flag_bits &= ~GDBR_LOG_VERBOSE; - else if (::strncasecmp (arg, "watch", 5) == 0 ) flag_bits &= ~GDBR_LOG_WATCHPOINTS; - else - { - feedback_strm->Printf("error: unrecognized log category '%s'\n", arg); - ListLogCategories (feedback_strm); - } - - } - } - - if (flag_bits == 0) - g_log_enabled = false; - else - log->GetMask().Reset (flag_bits); - } - - return; +Log *ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(uint32_t mask) { + Log *log(GetLog()); + if (log && log->GetMask().Get() & mask) + return log; + return NULL; } -Log * -ProcessGDBRemoteLog::EnableLog (StreamSP &log_stream_sp, uint32_t log_options, const char **categories, Stream *feedback_strm) -{ - // Try see if there already is a log - that way we can reuse its settings. - // We could reuse the log in toto, but we don't know that the stream is the same. +void ProcessGDBRemoteLog::DisableLog(const char **categories, + Stream *feedback_strm) { + Log *log(GetLog()); + if (log) { uint32_t flag_bits = 0; - if (g_log) - flag_bits = g_log->GetMask().Get(); - - // Now make a new log with this stream if one was provided - if (log_stream_sp) - { - if (g_log) - g_log->SetStream(log_stream_sp); - else - g_log = new Log(log_stream_sp); + + if (categories && categories[0]) { + flag_bits = log->GetMask().Get(); + for (size_t i = 0; categories[i] != NULL; ++i) { + const char *arg = categories[i]; + + if (::strcasecmp(arg, "all") == 0) + flag_bits &= ~GDBR_LOG_ALL; + else if (::strcasecmp(arg, "async") == 0) + flag_bits &= ~GDBR_LOG_ASYNC; + else if (::strncasecmp(arg, "break", 5) == 0) + flag_bits &= ~GDBR_LOG_BREAKPOINTS; + else if (::strncasecmp(arg, "comm", 4) == 0) + flag_bits &= ~GDBR_LOG_COMM; + else if (::strcasecmp(arg, "default") == 0) + flag_bits &= ~GDBR_LOG_DEFAULT; + else if (::strcasecmp(arg, "packets") == 0) + flag_bits &= ~GDBR_LOG_PACKETS; + else if (::strcasecmp(arg, "memory") == 0) + flag_bits &= ~GDBR_LOG_MEMORY; + else if (::strcasecmp(arg, "data-short") == 0) + flag_bits &= ~GDBR_LOG_MEMORY_DATA_SHORT; + else if (::strcasecmp(arg, "data-long") == 0) + flag_bits &= ~GDBR_LOG_MEMORY_DATA_LONG; + else if (::strcasecmp(arg, "process") == 0) + flag_bits &= ~GDBR_LOG_PROCESS; + else if (::strcasecmp(arg, "step") == 0) + flag_bits &= ~GDBR_LOG_STEP; + else if (::strcasecmp(arg, "thread") == 0) + flag_bits &= ~GDBR_LOG_THREAD; + else if (::strcasecmp(arg, "verbose") == 0) + flag_bits &= ~GDBR_LOG_VERBOSE; + else if (::strncasecmp(arg, "watch", 5) == 0) + flag_bits &= ~GDBR_LOG_WATCHPOINTS; + else { + feedback_strm->Printf("error: unrecognized log category '%s'\n", arg); + ListLogCategories(feedback_strm); + } + } } + if (flag_bits == 0) + g_log_enabled = false; + else + log->GetMask().Reset(flag_bits); + } + + return; +} + +Log *ProcessGDBRemoteLog::EnableLog(StreamSP &log_stream_sp, + uint32_t log_options, + const char **categories, + Stream *feedback_strm) { + // Try see if there already is a log - that way we can reuse its settings. + // We could reuse the log in toto, but we don't know that the stream is the + // same. + uint32_t flag_bits = 0; + if (g_log) + flag_bits = g_log->GetMask().Get(); + + // Now make a new log with this stream if one was provided + if (log_stream_sp) { if (g_log) - { - bool got_unknown_category = false; - for (size_t i=0; categories[i] != NULL; ++i) - { - const char *arg = categories[i]; - - if (::strcasecmp (arg, "all") == 0 ) flag_bits |= GDBR_LOG_ALL; - else if (::strcasecmp (arg, "async") == 0 ) flag_bits |= GDBR_LOG_ASYNC; - else if (::strncasecmp (arg, "break", 5) == 0 ) flag_bits |= GDBR_LOG_BREAKPOINTS; - else if (::strncasecmp (arg, "comm", 4) == 0 ) flag_bits |= GDBR_LOG_COMM; - else if (::strcasecmp (arg, "default") == 0 ) flag_bits |= GDBR_LOG_DEFAULT; - else if (::strcasecmp (arg, "packets") == 0 ) flag_bits |= GDBR_LOG_PACKETS; - else if (::strcasecmp (arg, "memory") == 0 ) flag_bits |= GDBR_LOG_MEMORY; - else if (::strcasecmp (arg, "data-short") == 0 ) flag_bits |= GDBR_LOG_MEMORY_DATA_SHORT; - else if (::strcasecmp (arg, "data-long") == 0 ) flag_bits |= GDBR_LOG_MEMORY_DATA_LONG; - else if (::strcasecmp (arg, "process") == 0 ) flag_bits |= GDBR_LOG_PROCESS; - else if (::strcasecmp (arg, "step") == 0 ) flag_bits |= GDBR_LOG_STEP; - else if (::strcasecmp (arg, "thread") == 0 ) flag_bits |= GDBR_LOG_THREAD; - else if (::strcasecmp (arg, "verbose") == 0 ) flag_bits |= GDBR_LOG_VERBOSE; - else if (::strncasecmp (arg, "watch", 5) == 0 ) flag_bits |= GDBR_LOG_WATCHPOINTS; - else - { - feedback_strm->Printf("error: unrecognized log category '%s'\n", arg); - if (got_unknown_category == false) - { - got_unknown_category = true; - ListLogCategories (feedback_strm); - } - } + g_log->SetStream(log_stream_sp); + else + g_log = new Log(log_stream_sp); + } + + if (g_log) { + bool got_unknown_category = false; + for (size_t i = 0; categories[i] != NULL; ++i) { + const char *arg = categories[i]; + + if (::strcasecmp(arg, "all") == 0) + flag_bits |= GDBR_LOG_ALL; + else if (::strcasecmp(arg, "async") == 0) + flag_bits |= GDBR_LOG_ASYNC; + else if (::strncasecmp(arg, "break", 5) == 0) + flag_bits |= GDBR_LOG_BREAKPOINTS; + else if (::strncasecmp(arg, "comm", 4) == 0) + flag_bits |= GDBR_LOG_COMM; + else if (::strcasecmp(arg, "default") == 0) + flag_bits |= GDBR_LOG_DEFAULT; + else if (::strcasecmp(arg, "packets") == 0) + flag_bits |= GDBR_LOG_PACKETS; + else if (::strcasecmp(arg, "memory") == 0) + flag_bits |= GDBR_LOG_MEMORY; + else if (::strcasecmp(arg, "data-short") == 0) + flag_bits |= GDBR_LOG_MEMORY_DATA_SHORT; + else if (::strcasecmp(arg, "data-long") == 0) + flag_bits |= GDBR_LOG_MEMORY_DATA_LONG; + else if (::strcasecmp(arg, "process") == 0) + flag_bits |= GDBR_LOG_PROCESS; + else if (::strcasecmp(arg, "step") == 0) + flag_bits |= GDBR_LOG_STEP; + else if (::strcasecmp(arg, "thread") == 0) + flag_bits |= GDBR_LOG_THREAD; + else if (::strcasecmp(arg, "verbose") == 0) + flag_bits |= GDBR_LOG_VERBOSE; + else if (::strncasecmp(arg, "watch", 5) == 0) + flag_bits |= GDBR_LOG_WATCHPOINTS; + else { + feedback_strm->Printf("error: unrecognized log category '%s'\n", arg); + if (got_unknown_category == false) { + got_unknown_category = true; + ListLogCategories(feedback_strm); } - if (flag_bits == 0) - flag_bits = GDBR_LOG_DEFAULT; - g_log->GetMask().Reset(flag_bits); - g_log->GetOptions().Reset(log_options); + } } - g_log_enabled = true; - return g_log; + if (flag_bits == 0) + flag_bits = GDBR_LOG_DEFAULT; + g_log->GetMask().Reset(flag_bits); + g_log->GetOptions().Reset(log_options); + } + g_log_enabled = true; + return g_log; } -void -ProcessGDBRemoteLog::ListLogCategories (Stream *strm) -{ - strm->Printf ("Logging categories for '%s':\n" - " all - turn on all available logging categories\n" - " async - log asynchronous activity\n" - " break - log breakpoints\n" - " communication - log communication activity\n" - " default - enable the default set of logging categories for liblldb\n" - " packets - log gdb remote packets\n" - " memory - log memory reads and writes\n" - " data-short - log memory bytes for memory reads and writes for short transactions only\n" - " data-long - log memory bytes for memory reads and writes for all transactions\n" - " process - log process events and activities\n" - " thread - log thread events and activities\n" - " step - log step related activities\n" - " verbose - enable verbose logging\n" - " watch - log watchpoint related activities\n", ProcessGDBRemote::GetPluginNameStatic().GetCString()); +void ProcessGDBRemoteLog::ListLogCategories(Stream *strm) { + strm->Printf( + "Logging categories for '%s':\n" + " all - turn on all available logging categories\n" + " async - log asynchronous activity\n" + " break - log breakpoints\n" + " communication - log communication activity\n" + " default - enable the default set of logging categories for liblldb\n" + " packets - log gdb remote packets\n" + " memory - log memory reads and writes\n" + " data-short - log memory bytes for memory reads and writes for short " + "transactions only\n" + " data-long - log memory bytes for memory reads and writes for all " + "transactions\n" + " process - log process events and activities\n" + " thread - log thread events and activities\n" + " step - log step related activities\n" + " verbose - enable verbose logging\n" + " watch - log watchpoint related activities\n", + ProcessGDBRemote::GetPluginNameStatic().GetCString()); } - -void -ProcessGDBRemoteLog::LogIf (uint32_t mask, const char *format, ...) -{ - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (mask)); - if (log) - { - va_list args; - va_start (args, format); - log->VAPrintf (format, args); - va_end (args); - } +void ProcessGDBRemoteLog::LogIf(uint32_t mask, const char *format, ...) { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(mask)); + if (log) { + va_list args; + va_start(args, format); + log->VAPrintf(format, args); + va_end(args); + } } diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h index 3cd974d..f5e92b4 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h @@ -17,50 +17,44 @@ // Project includes #include "lldb/Core/Log.h" -#define GDBR_LOG_VERBOSE (1u << 0) -#define GDBR_LOG_PROCESS (1u << 1) -#define GDBR_LOG_THREAD (1u << 2) -#define GDBR_LOG_PACKETS (1u << 3) -#define GDBR_LOG_MEMORY (1u << 4) // Log memory reads/writes calls -#define GDBR_LOG_MEMORY_DATA_SHORT (1u << 5) // Log short memory reads/writes bytes -#define GDBR_LOG_MEMORY_DATA_LONG (1u << 6) // Log all memory reads/writes bytes -#define GDBR_LOG_BREAKPOINTS (1u << 7) -#define GDBR_LOG_WATCHPOINTS (1u << 8) -#define GDBR_LOG_STEP (1u << 9) -#define GDBR_LOG_COMM (1u << 10) -#define GDBR_LOG_ASYNC (1u << 11) -#define GDBR_LOG_ALL (UINT32_MAX) -#define GDBR_LOG_DEFAULT GDBR_LOG_PACKETS +#define GDBR_LOG_VERBOSE (1u << 0) +#define GDBR_LOG_PROCESS (1u << 1) +#define GDBR_LOG_THREAD (1u << 2) +#define GDBR_LOG_PACKETS (1u << 3) +#define GDBR_LOG_MEMORY (1u << 4) // Log memory reads/writes calls +#define GDBR_LOG_MEMORY_DATA_SHORT \ + (1u << 5) // Log short memory reads/writes bytes +#define GDBR_LOG_MEMORY_DATA_LONG (1u << 6) // Log all memory reads/writes bytes +#define GDBR_LOG_BREAKPOINTS (1u << 7) +#define GDBR_LOG_WATCHPOINTS (1u << 8) +#define GDBR_LOG_STEP (1u << 9) +#define GDBR_LOG_COMM (1u << 10) +#define GDBR_LOG_ASYNC (1u << 11) +#define GDBR_LOG_ALL (UINT32_MAX) +#define GDBR_LOG_DEFAULT GDBR_LOG_PACKETS namespace lldb_private { namespace process_gdb_remote { -class ProcessGDBRemoteLog -{ +class ProcessGDBRemoteLog { public: - static void - Initialize(); + static void Initialize(); - static Log * - GetLogIfAllCategoriesSet(uint32_t mask = 0); - - static Log * - GetLogIfAnyCategoryIsSet (uint32_t mask); + static Log *GetLogIfAllCategoriesSet(uint32_t mask = 0); - static void - DisableLog (const char **categories, Stream *feedback_strm); + static Log *GetLogIfAnyCategoryIsSet(uint32_t mask); - static Log * - EnableLog (lldb::StreamSP &log_stream_sp, uint32_t log_options, const char **categories, Stream *feedback_strm); + static void DisableLog(const char **categories, Stream *feedback_strm); - static void - ListLogCategories (Stream *strm); + static Log *EnableLog(lldb::StreamSP &log_stream_sp, uint32_t log_options, + const char **categories, Stream *feedback_strm); - static void - LogIf (uint32_t mask, const char *format, ...); + static void ListLogCategories(Stream *strm); + + static void LogIf(uint32_t mask, const char *format, ...); }; } // namespace process_gdb_remote } // namespace lldb_private -#endif // liblldb_ProcessGDBRemoteLog_h_ +#endif // liblldb_ProcessGDBRemoteLog_h_ diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp index a4af12c..ab55214 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp @@ -7,7 +7,6 @@ // //===----------------------------------------------------------------------===// - #include "ThreadGDBRemote.h" #include "lldb/Breakpoint/Watchpoint.h" @@ -36,372 +35,318 @@ using namespace lldb_private::process_gdb_remote; // Thread Registers //---------------------------------------------------------------------- -ThreadGDBRemote::ThreadGDBRemote (Process &process, lldb::tid_t tid) : - Thread(process, tid), - m_thread_name (), - m_dispatch_queue_name (), - m_thread_dispatch_qaddr (LLDB_INVALID_ADDRESS), - m_dispatch_queue_t (LLDB_INVALID_ADDRESS), - m_queue_kind (eQueueKindUnknown), - m_queue_serial_number (LLDB_INVALID_QUEUE_ID), - m_associated_with_libdispatch_queue (eLazyBoolCalculate) -{ - ProcessGDBRemoteLog::LogIf(GDBR_LOG_THREAD, "%p: ThreadGDBRemote::ThreadGDBRemote (pid = %i, tid = 0x%4.4x)", - this, - process.GetID(), - GetID()); +ThreadGDBRemote::ThreadGDBRemote(Process &process, lldb::tid_t tid) + : Thread(process, tid), m_thread_name(), m_dispatch_queue_name(), + m_thread_dispatch_qaddr(LLDB_INVALID_ADDRESS), + m_dispatch_queue_t(LLDB_INVALID_ADDRESS), m_queue_kind(eQueueKindUnknown), + m_queue_serial_number(LLDB_INVALID_QUEUE_ID), + m_associated_with_libdispatch_queue(eLazyBoolCalculate) { + ProcessGDBRemoteLog::LogIf( + GDBR_LOG_THREAD, + "%p: ThreadGDBRemote::ThreadGDBRemote (pid = %i, tid = 0x%4.4x)", this, + process.GetID(), GetID()); } -ThreadGDBRemote::~ThreadGDBRemote () -{ - ProcessSP process_sp(GetProcess()); - ProcessGDBRemoteLog::LogIf(GDBR_LOG_THREAD, "%p: ThreadGDBRemote::~ThreadGDBRemote (pid = %i, tid = 0x%4.4x)", - this, - process_sp ? process_sp->GetID() : LLDB_INVALID_PROCESS_ID, - GetID()); - DestroyThread(); +ThreadGDBRemote::~ThreadGDBRemote() { + ProcessSP process_sp(GetProcess()); + ProcessGDBRemoteLog::LogIf( + GDBR_LOG_THREAD, + "%p: ThreadGDBRemote::~ThreadGDBRemote (pid = %i, tid = 0x%4.4x)", this, + process_sp ? process_sp->GetID() : LLDB_INVALID_PROCESS_ID, GetID()); + DestroyThread(); } -const char * -ThreadGDBRemote::GetName () -{ - if (m_thread_name.empty()) - return NULL; - return m_thread_name.c_str(); +const char *ThreadGDBRemote::GetName() { + if (m_thread_name.empty()) + return NULL; + return m_thread_name.c_str(); } -void -ThreadGDBRemote::ClearQueueInfo () -{ - m_dispatch_queue_name.clear(); - m_queue_kind = eQueueKindUnknown; - m_queue_serial_number = 0; - m_dispatch_queue_t = LLDB_INVALID_ADDRESS; - m_associated_with_libdispatch_queue = eLazyBoolCalculate; +void ThreadGDBRemote::ClearQueueInfo() { + m_dispatch_queue_name.clear(); + m_queue_kind = eQueueKindUnknown; + m_queue_serial_number = 0; + m_dispatch_queue_t = LLDB_INVALID_ADDRESS; + m_associated_with_libdispatch_queue = eLazyBoolCalculate; } -void -ThreadGDBRemote::SetQueueInfo (std::string &&queue_name, QueueKind queue_kind, uint64_t queue_serial, addr_t dispatch_queue_t, LazyBool associated_with_libdispatch_queue) -{ - m_dispatch_queue_name = queue_name; - m_queue_kind = queue_kind; - m_queue_serial_number = queue_serial; - m_dispatch_queue_t = dispatch_queue_t; - m_associated_with_libdispatch_queue = associated_with_libdispatch_queue; +void ThreadGDBRemote::SetQueueInfo(std::string &&queue_name, + QueueKind queue_kind, uint64_t queue_serial, + addr_t dispatch_queue_t, + LazyBool associated_with_libdispatch_queue) { + m_dispatch_queue_name = queue_name; + m_queue_kind = queue_kind; + m_queue_serial_number = queue_serial; + m_dispatch_queue_t = dispatch_queue_t; + m_associated_with_libdispatch_queue = associated_with_libdispatch_queue; } +const char *ThreadGDBRemote::GetQueueName() { + // If our cached queue info is valid, then someone called + // ThreadGDBRemote::SetQueueInfo(...) + // with valid information that was gleaned from the stop reply packet. In this + // case we trust + // that the info is valid in m_dispatch_queue_name without refetching it + if (CachedQueueInfoIsValid()) { + if (m_dispatch_queue_name.empty()) + return nullptr; + else + return m_dispatch_queue_name.c_str(); + } + // Always re-fetch the dispatch queue name since it can change -const char * -ThreadGDBRemote::GetQueueName () -{ - // If our cached queue info is valid, then someone called ThreadGDBRemote::SetQueueInfo(...) - // with valid information that was gleaned from the stop reply packet. In this case we trust - // that the info is valid in m_dispatch_queue_name without refetching it - if (CachedQueueInfoIsValid()) - { - if (m_dispatch_queue_name.empty()) - return nullptr; - else - return m_dispatch_queue_name.c_str(); - } - // Always re-fetch the dispatch queue name since it can change - - if (m_associated_with_libdispatch_queue == eLazyBoolNo) - return nullptr; - - if (m_thread_dispatch_qaddr != 0 && m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS) - { - ProcessSP process_sp (GetProcess()); - if (process_sp) - { - SystemRuntime *runtime = process_sp->GetSystemRuntime (); - if (runtime) - m_dispatch_queue_name = runtime->GetQueueNameFromThreadQAddress (m_thread_dispatch_qaddr); - else - m_dispatch_queue_name.clear(); - - if (!m_dispatch_queue_name.empty()) - return m_dispatch_queue_name.c_str(); - } + if (m_associated_with_libdispatch_queue == eLazyBoolNo) + return nullptr; + + if (m_thread_dispatch_qaddr != 0 && + m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS) { + ProcessSP process_sp(GetProcess()); + if (process_sp) { + SystemRuntime *runtime = process_sp->GetSystemRuntime(); + if (runtime) + m_dispatch_queue_name = + runtime->GetQueueNameFromThreadQAddress(m_thread_dispatch_qaddr); + else + m_dispatch_queue_name.clear(); + + if (!m_dispatch_queue_name.empty()) + return m_dispatch_queue_name.c_str(); } - return NULL; + } + return NULL; } -QueueKind -ThreadGDBRemote::GetQueueKind () -{ - // If our cached queue info is valid, then someone called ThreadGDBRemote::SetQueueInfo(...) - // with valid information that was gleaned from the stop reply packet. In this case we trust - // that the info is valid in m_dispatch_queue_name without refetching it - if (CachedQueueInfoIsValid()) - { - return m_queue_kind; - } +QueueKind ThreadGDBRemote::GetQueueKind() { + // If our cached queue info is valid, then someone called + // ThreadGDBRemote::SetQueueInfo(...) + // with valid information that was gleaned from the stop reply packet. In this + // case we trust + // that the info is valid in m_dispatch_queue_name without refetching it + if (CachedQueueInfoIsValid()) { + return m_queue_kind; + } + + if (m_associated_with_libdispatch_queue == eLazyBoolNo) + return eQueueKindUnknown; - if (m_associated_with_libdispatch_queue == eLazyBoolNo) - return eQueueKindUnknown; - - if (m_thread_dispatch_qaddr != 0 && m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS) - { - ProcessSP process_sp (GetProcess()); - if (process_sp) - { - SystemRuntime *runtime = process_sp->GetSystemRuntime (); - if (runtime) - m_queue_kind = runtime->GetQueueKind (m_thread_dispatch_qaddr); - return m_queue_kind; - } + if (m_thread_dispatch_qaddr != 0 && + m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS) { + ProcessSP process_sp(GetProcess()); + if (process_sp) { + SystemRuntime *runtime = process_sp->GetSystemRuntime(); + if (runtime) + m_queue_kind = runtime->GetQueueKind(m_thread_dispatch_qaddr); + return m_queue_kind; } - return eQueueKindUnknown; + } + return eQueueKindUnknown; } +queue_id_t ThreadGDBRemote::GetQueueID() { + // If our cached queue info is valid, then someone called + // ThreadGDBRemote::SetQueueInfo(...) + // with valid information that was gleaned from the stop reply packet. In this + // case we trust + // that the info is valid in m_dispatch_queue_name without refetching it + if (CachedQueueInfoIsValid()) + return m_queue_serial_number; -queue_id_t -ThreadGDBRemote::GetQueueID () -{ - // If our cached queue info is valid, then someone called ThreadGDBRemote::SetQueueInfo(...) - // with valid information that was gleaned from the stop reply packet. In this case we trust - // that the info is valid in m_dispatch_queue_name without refetching it - if (CachedQueueInfoIsValid()) - return m_queue_serial_number; - - if (m_associated_with_libdispatch_queue == eLazyBoolNo) - return LLDB_INVALID_QUEUE_ID; - - if (m_thread_dispatch_qaddr != 0 && m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS) - { - ProcessSP process_sp (GetProcess()); - if (process_sp) - { - SystemRuntime *runtime = process_sp->GetSystemRuntime (); - if (runtime) - { - return runtime->GetQueueIDFromThreadQAddress (m_thread_dispatch_qaddr); - } - } - } + if (m_associated_with_libdispatch_queue == eLazyBoolNo) return LLDB_INVALID_QUEUE_ID; + + if (m_thread_dispatch_qaddr != 0 && + m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS) { + ProcessSP process_sp(GetProcess()); + if (process_sp) { + SystemRuntime *runtime = process_sp->GetSystemRuntime(); + if (runtime) { + return runtime->GetQueueIDFromThreadQAddress(m_thread_dispatch_qaddr); + } + } + } + return LLDB_INVALID_QUEUE_ID; } -QueueSP -ThreadGDBRemote::GetQueue () -{ - queue_id_t queue_id = GetQueueID(); - QueueSP queue; - if (queue_id != LLDB_INVALID_QUEUE_ID) - { - ProcessSP process_sp (GetProcess()); - if (process_sp) - { - queue = process_sp->GetQueueList().FindQueueByID (queue_id); - } +QueueSP ThreadGDBRemote::GetQueue() { + queue_id_t queue_id = GetQueueID(); + QueueSP queue; + if (queue_id != LLDB_INVALID_QUEUE_ID) { + ProcessSP process_sp(GetProcess()); + if (process_sp) { + queue = process_sp->GetQueueList().FindQueueByID(queue_id); } - return queue; + } + return queue; } -addr_t -ThreadGDBRemote::GetQueueLibdispatchQueueAddress () -{ - if (m_dispatch_queue_t == LLDB_INVALID_ADDRESS) - { - if (m_thread_dispatch_qaddr != 0 && m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS) - { - ProcessSP process_sp (GetProcess()); - if (process_sp) - { - SystemRuntime *runtime = process_sp->GetSystemRuntime (); - if (runtime) - { - m_dispatch_queue_t = runtime->GetLibdispatchQueueAddressFromThreadQAddress (m_thread_dispatch_qaddr); - } - } +addr_t ThreadGDBRemote::GetQueueLibdispatchQueueAddress() { + if (m_dispatch_queue_t == LLDB_INVALID_ADDRESS) { + if (m_thread_dispatch_qaddr != 0 && + m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS) { + ProcessSP process_sp(GetProcess()); + if (process_sp) { + SystemRuntime *runtime = process_sp->GetSystemRuntime(); + if (runtime) { + m_dispatch_queue_t = + runtime->GetLibdispatchQueueAddressFromThreadQAddress( + m_thread_dispatch_qaddr); } + } } - return m_dispatch_queue_t; + } + return m_dispatch_queue_t; } -void -ThreadGDBRemote::SetQueueLibdispatchQueueAddress (lldb::addr_t dispatch_queue_t) -{ - m_dispatch_queue_t = dispatch_queue_t; +void ThreadGDBRemote::SetQueueLibdispatchQueueAddress( + lldb::addr_t dispatch_queue_t) { + m_dispatch_queue_t = dispatch_queue_t; } -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; +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; } -LazyBool -ThreadGDBRemote::GetAssociatedWithLibdispatchQueue () -{ - return m_associated_with_libdispatch_queue; +LazyBool ThreadGDBRemote::GetAssociatedWithLibdispatchQueue() { + return m_associated_with_libdispatch_queue; } -void -ThreadGDBRemote::SetAssociatedWithLibdispatchQueue (LazyBool associated_with_libdispatch_queue) -{ - m_associated_with_libdispatch_queue = associated_with_libdispatch_queue; +void ThreadGDBRemote::SetAssociatedWithLibdispatchQueue( + LazyBool associated_with_libdispatch_queue) { + m_associated_with_libdispatch_queue = associated_with_libdispatch_queue; } -StructuredData::ObjectSP -ThreadGDBRemote::FetchThreadExtendedInfo () -{ - StructuredData::ObjectSP object_sp; - const lldb::user_id_t tid = GetProtocolID(); - Log *log(GetLogIfAnyCategoriesSet (GDBR_LOG_THREAD)); - if (log) - log->Printf ("Fetching extended information for thread %4.4" PRIx64, tid); - ProcessSP process_sp (GetProcess()); - if (process_sp) - { - ProcessGDBRemote *gdb_process = static_cast<ProcessGDBRemote *>(process_sp.get()); - object_sp = gdb_process->GetExtendedInfoForThread (tid); - } - return object_sp; +StructuredData::ObjectSP ThreadGDBRemote::FetchThreadExtendedInfo() { + StructuredData::ObjectSP object_sp; + const lldb::user_id_t tid = GetProtocolID(); + Log *log(GetLogIfAnyCategoriesSet(GDBR_LOG_THREAD)); + if (log) + log->Printf("Fetching extended information for thread %4.4" PRIx64, tid); + ProcessSP process_sp(GetProcess()); + if (process_sp) { + ProcessGDBRemote *gdb_process = + static_cast<ProcessGDBRemote *>(process_sp.get()); + object_sp = gdb_process->GetExtendedInfoForThread(tid); + } + return object_sp; } -void -ThreadGDBRemote::WillResume (StateType resume_state) -{ - int signo = GetResumeSignal(); - const lldb::user_id_t tid = GetProtocolID(); - Log *log(GetLogIfAnyCategoriesSet (GDBR_LOG_THREAD)); - if (log) - log->Printf ("Resuming thread: %4.4" PRIx64 " with state: %s.", tid, StateAsCString(resume_state)); - - ProcessSP process_sp (GetProcess()); - if (process_sp) - { - ProcessGDBRemote *gdb_process = static_cast<ProcessGDBRemote *>(process_sp.get()); - switch (resume_state) - { - case eStateSuspended: - case eStateStopped: - // Don't append anything for threads that should stay stopped. - break; - - case eStateRunning: - if (gdb_process->GetUnixSignals()->SignalIsValid(signo)) - gdb_process->m_continue_C_tids.push_back(std::make_pair(tid, signo)); - else - gdb_process->m_continue_c_tids.push_back(tid); - break; - - case eStateStepping: - if (gdb_process->GetUnixSignals()->SignalIsValid(signo)) - gdb_process->m_continue_S_tids.push_back(std::make_pair(tid, signo)); - else - gdb_process->m_continue_s_tids.push_back(tid); - break; - - default: - break; - } +void ThreadGDBRemote::WillResume(StateType resume_state) { + int signo = GetResumeSignal(); + const lldb::user_id_t tid = GetProtocolID(); + Log *log(GetLogIfAnyCategoriesSet(GDBR_LOG_THREAD)); + if (log) + log->Printf("Resuming thread: %4.4" PRIx64 " with state: %s.", tid, + StateAsCString(resume_state)); + + ProcessSP process_sp(GetProcess()); + if (process_sp) { + ProcessGDBRemote *gdb_process = + static_cast<ProcessGDBRemote *>(process_sp.get()); + switch (resume_state) { + case eStateSuspended: + case eStateStopped: + // Don't append anything for threads that should stay stopped. + break; + + case eStateRunning: + if (gdb_process->GetUnixSignals()->SignalIsValid(signo)) + gdb_process->m_continue_C_tids.push_back(std::make_pair(tid, signo)); + else + gdb_process->m_continue_c_tids.push_back(tid); + break; + + case eStateStepping: + if (gdb_process->GetUnixSignals()->SignalIsValid(signo)) + gdb_process->m_continue_S_tids.push_back(std::make_pair(tid, signo)); + else + gdb_process->m_continue_s_tids.push_back(tid); + break; + + default: + break; } + } } -void -ThreadGDBRemote::RefreshStateAfterStop() -{ - // Invalidate all registers in our register context. We don't set "force" to - // true because the stop reply packet might have had some register values - // that were expedited and these will already be copied into the register - // context by the time this function gets called. The GDBRemoteRegisterContext - // class has been made smart enough to detect when it needs to invalidate - // which registers are valid by putting hooks in the register read and - // register supply functions where they check the process stop ID and do - // the right thing. - const bool force = false; - GetRegisterContext()->InvalidateIfNeeded (force); -} - -bool -ThreadGDBRemote::ThreadIDIsValid (lldb::tid_t thread) -{ - return thread != 0; +void ThreadGDBRemote::RefreshStateAfterStop() { + // Invalidate all registers in our register context. We don't set "force" to + // true because the stop reply packet might have had some register values + // that were expedited and these will already be copied into the register + // context by the time this function gets called. The GDBRemoteRegisterContext + // class has been made smart enough to detect when it needs to invalidate + // which registers are valid by putting hooks in the register read and + // register supply functions where they check the process stop ID and do + // the right thing. + const bool force = false; + GetRegisterContext()->InvalidateIfNeeded(force); } -void -ThreadGDBRemote::Dump(Log *log, uint32_t index) -{ +bool ThreadGDBRemote::ThreadIDIsValid(lldb::tid_t thread) { + return thread != 0; } +void ThreadGDBRemote::Dump(Log *log, uint32_t index) {} -bool -ThreadGDBRemote::ShouldStop (bool &step_more) -{ - return true; -} -lldb::RegisterContextSP -ThreadGDBRemote::GetRegisterContext () -{ - if (m_reg_context_sp.get() == NULL) - m_reg_context_sp = CreateRegisterContextForFrame (NULL); - return m_reg_context_sp; +bool ThreadGDBRemote::ShouldStop(bool &step_more) { return true; } +lldb::RegisterContextSP ThreadGDBRemote::GetRegisterContext() { + if (m_reg_context_sp.get() == NULL) + m_reg_context_sp = CreateRegisterContextForFrame(NULL); + return m_reg_context_sp; } lldb::RegisterContextSP -ThreadGDBRemote::CreateRegisterContextForFrame (StackFrame *frame) -{ - lldb::RegisterContextSP reg_ctx_sp; - uint32_t concrete_frame_idx = 0; - - if (frame) - concrete_frame_idx = frame->GetConcreteFrameIndex (); - - - if (concrete_frame_idx == 0) - { - ProcessSP process_sp (GetProcess()); - if (process_sp) - { - ProcessGDBRemote *gdb_process = static_cast<ProcessGDBRemote *>(process_sp.get()); - // read_all_registers_at_once will be true if 'p' packet is not supported. - bool read_all_registers_at_once = !gdb_process->GetGDBRemote().GetpPacketSupported (GetID()); - reg_ctx_sp.reset (new GDBRemoteRegisterContext (*this, concrete_frame_idx, gdb_process->m_register_info, read_all_registers_at_once)); - } - } - else - { - Unwind *unwinder = GetUnwinder (); - if (unwinder) - reg_ctx_sp = unwinder->CreateRegisterContextForFrame (frame); +ThreadGDBRemote::CreateRegisterContextForFrame(StackFrame *frame) { + lldb::RegisterContextSP reg_ctx_sp; + uint32_t concrete_frame_idx = 0; + + if (frame) + concrete_frame_idx = frame->GetConcreteFrameIndex(); + + if (concrete_frame_idx == 0) { + ProcessSP process_sp(GetProcess()); + if (process_sp) { + ProcessGDBRemote *gdb_process = + static_cast<ProcessGDBRemote *>(process_sp.get()); + // read_all_registers_at_once will be true if 'p' packet is not supported. + bool read_all_registers_at_once = + !gdb_process->GetGDBRemote().GetpPacketSupported(GetID()); + reg_ctx_sp.reset(new GDBRemoteRegisterContext( + *this, concrete_frame_idx, gdb_process->m_register_info, + read_all_registers_at_once)); } - return reg_ctx_sp; + } else { + Unwind *unwinder = GetUnwinder(); + if (unwinder) + reg_ctx_sp = unwinder->CreateRegisterContextForFrame(frame); + } + return reg_ctx_sp; } -bool -ThreadGDBRemote::PrivateSetRegisterValue (uint32_t reg, StringExtractor &response) -{ - GDBRemoteRegisterContext *gdb_reg_ctx = static_cast<GDBRemoteRegisterContext *>(GetRegisterContext ().get()); - assert (gdb_reg_ctx); - return gdb_reg_ctx->PrivateSetRegisterValue (reg, response); +bool ThreadGDBRemote::PrivateSetRegisterValue(uint32_t reg, + llvm::ArrayRef<uint8_t> data) { + GDBRemoteRegisterContext *gdb_reg_ctx = + static_cast<GDBRemoteRegisterContext *>(GetRegisterContext().get()); + assert(gdb_reg_ctx); + return gdb_reg_ctx->PrivateSetRegisterValue(reg, data); } -bool -ThreadGDBRemote::PrivateSetRegisterValue (uint32_t reg, uint64_t regval) -{ - GDBRemoteRegisterContext *gdb_reg_ctx = static_cast<GDBRemoteRegisterContext *>(GetRegisterContext ().get()); - assert (gdb_reg_ctx); - return gdb_reg_ctx->PrivateSetRegisterValue (reg, regval); +bool ThreadGDBRemote::PrivateSetRegisterValue(uint32_t reg, uint64_t regval) { + GDBRemoteRegisterContext *gdb_reg_ctx = + static_cast<GDBRemoteRegisterContext *>(GetRegisterContext().get()); + assert(gdb_reg_ctx); + return gdb_reg_ctx->PrivateSetRegisterValue(reg, regval); } -bool -ThreadGDBRemote::CalculateStopInfo () -{ - ProcessSP process_sp (GetProcess()); - if (process_sp) - return static_cast<ProcessGDBRemote *>(process_sp.get())->CalculateThreadStopInfo(this); - return false; +bool ThreadGDBRemote::CalculateStopInfo() { + ProcessSP process_sp(GetProcess()); + if (process_sp) + return static_cast<ProcessGDBRemote *>(process_sp.get()) + ->CalculateThreadStopInfo(this); + return false; } - - diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h index d7619f4..27caf42 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h @@ -27,126 +27,94 @@ namespace process_gdb_remote { class ProcessGDBRemote; -class ThreadGDBRemote : public Thread -{ +class ThreadGDBRemote : public Thread { public: - ThreadGDBRemote (Process &process, lldb::tid_t tid); + ThreadGDBRemote(Process &process, lldb::tid_t tid); - ~ThreadGDBRemote() override; + ~ThreadGDBRemote() override; - void - WillResume (lldb::StateType resume_state) override; + void WillResume(lldb::StateType resume_state) override; - void - RefreshStateAfterStop() override; + void RefreshStateAfterStop() override; - const char * - GetName () override; + const char *GetName() override; - const char * - GetQueueName () override; + const char *GetQueueName() override; - lldb::QueueKind - GetQueueKind () override; + lldb::QueueKind GetQueueKind() override; - lldb::queue_id_t - GetQueueID () override; + lldb::queue_id_t GetQueueID() override; - lldb::QueueSP - GetQueue () override; + lldb::QueueSP GetQueue() override; - lldb::addr_t - GetQueueLibdispatchQueueAddress () override; + lldb::addr_t GetQueueLibdispatchQueueAddress() override; - void - SetQueueLibdispatchQueueAddress (lldb::addr_t dispatch_queue_t) override; + void SetQueueLibdispatchQueueAddress(lldb::addr_t dispatch_queue_t) override; - bool - ThreadHasQueueInformation () const override; + bool ThreadHasQueueInformation() const override; - lldb::RegisterContextSP - GetRegisterContext () override; + lldb::RegisterContextSP GetRegisterContext() override; - lldb::RegisterContextSP - CreateRegisterContextForFrame (StackFrame *frame) override; + lldb::RegisterContextSP + CreateRegisterContextForFrame(StackFrame *frame) override; - void - Dump (Log *log, uint32_t index); + void Dump(Log *log, uint32_t index); - static bool - ThreadIDIsValid (lldb::tid_t thread); + static bool ThreadIDIsValid(lldb::tid_t thread); - bool - ShouldStop (bool &step_more); + bool ShouldStop(bool &step_more); - const char * - GetBasicInfoAsString (); + const char *GetBasicInfoAsString(); - void - SetName (const char *name) override - { - if (name && name[0]) - m_thread_name.assign (name); - else - m_thread_name.clear(); - } + void SetName(const char *name) override { + if (name && name[0]) + m_thread_name.assign(name); + else + m_thread_name.clear(); + } - lldb::addr_t - GetThreadDispatchQAddr () - { - return m_thread_dispatch_qaddr; - } + lldb::addr_t GetThreadDispatchQAddr() { return m_thread_dispatch_qaddr; } - void - SetThreadDispatchQAddr (lldb::addr_t thread_dispatch_qaddr) - { - m_thread_dispatch_qaddr = thread_dispatch_qaddr; - } + void SetThreadDispatchQAddr(lldb::addr_t thread_dispatch_qaddr) { + m_thread_dispatch_qaddr = thread_dispatch_qaddr; + } - void - ClearQueueInfo (); - - void - SetQueueInfo (std::string &&queue_name, lldb::QueueKind queue_kind, uint64_t queue_serial, lldb::addr_t dispatch_queue_t, lldb_private::LazyBool associated_with_libdispatch_queue); + void ClearQueueInfo(); - lldb_private::LazyBool - GetAssociatedWithLibdispatchQueue () override; + void SetQueueInfo(std::string &&queue_name, lldb::QueueKind queue_kind, + uint64_t queue_serial, lldb::addr_t dispatch_queue_t, + lldb_private::LazyBool associated_with_libdispatch_queue); - void - SetAssociatedWithLibdispatchQueue (lldb_private::LazyBool associated_with_libdispatch_queue) override; + lldb_private::LazyBool GetAssociatedWithLibdispatchQueue() override; - StructuredData::ObjectSP - FetchThreadExtendedInfo () override; + void SetAssociatedWithLibdispatchQueue( + lldb_private::LazyBool associated_with_libdispatch_queue) override; + + StructuredData::ObjectSP FetchThreadExtendedInfo() override; protected: - friend class ProcessGDBRemote; - - std::string m_thread_name; - std::string m_dispatch_queue_name; - lldb::addr_t m_thread_dispatch_qaddr; - lldb::addr_t m_dispatch_queue_t; - lldb::QueueKind m_queue_kind; // Queue info from stop reply/stop info for thread - uint64_t m_queue_serial_number; // Queue info from stop reply/stop info for thread - lldb_private::LazyBool m_associated_with_libdispatch_queue; - - bool - PrivateSetRegisterValue (uint32_t reg, - StringExtractor &response); - - bool - PrivateSetRegisterValue (uint32_t reg, - uint64_t regval); - - bool - CachedQueueInfoIsValid() const - { - return m_queue_kind != lldb::eQueueKindUnknown; - } - void - SetStopInfoFromPacket (StringExtractor &stop_packet, uint32_t stop_id); - - bool - CalculateStopInfo () override; + friend class ProcessGDBRemote; + + std::string m_thread_name; + std::string m_dispatch_queue_name; + lldb::addr_t m_thread_dispatch_qaddr; + lldb::addr_t m_dispatch_queue_t; + lldb::QueueKind + m_queue_kind; // Queue info from stop reply/stop info for thread + uint64_t + m_queue_serial_number; // Queue info from stop reply/stop info for thread + lldb_private::LazyBool m_associated_with_libdispatch_queue; + + bool PrivateSetRegisterValue(uint32_t reg, llvm::ArrayRef<uint8_t> data); + + bool PrivateSetRegisterValue(uint32_t reg, uint64_t regval); + + bool CachedQueueInfoIsValid() const { + return m_queue_kind != lldb::eQueueKindUnknown; + } + void SetStopInfoFromPacket(StringExtractor &stop_packet, uint32_t stop_id); + + bool CalculateStopInfo() override; }; } // namespace process_gdb_remote |