aboutsummaryrefslogtreecommitdiffstats
path: root/source/Plugins/Process/gdb-remote
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-01-02 19:26:05 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-01-02 19:26:05 +0000
commit14f1b3e8826ce43b978db93a62d1166055db5394 (patch)
tree0a00ad8d3498783fe0193f3b656bca17c4c8697d /source/Plugins/Process/gdb-remote
parent4ee8c119c71a06dcad1e0fecc8c675e480e59337 (diff)
downloadsrc-14f1b3e8826ce43b978db93a62d1166055db5394.tar.gz
src-14f1b3e8826ce43b978db93a62d1166055db5394.zip
Vendor import of lldb trunk r290819:vendor/lldb/lldb-trunk-r290819
Notes
Notes: svn path=/vendor/lldb/dist/; revision=311128 svn path=/vendor/lldb/lldb-trunk-r290819/; revision=311129; tag=vendor/lldb/lldb-trunk-r290819
Diffstat (limited to 'source/Plugins/Process/gdb-remote')
-rw-r--r--source/Plugins/Process/gdb-remote/CMakeLists.txt1
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp376
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h144
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp2469
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h538
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp7509
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h1188
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp154
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h61
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp2074
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h205
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp5426
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h364
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp896
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h128
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp1926
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h181
-rw-r--r--source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp9096
-rw-r--r--source/Plugins/Process/gdb-remote/ProcessGDBRemote.h711
-rw-r--r--source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp342
-rw-r--r--source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h58
-rw-r--r--source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp569
-rw-r--r--source/Plugins/Process/gdb-remote/ThreadGDBRemote.h154
23 files changed, 16619 insertions, 17951 deletions
diff --git a/source/Plugins/Process/gdb-remote/CMakeLists.txt b/source/Plugins/Process/gdb-remote/CMakeLists.txt
index 8dbfa453f2c2..b28522725868 100644
--- a/source/Plugins/Process/gdb-remote/CMakeLists.txt
+++ b/source/Plugins/Process/gdb-remote/CMakeLists.txt
@@ -3,6 +3,7 @@ if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
endif()
add_lldb_library(lldbPluginProcessGDBRemote
+ GDBRemoteClientBase.cpp
GDBRemoteCommunication.cpp
GDBRemoteCommunicationClient.cpp
GDBRemoteCommunicationServer.cpp
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp
new file mode 100644
index 000000000000..1e20a090161d
--- /dev/null
+++ b/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/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h b/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h
new file mode 100644
index 000000000000..2646405c9b91
--- /dev/null
+++ b/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/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
index f164b1411be8..bd87521fe6e7 100644
--- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
+++ b/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/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
index 2a01bcec260c..1f3fa17cfc26 100644
--- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
+++ b/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/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index a792bbbd1385..f9bbaef60215 100644
--- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/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,3098 @@ 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 &region_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 &region_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");
+ 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)
+// 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'");
+ 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()));
+ 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/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
index 096c4cf81015..83162a662e06 100644
--- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
+++ b/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/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
index 4ee66b84d474..934824e214dc 100644
--- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
+++ b/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/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
index 1d512bf1de59..0c583e62d76b 100644
--- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
+++ b/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/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
index 26a2e697e854..e4e6810f665c 100644
--- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
+++ b/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/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h
index d2fd70042ccc..321a92266bdd 100644
--- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h
+++ b/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/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
index c468ba33e858..bf72673f1769 100644
--- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
+++ b/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 &reg_ctx_sp,
- const RegisterInfo &reg_info,
- const RegisterValue *reg_value_p)
-{
- RegisterValue reg_value;
- if (!reg_value_p)
- {
- Error error = reg_ctx_sp->ReadRegister (&reg_info, reg_value);
- if (error.Success ())
- reg_value_p = &reg_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 (), re