diff options
author | dim <dim@FreeBSD.org> | 2017-04-02 17:24:58 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2017-04-02 17:24:58 +0000 |
commit | 60b571e49a90d38697b3aca23020d9da42fc7d7f (patch) | |
tree | 99351324c24d6cb146b6285b6caffa4d26fce188 /contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote | |
parent | bea1b22c7a9bce1dfdd73e6e5b65bc4752215180 (diff) | |
download | FreeBSD-src-60b571e49a90d38697b3aca23020d9da42fc7d7f.zip FreeBSD-src-60b571e49a90d38697b3aca23020d9da42fc7d7f.tar.gz |
Update clang, llvm, lld, lldb, compiler-rt and libc++ to 4.0.0 release:
MFC r309142 (by emaste):
Add WITH_LLD_AS_LD build knob
If set it installs LLD as /usr/bin/ld. LLD (as of version 3.9) is not
capable of linking the world and kernel, but can self-host and link many
substantial applications. GNU ld continues to be used for the world and
kernel build, regardless of how this knob is set.
It is on by default for arm64, and off for all other CPU architectures.
Sponsored by: The FreeBSD Foundation
MFC r310840:
Reapply 310775, now it also builds correctly if lldb is disabled:
Move llvm-objdump from CLANG_EXTRAS to installed by default
We currently install three tools from binutils 2.17.50: as, ld, and
objdump. Work is underway to migrate to a permissively-licensed
tool-chain, with one goal being the retirement of binutils 2.17.50.
LLVM's llvm-objdump is intended to be compatible with GNU objdump
although it is currently missing some options and may have formatting
differences. Enable it by default for testing and further investigation.
It may later be changed to install as /usr/bin/objdump, it becomes a
fully viable replacement.
Reviewed by: emaste
Differential Revision: https://reviews.freebsd.org/D8879
MFC r312855 (by emaste):
Rename LLD_AS_LD to LLD_IS_LD, for consistency with CLANG_IS_CC
Reported by: Dan McGregor <dan.mcgregor usask.ca>
MFC r313559 | glebius | 2017-02-10 18:34:48 +0100 (Fri, 10 Feb 2017) | 5 lines
Don't check struct rtentry on FreeBSD, it is an internal kernel structure.
On other systems it may be API structure for SIOCADDRT/SIOCDELRT.
Reviewed by: emaste, dim
MFC r314152 (by jkim):
Remove an assembler flag, which is redundant since r309124. The upstream
took care of it by introducing a macro NO_EXEC_STACK_DIRECTIVE.
http://llvm.org/viewvc/llvm-project?rev=273500&view=rev
Reviewed by: dim
MFC r314564:
Upgrade our copies of clang, llvm, lld, lldb, compiler-rt and libc++ to
4.0.0 (branches/release_40 296509). The release will follow soon.
Please note that from 3.5.0 onwards, clang, llvm and lldb require C++11
support to build; see UPDATING for more information.
Also note that as of 4.0.0, lld should be able to link the base system
on amd64 and aarch64. See the WITH_LLD_IS_LLD setting in src.conf(5).
Though please be aware that this is work in progress.
Release notes for llvm, clang and lld will be available here:
<http://releases.llvm.org/4.0.0/docs/ReleaseNotes.html>
<http://releases.llvm.org/4.0.0/tools/clang/docs/ReleaseNotes.html>
<http://releases.llvm.org/4.0.0/tools/lld/docs/ReleaseNotes.html>
Thanks to Ed Maste, Jan Beich, Antoine Brodin and Eric Fiselier for
their help.
Relnotes: yes
Exp-run: antoine
PR: 215969, 216008
MFC r314708:
For now, revert r287232 from upstream llvm trunk (by Daniil Fukalov):
[SCEV] limit recursion depth of CompareSCEVComplexity
Summary:
CompareSCEVComplexity goes too deep (50+ on a quite a big unrolled
loop) and runs almost infinite time.
Added cache of "equal" SCEV pairs to earlier cutoff of further
estimation. Recursion depth limit was also introduced as a parameter.
Reviewers: sanjoy
Subscribers: mzolotukhin, tstellarAMD, llvm-commits
Differential Revision: https://reviews.llvm.org/D26389
This commit is the cause of excessive compile times on skein_block.c
(and possibly other files) during kernel builds on amd64.
We never saw the problematic behavior described in this upstream commit,
so for now it is better to revert it. An upstream bug has been filed
here: https://bugs.llvm.org/show_bug.cgi?id=32142
Reported by: mjg
MFC r314795:
Reapply r287232 from upstream llvm trunk (by Daniil Fukalov):
[SCEV] limit recursion depth of CompareSCEVComplexity
Summary:
CompareSCEVComplexity goes too deep (50+ on a quite a big unrolled
loop) and runs almost infinite time.
Added cache of "equal" SCEV pairs to earlier cutoff of further
estimation. Recursion depth limit was also introduced as a parameter.
Reviewers: sanjoy
Subscribers: mzolotukhin, tstellarAMD, llvm-commits
Differential Revision: https://reviews.llvm.org/D26389
Pull in r296992 from upstream llvm trunk (by Sanjoy Das):
[SCEV] Decrease the recursion threshold for CompareValueComplexity
Fixes PR32142.
r287232 accidentally increased the recursion threshold for
CompareValueComplexity from 2 to 32. This change reverses that
change by introducing a separate flag for CompareValueComplexity's
threshold.
The latter revision fixes the excessive compile times for skein_block.c.
MFC r314907 | mmel | 2017-03-08 12:40:27 +0100 (Wed, 08 Mar 2017) | 7 lines
Unbreak ARMv6 world.
The new compiler_rt library imported with clang 4.0.0 have several fatal
issues (non-functional __udivsi3 for example) with ARM specific instrict
functions. As temporary workaround, until upstream solve these problems,
disable all thumb[1][2] related feature.
MFC r315016:
Update clang, llvm, lld, lldb, compiler-rt and libc++ to 4.0.0 release.
We were already very close to the last release candidate, so this is a
pretty minor update.
Relnotes: yes
MFC r316005:
Revert r314907, and pull in r298713 from upstream compiler-rt trunk (by
Weiming Zhao):
builtins: Select correct code fragments when compiling for Thumb1/Thum2/ARM ISA.
Summary:
Value of __ARM_ARCH_ISA_THUMB isn't based on the actual compilation
mode (-mthumb, -marm), it reflect's capability of given CPU.
Due to this:
- use __tbumb__ and __thumb2__ insteand of __ARM_ARCH_ISA_THUMB
- use '.thumb' directive consistently in all affected files
- decorate all thumb functions using
DEFINE_COMPILERRT_THUMB_FUNCTION()
---------
Note: This patch doesn't fix broken Thumb1 variant of __udivsi3 !
Reviewers: weimingz, rengolin, compnerd
Subscribers: aemerson, dim
Differential Revision: https://reviews.llvm.org/D30938
Discussed with: mmel
Diffstat (limited to 'contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote')
22 files changed, 16615 insertions, 17951 deletions
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp new file mode 100644 index 0000000..1e20a09 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp @@ -0,0 +1,376 @@ +//===-- GDBRemoteClientBase.cpp ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "GDBRemoteClientBase.h" + +#include "llvm/ADT/StringExtras.h" + +#include "lldb/Target/Process.h" +#include "lldb/Target/UnixSignals.h" +#include "lldb/Utility/LLDBAssert.h" + +#include "ProcessGDBRemoteLog.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_gdb_remote; +using namespace std::chrono; + +static const seconds kInterruptTimeout(5); + +///////////////////////// +// GDBRemoteClientBase // +///////////////////////// + +GDBRemoteClientBase::ContinueDelegate::~ContinueDelegate() = default; + +GDBRemoteClientBase::GDBRemoteClientBase(const char *comm_name, + const char *listener_name) + : GDBRemoteCommunication(comm_name, listener_name), m_async_count(0), + m_is_running(false), m_should_stop(false) {} + +StateType GDBRemoteClientBase::SendContinuePacketAndWaitForResponse( + ContinueDelegate &delegate, const UnixSignals &signals, + llvm::StringRef payload, StringExtractorGDBRemote &response) { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + response.Clear(); + + { + std::lock_guard<std::mutex> lock(m_mutex); + m_continue_packet = payload; + m_should_stop = false; + } + ContinueLock cont_lock(*this); + if (!cont_lock) + return eStateInvalid; + OnRunPacketSent(true); + + for (;;) { + PacketResult read_result = ReadPacket(response, kInterruptTimeout, false); + switch (read_result) { + case PacketResult::ErrorReplyTimeout: { + std::lock_guard<std::mutex> lock(m_mutex); + if (m_async_count == 0) + continue; + if (steady_clock::now() >= m_interrupt_time + kInterruptTimeout) + return eStateInvalid; + } + case PacketResult::Success: + break; + default: + if (log) + log->Printf("GDBRemoteClientBase::%s () ReadPacket(...) => false", + __FUNCTION__); + return eStateInvalid; + } + if (response.Empty()) + return eStateInvalid; + + const char stop_type = response.GetChar(); + if (log) + log->Printf("GDBRemoteClientBase::%s () got packet: %s", __FUNCTION__, + response.GetStringRef().c_str()); + + switch (stop_type) { + case 'W': + case 'X': + return eStateExited; + case 'E': + // ERROR + return eStateInvalid; + default: + if (log) + log->Printf("GDBRemoteClientBase::%s () unrecognized async packet", + __FUNCTION__); + return eStateInvalid; + case 'O': { + std::string inferior_stdout; + response.GetHexByteString(inferior_stdout); + delegate.HandleAsyncStdout(inferior_stdout); + break; + } + case 'A': + delegate.HandleAsyncMisc( + llvm::StringRef(response.GetStringRef()).substr(1)); + break; + case 'J': + delegate.HandleAsyncStructuredDataPacket(response.GetStringRef()); + break; + case 'T': + case 'S': + // Do this with the continue lock held. + const bool should_stop = ShouldStop(signals, response); + response.SetFilePos(0); + + // The packet we should resume with. In the future + // we should check our thread list and "do the right thing" + // for new threads that show up while we stop and run async + // packets. Setting the packet to 'c' to continue all threads + // is the right thing to do 99.99% of the time because if a + // thread was single stepping, and we sent an interrupt, we + // will notice above that we didn't stop due to an interrupt + // but stopped due to stepping and we would _not_ continue. + // This packet may get modified by the async actions (e.g. to send a + // signal). + m_continue_packet = 'c'; + cont_lock.unlock(); + + delegate.HandleStopReply(); + if (should_stop) + return eStateStopped; + + switch (cont_lock.lock()) { + case ContinueLock::LockResult::Success: + break; + case ContinueLock::LockResult::Failed: + return eStateInvalid; + case ContinueLock::LockResult::Cancelled: + return eStateStopped; + } + OnRunPacketSent(false); + break; + } + } +} + +bool GDBRemoteClientBase::SendAsyncSignal(int signo) { + Lock lock(*this, true); + if (!lock || !lock.DidInterrupt()) + return false; + + m_continue_packet = 'C'; + m_continue_packet += llvm::hexdigit((signo / 16) % 16); + m_continue_packet += llvm::hexdigit(signo % 16); + return true; +} + +bool GDBRemoteClientBase::Interrupt() { + Lock lock(*this, true); + if (!lock.DidInterrupt()) + return false; + m_should_stop = true; + return true; +} +GDBRemoteCommunication::PacketResult +GDBRemoteClientBase::SendPacketAndWaitForResponse( + llvm::StringRef payload, StringExtractorGDBRemote &response, + bool send_async) { + Lock lock(*this, send_async); + if (!lock) { + if (Log *log = + ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)) + log->Printf("GDBRemoteClientBase::%s failed to get mutex, not sending " + "packet '%.*s' (send_async=%d)", + __FUNCTION__, int(payload.size()), payload.data(), + send_async); + return PacketResult::ErrorSendFailed; + } + + return SendPacketAndWaitForResponseNoLock(payload, response); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteClientBase::SendPacketAndWaitForResponseNoLock( + llvm::StringRef payload, StringExtractorGDBRemote &response) { + PacketResult packet_result = SendPacketNoLock(payload); + if (packet_result != PacketResult::Success) + return packet_result; + + const size_t max_response_retries = 3; + for (size_t i = 0; i < max_response_retries; ++i) { + packet_result = ReadPacket(response, GetPacketTimeout(), true); + // Make sure we received a response + if (packet_result != PacketResult::Success) + return packet_result; + // Make sure our response is valid for the payload that was sent + if (response.ValidateResponse()) + return packet_result; + // Response says it wasn't valid + Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS); + if (log) + log->Printf( + "error: packet with payload \"%.*s\" got invalid response \"%s\": %s", + int(payload.size()), payload.data(), response.GetStringRef().c_str(), + (i == (max_response_retries - 1)) + ? "using invalid response and giving up" + : "ignoring response and waiting for another"); + } + return packet_result; +} + +bool GDBRemoteClientBase::SendvContPacket(llvm::StringRef payload, + StringExtractorGDBRemote &response) { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + if (log) + log->Printf("GDBRemoteCommunicationClient::%s ()", __FUNCTION__); + + // we want to lock down packet sending while we continue + Lock lock(*this, true); + + if (log) + log->Printf( + "GDBRemoteCommunicationClient::%s () sending vCont packet: %.*s", + __FUNCTION__, int(payload.size()), payload.data()); + + if (SendPacketNoLock(payload) != PacketResult::Success) + return false; + + OnRunPacketSent(true); + + // wait for the response to the vCont + if (ReadPacket(response, llvm::None, false) == PacketResult::Success) { + if (response.IsOKResponse()) + return true; + } + + return false; +} +bool GDBRemoteClientBase::ShouldStop(const UnixSignals &signals, + StringExtractorGDBRemote &response) { + std::lock_guard<std::mutex> lock(m_mutex); + + if (m_async_count == 0) + return true; // We were not interrupted. The process stopped on its own. + + // Older debugserver stubs (before April 2016) can return two + // stop-reply packets in response to a ^C packet. + // Additionally, all debugservers still return two stop replies if + // the inferior stops due to some other reason before the remote + // stub manages to interrupt it. We need to wait for this + // additional packet to make sure the packet sequence does not get + // skewed. + StringExtractorGDBRemote extra_stop_reply_packet; + ReadPacket(extra_stop_reply_packet, milliseconds(100), false); + + // Interrupting is typically done using SIGSTOP or SIGINT, so if + // the process stops with some other signal, we definitely want to + // stop. + const uint8_t signo = response.GetHexU8(UINT8_MAX); + if (signo != signals.GetSignalNumberFromName("SIGSTOP") && + signo != signals.GetSignalNumberFromName("SIGINT")) + return true; + + // We probably only stopped to perform some async processing, so continue + // after that is done. + // TODO: This is not 100% correct, as the process may have been stopped with + // SIGINT or SIGSTOP that was not caused by us (e.g. raise(SIGINT)). This will + // normally cause a stop, but if it's done concurrently with a async + // interrupt, that stop will get eaten (llvm.org/pr20231). + return false; +} + +void GDBRemoteClientBase::OnRunPacketSent(bool first) { + if (first) + BroadcastEvent(eBroadcastBitRunPacketSent, NULL); +} + +/////////////////////////////////////// +// GDBRemoteClientBase::ContinueLock // +/////////////////////////////////////// + +GDBRemoteClientBase::ContinueLock::ContinueLock(GDBRemoteClientBase &comm) + : m_comm(comm), m_acquired(false) { + lock(); +} + +GDBRemoteClientBase::ContinueLock::~ContinueLock() { + if (m_acquired) + unlock(); +} + +void GDBRemoteClientBase::ContinueLock::unlock() { + lldbassert(m_acquired); + { + std::unique_lock<std::mutex> lock(m_comm.m_mutex); + m_comm.m_is_running = false; + } + m_comm.m_cv.notify_all(); + m_acquired = false; +} + +GDBRemoteClientBase::ContinueLock::LockResult +GDBRemoteClientBase::ContinueLock::lock() { + Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS); + if (log) + log->Printf("GDBRemoteClientBase::ContinueLock::%s() resuming with %s", + __FUNCTION__, m_comm.m_continue_packet.c_str()); + + lldbassert(!m_acquired); + std::unique_lock<std::mutex> lock(m_comm.m_mutex); + m_comm.m_cv.wait(lock, [this] { return m_comm.m_async_count == 0; }); + if (m_comm.m_should_stop) { + m_comm.m_should_stop = false; + if (log) + log->Printf("GDBRemoteClientBase::ContinueLock::%s() cancelled", + __FUNCTION__); + return LockResult::Cancelled; + } + if (m_comm.SendPacketNoLock(m_comm.m_continue_packet) != + PacketResult::Success) + return LockResult::Failed; + + lldbassert(!m_comm.m_is_running); + m_comm.m_is_running = true; + m_acquired = true; + return LockResult::Success; +} + +/////////////////////////////// +// GDBRemoteClientBase::Lock // +/////////////////////////////// + +GDBRemoteClientBase::Lock::Lock(GDBRemoteClientBase &comm, bool interrupt) + : m_async_lock(comm.m_async_mutex, std::defer_lock), m_comm(comm), + m_acquired(false), m_did_interrupt(false) { + SyncWithContinueThread(interrupt); + if (m_acquired) + m_async_lock.lock(); +} + +void GDBRemoteClientBase::Lock::SyncWithContinueThread(bool interrupt) { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + std::unique_lock<std::mutex> lock(m_comm.m_mutex); + if (m_comm.m_is_running && !interrupt) + return; // We were asked to avoid interrupting the sender. Lock is not + // acquired. + + ++m_comm.m_async_count; + if (m_comm.m_is_running) { + if (m_comm.m_async_count == 1) { + // The sender has sent the continue packet and we are the first async + // packet. Let's interrupt it. + const char ctrl_c = '\x03'; + ConnectionStatus status = eConnectionStatusSuccess; + size_t bytes_written = m_comm.Write(&ctrl_c, 1, status, NULL); + if (bytes_written == 0) { + --m_comm.m_async_count; + if (log) + log->Printf("GDBRemoteClientBase::Lock::Lock failed to send " + "interrupt packet"); + return; + } + if (log) + log->PutCString("GDBRemoteClientBase::Lock::Lock sent packet: \\x03"); + m_comm.m_interrupt_time = steady_clock::now(); + } + m_comm.m_cv.wait(lock, [this] { return m_comm.m_is_running == false; }); + m_did_interrupt = true; + } + m_acquired = true; +} + +GDBRemoteClientBase::Lock::~Lock() { + if (!m_acquired) + return; + { + std::unique_lock<std::mutex> lock(m_comm.m_mutex); + --m_comm.m_async_count; + } + m_comm.m_cv.notify_one(); +} diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h new file mode 100644 index 0000000..2646405 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h @@ -0,0 +1,144 @@ +//===-- GDBRemoteClientBase.h -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_GDBRemoteClientBase_h_ +#define liblldb_GDBRemoteClientBase_h_ + +#include "GDBRemoteCommunication.h" + +#include <condition_variable> + +namespace lldb_private { +namespace process_gdb_remote { + +class GDBRemoteClientBase : public GDBRemoteCommunication { +public: + struct ContinueDelegate { + virtual ~ContinueDelegate(); + virtual void HandleAsyncStdout(llvm::StringRef out) = 0; + virtual void HandleAsyncMisc(llvm::StringRef data) = 0; + virtual void HandleStopReply() = 0; + + // ========================================================================= + /// Process asynchronously-received structured data. + /// + /// @param[in] data + /// The complete data packet, expected to start with JSON-async. + // ========================================================================= + virtual void HandleAsyncStructuredDataPacket(llvm::StringRef data) = 0; + }; + + GDBRemoteClientBase(const char *comm_name, const char *listener_name); + + bool SendAsyncSignal(int signo); + + bool Interrupt(); + + lldb::StateType SendContinuePacketAndWaitForResponse( + ContinueDelegate &delegate, const UnixSignals &signals, + llvm::StringRef payload, StringExtractorGDBRemote &response); + + PacketResult SendPacketAndWaitForResponse(llvm::StringRef payload, + StringExtractorGDBRemote &response, + bool send_async); + + bool SendvContPacket(llvm::StringRef payload, + StringExtractorGDBRemote &response); + + class Lock { + public: + Lock(GDBRemoteClientBase &comm, bool interrupt); + ~Lock(); + + explicit operator bool() { return m_acquired; } + + // Whether we had to interrupt the continue thread to acquire the + // connection. + bool DidInterrupt() const { return m_did_interrupt; } + + private: + std::unique_lock<std::recursive_mutex> m_async_lock; + GDBRemoteClientBase &m_comm; + bool m_acquired; + bool m_did_interrupt; + + void SyncWithContinueThread(bool interrupt); + }; + +protected: + PacketResult + SendPacketAndWaitForResponseNoLock(llvm::StringRef payload, + StringExtractorGDBRemote &response); + + virtual void OnRunPacketSent(bool first); + +private: + // Variables handling synchronization between the Continue thread and any + // other threads + // wishing to send packets over the connection. Either the continue thread has + // control over + // the connection (m_is_running == true) or the connection is free for an + // arbitrary number of + // other senders to take which indicate their interest by incrementing + // m_async_count. + // Semantics of individual states: + // - m_continue_packet == false, m_async_count == 0: connection is free + // - m_continue_packet == true, m_async_count == 0: only continue thread is + // present + // - m_continue_packet == true, m_async_count > 0: continue thread has + // control, async threads + // should interrupt it and wait for it to set m_continue_packet to false + // - m_continue_packet == false, m_async_count > 0: async threads have + // control, continue + // thread needs to wait for them to finish (m_async_count goes down to 0). + std::mutex m_mutex; + std::condition_variable m_cv; + // Packet with which to resume after an async interrupt. Can be changed by an + // async thread + // e.g. to inject a signal. + std::string m_continue_packet; + // When was the interrupt packet sent. Used to make sure we time out if the + // stub does not + // respond to interrupt requests. + std::chrono::time_point<std::chrono::steady_clock> m_interrupt_time; + uint32_t m_async_count; + bool m_is_running; + bool m_should_stop; // Whether we should resume after a stop. + // end of continue thread synchronization block + + // This handles the synchronization between individual async threads. For now + // they just use a + // simple mutex. + std::recursive_mutex m_async_mutex; + + bool ShouldStop(const UnixSignals &signals, + StringExtractorGDBRemote &response); + + class ContinueLock { + public: + enum class LockResult { Success, Cancelled, Failed }; + + explicit ContinueLock(GDBRemoteClientBase &comm); + ~ContinueLock(); + explicit operator bool() { return m_acquired; } + + LockResult lock(); + + void unlock(); + + private: + GDBRemoteClientBase &m_comm; + bool m_acquired; + }; +}; + +} // namespace process_gdb_remote +} // namespace lldb_private + +#endif // liblldb_GDBRemoteCommunicationClient_h_ diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index f164b14..bd87521 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -7,7 +7,6 @@ // //===----------------------------------------------------------------------===// - #include "GDBRemoteCommunication.h" // C Includes @@ -29,25 +28,25 @@ #include "lldb/Host/Socket.h" #include "lldb/Host/StringConvert.h" #include "lldb/Host/ThreadLauncher.h" -#include "lldb/Host/TimeValue.h" #include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" #include "llvm/ADT/SmallString.h" +#include "llvm/Support/ScopedPrinter.h" // Project includes #include "ProcessGDBRemoteLog.h" #if defined(__APPLE__) -# define DEBUGSERVER_BASENAME "debugserver" +#define DEBUGSERVER_BASENAME "debugserver" #else -# define DEBUGSERVER_BASENAME "lldb-server" +#define DEBUGSERVER_BASENAME "lldb-server" #endif -#if defined (HAVE_LIBCOMPRESSION) +#if defined(HAVE_LIBCOMPRESSION) #include <compression.h> #endif -#if defined (HAVE_LIBZ) +#if defined(HAVE_LIBZ) #include <zlib.h> #endif @@ -55,1449 +54,1309 @@ using namespace lldb; using namespace lldb_private; using namespace lldb_private::process_gdb_remote; -GDBRemoteCommunication::History::History (uint32_t size) : - m_packets(), - m_curr_idx (0), - m_total_packet_count (0), - m_dumped_to_log (false) -{ - m_packets.resize(size); +GDBRemoteCommunication::History::History(uint32_t size) + : m_packets(), m_curr_idx(0), m_total_packet_count(0), + m_dumped_to_log(false) { + m_packets.resize(size); } -GDBRemoteCommunication::History::~History () -{ +GDBRemoteCommunication::History::~History() {} + +void GDBRemoteCommunication::History::AddPacket(char packet_char, + PacketType type, + uint32_t bytes_transmitted) { + const size_t size = m_packets.size(); + if (size > 0) { + const uint32_t idx = GetNextIndex(); + m_packets[idx].packet.assign(1, packet_char); + m_packets[idx].type = type; + m_packets[idx].bytes_transmitted = bytes_transmitted; + m_packets[idx].packet_idx = m_total_packet_count; + m_packets[idx].tid = Host::GetCurrentThreadID(); + } } -void -GDBRemoteCommunication::History::AddPacket (char packet_char, - PacketType type, - uint32_t bytes_transmitted) -{ - const size_t size = m_packets.size(); - if (size > 0) - { - const uint32_t idx = GetNextIndex(); - m_packets[idx].packet.assign (1, packet_char); - m_packets[idx].type = type; - m_packets[idx].bytes_transmitted = bytes_transmitted; - m_packets[idx].packet_idx = m_total_packet_count; - m_packets[idx].tid = Host::GetCurrentThreadID(); - } +void GDBRemoteCommunication::History::AddPacket(const std::string &src, + uint32_t src_len, + PacketType type, + uint32_t bytes_transmitted) { + const size_t size = m_packets.size(); + if (size > 0) { + const uint32_t idx = GetNextIndex(); + m_packets[idx].packet.assign(src, 0, src_len); + m_packets[idx].type = type; + m_packets[idx].bytes_transmitted = bytes_transmitted; + m_packets[idx].packet_idx = m_total_packet_count; + m_packets[idx].tid = Host::GetCurrentThreadID(); + } } -void -GDBRemoteCommunication::History::AddPacket (const std::string &src, - uint32_t src_len, - PacketType type, - uint32_t bytes_transmitted) -{ - const size_t size = m_packets.size(); - if (size > 0) - { - const uint32_t idx = GetNextIndex(); - m_packets[idx].packet.assign (src, 0, src_len); - m_packets[idx].type = type; - m_packets[idx].bytes_transmitted = bytes_transmitted; - m_packets[idx].packet_idx = m_total_packet_count; - m_packets[idx].tid = Host::GetCurrentThreadID(); - } +void GDBRemoteCommunication::History::Dump(Stream &strm) const { + const uint32_t size = GetNumPacketsInHistory(); + const uint32_t first_idx = GetFirstSavedPacketIndex(); + const uint32_t stop_idx = m_curr_idx + size; + for (uint32_t i = first_idx; i < stop_idx; ++i) { + const uint32_t idx = NormalizeIndex(i); + const Entry &entry = m_packets[idx]; + if (entry.type == ePacketTypeInvalid || entry.packet.empty()) + break; + strm.Printf("history[%u] tid=0x%4.4" PRIx64 " <%4u> %s packet: %s\n", + entry.packet_idx, entry.tid, entry.bytes_transmitted, + (entry.type == ePacketTypeSend) ? "send" : "read", + entry.packet.c_str()); + } } -void -GDBRemoteCommunication::History::Dump (Stream &strm) const -{ - const uint32_t size = GetNumPacketsInHistory (); - const uint32_t first_idx = GetFirstSavedPacketIndex (); +void GDBRemoteCommunication::History::Dump(Log *log) const { + if (log && !m_dumped_to_log) { + m_dumped_to_log = true; + const uint32_t size = GetNumPacketsInHistory(); + const uint32_t first_idx = GetFirstSavedPacketIndex(); const uint32_t stop_idx = m_curr_idx + size; - for (uint32_t i = first_idx; i < stop_idx; ++i) - { - const uint32_t idx = NormalizeIndex (i); - const Entry &entry = m_packets[idx]; - if (entry.type == ePacketTypeInvalid || entry.packet.empty()) - break; - strm.Printf ("history[%u] tid=0x%4.4" PRIx64 " <%4u> %s packet: %s\n", - entry.packet_idx, - entry.tid, - entry.bytes_transmitted, - (entry.type == ePacketTypeSend) ? "send" : "read", - entry.packet.c_str()); - } -} - -void -GDBRemoteCommunication::History::Dump (Log *log) const -{ - if (log && !m_dumped_to_log) - { - m_dumped_to_log = true; - const uint32_t size = GetNumPacketsInHistory (); - const uint32_t first_idx = GetFirstSavedPacketIndex (); - const uint32_t stop_idx = m_curr_idx + size; - for (uint32_t i = first_idx; i < stop_idx; ++i) - { - const uint32_t idx = NormalizeIndex (i); - const Entry &entry = m_packets[idx]; - if (entry.type == ePacketTypeInvalid || entry.packet.empty()) - break; - log->Printf ("history[%u] tid=0x%4.4" PRIx64 " <%4u> %s packet: %s", - entry.packet_idx, - entry.tid, - entry.bytes_transmitted, - (entry.type == ePacketTypeSend) ? "send" : "read", - entry.packet.c_str()); - } + for (uint32_t i = first_idx; i < stop_idx; ++i) { + const uint32_t idx = NormalizeIndex(i); + const Entry &entry = m_packets[idx]; + if (entry.type == ePacketTypeInvalid || entry.packet.empty()) + break; + log->Printf("history[%u] tid=0x%4.4" PRIx64 " <%4u> %s packet: %s", + entry.packet_idx, entry.tid, entry.bytes_transmitted, + (entry.type == ePacketTypeSend) ? "send" : "read", + entry.packet.c_str()); } + } } //---------------------------------------------------------------------- // GDBRemoteCommunication constructor //---------------------------------------------------------------------- -GDBRemoteCommunication::GDBRemoteCommunication(const char *comm_name, - const char *listener_name) : - Communication(comm_name), +GDBRemoteCommunication::GDBRemoteCommunication(const char *comm_name, + const char *listener_name) + : Communication(comm_name), #ifdef LLDB_CONFIGURATION_DEBUG - m_packet_timeout (1000), + m_packet_timeout(1000), #else - m_packet_timeout (1), + m_packet_timeout(1), #endif - m_echo_number(0), - m_supports_qEcho (eLazyBoolCalculate), - m_sequence_mutex (Mutex::eMutexTypeRecursive), - m_public_is_running (false), - m_private_is_running (false), - m_history (512), - m_send_acks (true), - m_compression_type (CompressionType::None), - m_listen_url () -{ + m_echo_number(0), m_supports_qEcho(eLazyBoolCalculate), m_history(512), + m_send_acks(true), m_compression_type(CompressionType::None), + m_listen_url() { } //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- -GDBRemoteCommunication::~GDBRemoteCommunication() -{ - if (IsConnected()) - { - Disconnect(); - } - - // Stop the communications read thread which is used to parse all - // incoming packets. This function will block until the read - // thread returns. - if (m_read_thread_enabled) - StopReadThread(); +GDBRemoteCommunication::~GDBRemoteCommunication() { + if (IsConnected()) { + Disconnect(); + } + + // Stop the communications read thread which is used to parse all + // incoming packets. This function will block until the read + // thread returns. + if (m_read_thread_enabled) + StopReadThread(); } -char -GDBRemoteCommunication::CalculcateChecksum (const char *payload, size_t payload_length) -{ - int checksum = 0; +char GDBRemoteCommunication::CalculcateChecksum(llvm::StringRef payload) { + int checksum = 0; - for (size_t i = 0; i < payload_length; ++i) - checksum += payload[i]; + for (char c : payload) + checksum += c; - return checksum & 255; + return checksum & 255; } -size_t -GDBRemoteCommunication::SendAck () -{ - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS)); - ConnectionStatus status = eConnectionStatusSuccess; - char ch = '+'; - const size_t bytes_written = Write (&ch, 1, status, NULL); - if (log) - log->Printf ("<%4" PRIu64 "> send packet: %c", (uint64_t)bytes_written, ch); - m_history.AddPacket (ch, History::ePacketTypeSend, bytes_written); - return bytes_written; +size_t GDBRemoteCommunication::SendAck() { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS)); + ConnectionStatus status = eConnectionStatusSuccess; + char ch = '+'; + const size_t bytes_written = Write(&ch, 1, status, NULL); + if (log) + log->Printf("<%4" PRIu64 "> send packet: %c", (uint64_t)bytes_written, ch); + m_history.AddPacket(ch, History::ePacketTypeSend, bytes_written); + return bytes_written; } -size_t -GDBRemoteCommunication::SendNack () -{ - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS)); - ConnectionStatus status = eConnectionStatusSuccess; - char ch = '-'; - const size_t bytes_written = Write (&ch, 1, status, NULL); - if (log) - log->Printf("<%4" PRIu64 "> send packet: %c", (uint64_t)bytes_written, ch); - m_history.AddPacket (ch, History::ePacketTypeSend, bytes_written); - return bytes_written; +size_t GDBRemoteCommunication::SendNack() { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS)); + ConnectionStatus status = eConnectionStatusSuccess; + char ch = '-'; + const size_t bytes_written = Write(&ch, 1, status, NULL); + if (log) + log->Printf("<%4" PRIu64 "> send packet: %c", (uint64_t)bytes_written, ch); + m_history.AddPacket(ch, History::ePacketTypeSend, bytes_written); + return bytes_written; } GDBRemoteCommunication::PacketResult -GDBRemoteCommunication::SendPacket (const char *payload, size_t payload_length) -{ - Mutex::Locker locker(m_sequence_mutex); - return SendPacketNoLock (payload, payload_length); -} +GDBRemoteCommunication::SendPacketNoLock(llvm::StringRef payload) { + if (IsConnected()) { + StreamString packet(0, 4, eByteOrderBig); -GDBRemoteCommunication::PacketResult -GDBRemoteCommunication::SendPacketNoLock (const char *payload, size_t payload_length) -{ - if (IsConnected()) - { - StreamString packet(0, 4, eByteOrderBig); - - packet.PutChar('$'); - packet.Write (payload, payload_length); - packet.PutChar('#'); - packet.PutHex8(CalculcateChecksum (payload, payload_length)); - - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS)); - ConnectionStatus status = eConnectionStatusSuccess; - const char *packet_data = packet.GetData(); - const size_t packet_length = packet.GetSize(); - size_t bytes_written = Write (packet_data, packet_length, status, NULL); - if (log) - { - size_t binary_start_offset = 0; - if (strncmp(packet_data, "$vFile:pwrite:", strlen("$vFile:pwrite:")) == 0) - { - const char *first_comma = strchr(packet_data, ','); - if (first_comma) - { - const char *second_comma = strchr(first_comma + 1, ','); - if (second_comma) - binary_start_offset = second_comma - packet_data + 1; - } - } - - // If logging was just enabled and we have history, then dump out what - // we have to the log so we get the historical context. The Dump() call that - // logs all of the packet will set a boolean so that we don't dump this more - // than once - if (!m_history.DidDumpToLog ()) - m_history.Dump (log); - - if (binary_start_offset) - { - StreamString strm; - // Print non binary data header - strm.Printf("<%4" PRIu64 "> send packet: %.*s", (uint64_t)bytes_written, (int)binary_start_offset, packet_data); - const uint8_t *p; - // Print binary data exactly as sent - for (p = (const uint8_t*)packet_data + binary_start_offset; *p != '#'; ++p) - strm.Printf("\\x%2.2x", *p); - // Print the checksum - strm.Printf("%*s", (int)3, p); - log->PutCString(strm.GetString().c_str()); - } - else - log->Printf("<%4" PRIu64 "> send packet: %.*s", (uint64_t)bytes_written, (int)packet_length, packet_data); - } + packet.PutChar('$'); + packet.Write(payload.data(), payload.size()); + packet.PutChar('#'); + packet.PutHex8(CalculcateChecksum(payload)); - m_history.AddPacket (packet.GetString(), packet_length, History::ePacketTypeSend, bytes_written); - - - if (bytes_written == packet_length) - { - if (GetSendAcks ()) - return GetAck (); - else - return PacketResult::Success; - } - else - { - if (log) - log->Printf ("error: failed to send packet: %.*s", (int)packet_length, packet_data); + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS)); + ConnectionStatus status = eConnectionStatusSuccess; + // TODO: Don't shimmy through a std::string, just use StringRef. + std::string packet_str = packet.GetString(); + const char *packet_data = packet_str.c_str(); + const size_t packet_length = packet.GetSize(); + size_t bytes_written = Write(packet_data, packet_length, status, NULL); + if (log) { + size_t binary_start_offset = 0; + if (strncmp(packet_data, "$vFile:pwrite:", strlen("$vFile:pwrite:")) == + 0) { + const char *first_comma = strchr(packet_data, ','); + if (first_comma) { + const char *second_comma = strchr(first_comma + 1, ','); + if (second_comma) + binary_start_offset = second_comma - packet_data + 1; } + } + + // If logging was just enabled and we have history, then dump out what + // we have to the log so we get the historical context. The Dump() call + // that + // logs all of the packet will set a boolean so that we don't dump this + // more + // than once + if (!m_history.DidDumpToLog()) + m_history.Dump(log); + + if (binary_start_offset) { + StreamString strm; + // Print non binary data header + strm.Printf("<%4" PRIu64 "> send packet: %.*s", (uint64_t)bytes_written, + (int)binary_start_offset, packet_data); + const uint8_t *p; + // Print binary data exactly as sent + for (p = (const uint8_t *)packet_data + binary_start_offset; *p != '#'; + ++p) + strm.Printf("\\x%2.2x", *p); + // Print the checksum + strm.Printf("%*s", (int)3, p); + log->PutString(strm.GetString()); + } else + log->Printf("<%4" PRIu64 "> send packet: %.*s", (uint64_t)bytes_written, + (int)packet_length, packet_data); } - return PacketResult::ErrorSendFailed; -} -GDBRemoteCommunication::PacketResult -GDBRemoteCommunication::GetAck () -{ - StringExtractorGDBRemote packet; - PacketResult result = ReadPacket (packet, GetPacketTimeoutInMicroSeconds (), false); - if (result == PacketResult::Success) - { - if (packet.GetResponseType() == StringExtractorGDBRemote::ResponseType::eAck) - return PacketResult::Success; - else - return PacketResult::ErrorSendAck; - } - return result; -} + m_history.AddPacket(packet.GetString(), packet_length, + History::ePacketTypeSend, bytes_written); -bool -GDBRemoteCommunication::GetSequenceMutex (Mutex::Locker& locker, const char *failure_message) -{ - if (IsRunning()) - return locker.TryLock (m_sequence_mutex, failure_message); - - locker.Lock (m_sequence_mutex); - return true; + if (bytes_written == packet_length) { + if (GetSendAcks()) + return GetAck(); + else + return PacketResult::Success; + } else { + if (log) + log->Printf("error: failed to send packet: %.*s", (int)packet_length, + packet_data); + } + } + return PacketResult::ErrorSendFailed; } - -bool -GDBRemoteCommunication::WaitForNotRunningPrivate (const TimeValue *timeout_ptr) -{ - return m_private_is_running.WaitForValueEqualTo (false, timeout_ptr, NULL); +GDBRemoteCommunication::PacketResult GDBRemoteCommunication::GetAck() { + StringExtractorGDBRemote packet; + PacketResult result = ReadPacket(packet, GetPacketTimeout(), false); + if (result == PacketResult::Success) { + if (packet.GetResponseType() == + StringExtractorGDBRemote::ResponseType::eAck) + return PacketResult::Success; + else + return PacketResult::ErrorSendAck; + } + return result; } GDBRemoteCommunication::PacketResult -GDBRemoteCommunication::ReadPacket (StringExtractorGDBRemote &response, uint32_t timeout_usec, bool sync_on_timeout) -{ - if (m_read_thread_enabled) - return PopPacketFromQueue (response, timeout_usec); - else - return WaitForPacketWithTimeoutMicroSecondsNoLock (response, timeout_usec, sync_on_timeout); +GDBRemoteCommunication::ReadPacket(StringExtractorGDBRemote &response, + Timeout<std::micro> timeout, + bool sync_on_timeout) { + if (m_read_thread_enabled) + return PopPacketFromQueue(response, timeout); + else + return WaitForPacketNoLock(response, timeout, sync_on_timeout); } - // This function is called when a packet is requested. // A whole packet is popped from the packet queue and returned to the caller. // Packets are placed into this queue from the communication read thread. // See GDBRemoteCommunication::AppendBytesToCache. GDBRemoteCommunication::PacketResult -GDBRemoteCommunication::PopPacketFromQueue (StringExtractorGDBRemote &response, uint32_t timeout_usec) -{ - // Calculate absolute timeout value - TimeValue timeout = TimeValue::Now(); - timeout.OffsetWithMicroSeconds(timeout_usec); - - do - { - // scope for the mutex - { - // lock down the packet queue - Mutex::Locker locker(m_packet_queue_mutex); - - // Wait on condition variable. - if (m_packet_queue.size() == 0) - m_condition_queue_not_empty.Wait(m_packet_queue_mutex, &timeout); - - if (m_packet_queue.size() > 0) - { - // get the front element of the queue - response = m_packet_queue.front(); - - // remove the front element - m_packet_queue.pop(); - - // we got a packet - return PacketResult::Success; - } - } - - // Disconnected - if (!IsConnected()) - return PacketResult::ErrorDisconnected; - - // Loop while not timed out - } while (TimeValue::Now() < timeout); - - return PacketResult::ErrorReplyTimeout; +GDBRemoteCommunication::PopPacketFromQueue(StringExtractorGDBRemote &response, + Timeout<std::micro> timeout) { + auto pred = [&] { return !m_packet_queue.empty() && IsConnected(); }; + // lock down the packet queue + std::unique_lock<std::mutex> lock(m_packet_queue_mutex); + + if (!timeout) + m_condition_queue_not_empty.wait(lock, pred); + else { + if (!m_condition_queue_not_empty.wait_for(lock, *timeout, pred)) + return PacketResult::ErrorReplyTimeout; + if (!IsConnected()) + return PacketResult::ErrorDisconnected; + } + + // get the front element of the queue + response = m_packet_queue.front(); + + // remove the front element + m_packet_queue.pop(); + + // we got a packet + return PacketResult::Success; } - GDBRemoteCommunication::PacketResult -GDBRemoteCommunication::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtractorGDBRemote &packet, uint32_t timeout_usec, bool sync_on_timeout) -{ - uint8_t buffer[8192]; - Error error; +GDBRemoteCommunication::WaitForPacketNoLock(StringExtractorGDBRemote &packet, + Timeout<std::micro> timeout, + bool sync_on_timeout) { + uint8_t buffer[8192]; + Error error; - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS | GDBR_LOG_VERBOSE)); + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS | + GDBR_LOG_VERBOSE)); - // Check for a packet from our cache first without trying any reading... - if (CheckForPacket(NULL, 0, packet) != PacketType::Invalid) - return PacketResult::Success; + // Check for a packet from our cache first without trying any reading... + if (CheckForPacket(NULL, 0, packet) != PacketType::Invalid) + return PacketResult::Success; - bool timed_out = false; - bool disconnected = false; - while (IsConnected() && !timed_out) - { - lldb::ConnectionStatus status = eConnectionStatusNoConnection; - size_t bytes_read = Read (buffer, sizeof(buffer), timeout_usec, status, &error); - - if (log) - log->Printf ("%s: Read (buffer, (sizeof(buffer), timeout_usec = 0x%x, status = %s, error = %s) => bytes_read = %" PRIu64, - __PRETTY_FUNCTION__, - timeout_usec, - Communication::ConnectionStatusAsCString (status), - error.AsCString(), - (uint64_t)bytes_read); - - if (bytes_read > 0) - { - if (CheckForPacket(buffer, bytes_read, packet) != PacketType::Invalid) - return PacketResult::Success; - } - else - { - switch (status) - { - case eConnectionStatusTimedOut: - case eConnectionStatusInterrupted: - if (sync_on_timeout) - { - //------------------------------------------------------------------ - /// Sync the remote GDB server and make sure we get a response that - /// corresponds to what we send. - /// - /// Sends a "qEcho" packet and makes sure it gets the exact packet - /// echoed back. If the qEcho packet isn't supported, we send a qC - /// packet and make sure we get a valid thread ID back. We use the - /// "qC" packet since its response if very unique: is responds with - /// "QC%x" where %x is the thread ID of the current thread. This - /// makes the response unique enough from other packet responses to - /// ensure we are back on track. - /// - /// This packet is needed after we time out sending a packet so we - /// can ensure that we are getting the response for the packet we - /// are sending. There are no sequence IDs in the GDB remote - /// protocol (there used to be, but they are not supported anymore) - /// so if you timeout sending packet "abc", you might then send - /// packet "cde" and get the response for the previous "abc" packet. - /// Many responses are "OK" or "" (unsupported) or "EXX" (error) so - /// many responses for packets can look like responses for other - /// packets. So if we timeout, we need to ensure that we can get - /// back on track. If we can't get back on track, we must - /// disconnect. - //------------------------------------------------------------------ - bool sync_success = false; - bool got_actual_response = false; - // We timed out, we need to sync back up with the - char echo_packet[32]; - int echo_packet_len = 0; - RegularExpression response_regex; - - if (m_supports_qEcho == eLazyBoolYes) - { - echo_packet_len = ::snprintf (echo_packet, sizeof(echo_packet), "qEcho:%u", ++m_echo_number); - std::string regex_str = "^"; - regex_str += echo_packet; - regex_str += "$"; - response_regex.Compile(regex_str.c_str()); - } - else - { - echo_packet_len = ::snprintf (echo_packet, sizeof(echo_packet), "qC"); - response_regex.Compile("^QC[0-9A-Fa-f]+$"); - } - - PacketResult echo_packet_result = SendPacketNoLock (echo_packet, echo_packet_len); - if (echo_packet_result == PacketResult::Success) - { - const uint32_t max_retries = 3; - uint32_t successful_responses = 0; - for (uint32_t i=0; i<max_retries; ++i) - { - StringExtractorGDBRemote echo_response; - echo_packet_result = WaitForPacketWithTimeoutMicroSecondsNoLock (echo_response, timeout_usec, false); - if (echo_packet_result == PacketResult::Success) - { - ++successful_responses; - if (response_regex.Execute(echo_response.GetStringRef().c_str())) - { - sync_success = true; - break; - } - else if (successful_responses == 1) - { - // We got something else back as the first successful response, it probably is - // the response to the packet we actually wanted, so copy it over if this - // is the first success and continue to try to get the qEcho response - packet = echo_response; - got_actual_response = true; - } - } - else if (echo_packet_result == PacketResult::ErrorReplyTimeout) - continue; // Packet timed out, continue waiting for a response - else - break; // Something else went wrong getting the packet back, we failed and are done trying - } - } - - // We weren't able to sync back up with the server, we must abort otherwise - // all responses might not be from the right packets... - if (sync_success) - { - // We timed out, but were able to recover - if (got_actual_response) - { - // We initially timed out, but we did get a response that came in before the successful - // reply to our qEcho packet, so lets say everything is fine... - return PacketResult::Success; - } - } - else - { - disconnected = true; - Disconnect(); - } + bool timed_out = false; + bool disconnected = false; + while (IsConnected() && !timed_out) { + lldb::ConnectionStatus status = eConnectionStatusNoConnection; + size_t bytes_read = Read(buffer, sizeof(buffer), timeout, status, &error); + + if (log) + log->Printf("%s: Read (buffer, (sizeof(buffer), timeout = %ld us, " + "status = %s, error = %s) => bytes_read = %" PRIu64, + LLVM_PRETTY_FUNCTION, long(timeout ? timeout->count() : -1), + Communication::ConnectionStatusAsCString(status), + error.AsCString(), (uint64_t)bytes_read); + + if (bytes_read > 0) { + if (CheckForPacket(buffer, bytes_read, packet) != PacketType::Invalid) + return PacketResult::Success; + } else { + switch (status) { + case eConnectionStatusTimedOut: + case eConnectionStatusInterrupted: + if (sync_on_timeout) { + //------------------------------------------------------------------ + /// Sync the remote GDB server and make sure we get a response that + /// corresponds to what we send. + /// + /// Sends a "qEcho" packet and makes sure it gets the exact packet + /// echoed back. If the qEcho packet isn't supported, we send a qC + /// packet and make sure we get a valid thread ID back. We use the + /// "qC" packet since its response if very unique: is responds with + /// "QC%x" where %x is the thread ID of the current thread. This + /// makes the response unique enough from other packet responses to + /// ensure we are back on track. + /// + /// This packet is needed after we time out sending a packet so we + /// can ensure that we are getting the response for the packet we + /// are sending. There are no sequence IDs in the GDB remote + /// protocol (there used to be, but they are not supported anymore) + /// so if you timeout sending packet "abc", you might then send + /// packet "cde" and get the response for the previous "abc" packet. + /// Many responses are "OK" or "" (unsupported) or "EXX" (error) so + /// many responses for packets can look like responses for other + /// packets. So if we timeout, we need to ensure that we can get + /// back on track. If we can't get back on track, we must + /// disconnect. + //------------------------------------------------------------------ + bool sync_success = false; + bool got_actual_response = false; + // We timed out, we need to sync back up with the + char echo_packet[32]; + int echo_packet_len = 0; + RegularExpression response_regex; + + if (m_supports_qEcho == eLazyBoolYes) { + echo_packet_len = ::snprintf(echo_packet, sizeof(echo_packet), + "qEcho:%u", ++m_echo_number); + std::string regex_str = "^"; + regex_str += echo_packet; + regex_str += "$"; + response_regex.Compile(regex_str); + } else { + echo_packet_len = + ::snprintf(echo_packet, sizeof(echo_packet), "qC"); + response_regex.Compile(llvm::StringRef("^QC[0-9A-Fa-f]+$")); + } + + PacketResult echo_packet_result = + SendPacketNoLock(llvm::StringRef(echo_packet, echo_packet_len)); + if (echo_packet_result == PacketResult::Success) { + const uint32_t max_retries = 3; + uint32_t successful_responses = 0; + for (uint32_t i = 0; i < max_retries; ++i) { + StringExtractorGDBRemote echo_response; + echo_packet_result = + WaitForPacketNoLock(echo_response, timeout, false); + if (echo_packet_result == PacketResult::Success) { + ++successful_responses; + if (response_regex.Execute(echo_response.GetStringRef())) { + sync_success = true; + break; + } else if (successful_responses == 1) { + // We got something else back as the first successful + // response, it probably is + // the response to the packet we actually wanted, so copy it + // over if this + // is the first success and continue to try to get the qEcho + // response + packet = echo_response; + got_actual_response = true; } - timed_out = true; - break; - case eConnectionStatusSuccess: - //printf ("status = success but error = %s\n", error.AsCString("<invalid>")); - break; - - case eConnectionStatusEndOfFile: - case eConnectionStatusNoConnection: - case eConnectionStatusLostConnection: - case eConnectionStatusError: - disconnected = true; - Disconnect(); - break; + } else if (echo_packet_result == PacketResult::ErrorReplyTimeout) + continue; // Packet timed out, continue waiting for a response + else + break; // Something else went wrong getting the packet back, we + // failed and are done trying } + } + + // We weren't able to sync back up with the server, we must abort + // otherwise + // all responses might not be from the right packets... + if (sync_success) { + // We timed out, but were able to recover + if (got_actual_response) { + // We initially timed out, but we did get a response that came in + // before the successful + // reply to our qEcho packet, so lets say everything is fine... + return PacketResult::Success; + } + } else { + disconnected = true; + Disconnect(); + } } + timed_out = true; + break; + case eConnectionStatusSuccess: + // printf ("status = success but error = %s\n", + // error.AsCString("<invalid>")); + break; + + case eConnectionStatusEndOfFile: + case eConnectionStatusNoConnection: + case eConnectionStatusLostConnection: + case eConnectionStatusError: + disconnected = true; + Disconnect(); + break; + } } - packet.Clear (); - if (disconnected) - return PacketResult::ErrorDisconnected; - if (timed_out) - return PacketResult::ErrorReplyTimeout; - else - return PacketResult::ErrorReplyFailed; + } + packet.Clear(); + if (disconnected) + return PacketResult::ErrorDisconnected; + if (timed_out) + return PacketResult::ErrorReplyTimeout; + else + return PacketResult::ErrorReplyFailed; } -bool -GDBRemoteCommunication::DecompressPacket () -{ - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS)); - - if (!CompressionIsEnabled()) - return true; - - size_t pkt_size = m_bytes.size(); - - // Smallest possible compressed packet is $N#00 - an uncompressed empty reply, most commonly indicating - // an unsupported packet. Anything less than 5 characters, it's definitely not a compressed packet. - if (pkt_size < 5) - return true; - - if (m_bytes[0] != '$' && m_bytes[0] != '%') - return true; - if (m_bytes[1] != 'C' && m_bytes[1] != 'N') - return true; - - size_t hash_mark_idx = m_bytes.find ('#'); - if (hash_mark_idx == std::string::npos) - return true; - if (hash_mark_idx + 2 >= m_bytes.size()) - return true; - - if (!::isxdigit (m_bytes[hash_mark_idx + 1]) || !::isxdigit (m_bytes[hash_mark_idx + 2])) - return true; - - size_t content_length = pkt_size - 5; // not counting '$', 'C' | 'N', '#', & the two hex checksum chars - size_t content_start = 2; // The first character of the compressed/not-compressed text of the packet - size_t checksum_idx = hash_mark_idx + 1; // The first character of the two hex checksum characters - - // Normally size_of_first_packet == m_bytes.size() but m_bytes may contain multiple packets. - // size_of_first_packet is the size of the initial packet which we'll replace with the decompressed - // version of, leaving the rest of m_bytes unmodified. - size_t size_of_first_packet = hash_mark_idx + 3; - - // Compressed packets ("$C") start with a base10 number which is the size of the uncompressed payload, - // then a : and then the compressed data. e.g. $C1024:<binary>#00 - // Update content_start and content_length to only include the <binary> part of the packet. - - uint64_t decompressed_bufsize = ULONG_MAX; - if (m_bytes[1] == 'C') - { - size_t i = content_start; - while (i < hash_mark_idx && isdigit(m_bytes[i])) - i++; - if (i < hash_mark_idx && m_bytes[i] == ':') - { - i++; - content_start = i; - content_length = hash_mark_idx - content_start; - std::string bufsize_str (m_bytes.data() + 2, i - 2 - 1); - errno = 0; - decompressed_bufsize = ::strtoul (bufsize_str.c_str(), NULL, 10); - if (errno != 0 || decompressed_bufsize == ULONG_MAX) - { - m_bytes.erase (0, size_of_first_packet); - return false; - } - } - } +bool GDBRemoteCommunication::DecompressPacket() { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS)); - if (GetSendAcks ()) - { - char packet_checksum_cstr[3]; - packet_checksum_cstr[0] = m_bytes[checksum_idx]; - packet_checksum_cstr[1] = m_bytes[checksum_idx + 1]; - packet_checksum_cstr[2] = '\0'; - long packet_checksum = strtol (packet_checksum_cstr, NULL, 16); - - long actual_checksum = CalculcateChecksum (m_bytes.data() + 1, hash_mark_idx - 1); - bool success = packet_checksum == actual_checksum; - if (!success) - { - if (log) - log->Printf ("error: checksum mismatch: %.*s expected 0x%2.2x, got 0x%2.2x", - (int)(pkt_size), - m_bytes.c_str(), - (uint8_t)packet_checksum, - (uint8_t)actual_checksum); - } - // Send the ack or nack if needed - if (!success) - { - SendNack(); - m_bytes.erase (0, size_of_first_packet); - return false; - } - else - { - SendAck(); - } - } + if (!CompressionIsEnabled()) + return true; - if (m_bytes[1] == 'N') - { - // This packet was not compressed -- delete the 'N' character at the - // start and the packet may be processed as-is. - m_bytes.erase(1, 1); - return true; - } + size_t pkt_size = m_bytes.size(); - // Reverse the gdb-remote binary escaping that was done to the compressed text to - // guard characters like '$', '#', '}', etc. - std::vector<uint8_t> unescaped_content; - unescaped_content.reserve (content_length); - size_t i = content_start; - while (i < hash_mark_idx) - { - if (m_bytes[i] == '}') - { - i++; - unescaped_content.push_back (m_bytes[i] ^ 0x20); - } - else - { - unescaped_content.push_back (m_bytes[i]); - } - i++; - } + // Smallest possible compressed packet is $N#00 - an uncompressed empty reply, + // most commonly indicating + // an unsupported packet. Anything less than 5 characters, it's definitely + // not a compressed packet. + if (pkt_size < 5) + return true; - uint8_t *decompressed_buffer = nullptr; - size_t decompressed_bytes = 0; + if (m_bytes[0] != '$' && m_bytes[0] != '%') + return true; + if (m_bytes[1] != 'C' && m_bytes[1] != 'N') + return true; - if (decompressed_bufsize != ULONG_MAX) - { - decompressed_buffer = (uint8_t *) malloc (decompressed_bufsize + 1); - if (decompressed_buffer == nullptr) - { - m_bytes.erase (0, size_of_first_packet); - return false; - } + size_t hash_mark_idx = m_bytes.find('#'); + if (hash_mark_idx == std::string::npos) + return true; + if (hash_mark_idx + 2 >= m_bytes.size()) + return true; - } + if (!::isxdigit(m_bytes[hash_mark_idx + 1]) || + !::isxdigit(m_bytes[hash_mark_idx + 2])) + return true; -#if defined (HAVE_LIBCOMPRESSION) - // libcompression is weak linked so check that compression_decode_buffer() is available - if (compression_decode_buffer != NULL && - (m_compression_type == CompressionType::ZlibDeflate - || m_compression_type == CompressionType::LZFSE - || m_compression_type == CompressionType::LZ4)) - { - compression_algorithm compression_type; - if (m_compression_type == CompressionType::ZlibDeflate) - compression_type = COMPRESSION_ZLIB; - else if (m_compression_type == CompressionType::LZFSE) - compression_type = COMPRESSION_LZFSE; - else if (m_compression_type == CompressionType::LZ4) - compression_type = COMPRESSION_LZ4_RAW; - else if (m_compression_type == CompressionType::LZMA) - compression_type = COMPRESSION_LZMA; - - - // If we have the expected size of the decompressed payload, we can allocate - // the right-sized buffer and do it. If we don't have that information, we'll - // need to try decoding into a big buffer and if the buffer wasn't big enough, - // increase it and try again. - - if (decompressed_bufsize != ULONG_MAX && decompressed_buffer != nullptr) - { - decompressed_bytes = compression_decode_buffer (decompressed_buffer, decompressed_bufsize + 10 , - (uint8_t*) unescaped_content.data(), - unescaped_content.size(), - NULL, - compression_type); - } + size_t content_length = + pkt_size - + 5; // not counting '$', 'C' | 'N', '#', & the two hex checksum chars + size_t content_start = 2; // The first character of the + // compressed/not-compressed text of the packet + size_t checksum_idx = + hash_mark_idx + + 1; // The first character of the two hex checksum characters + + // Normally size_of_first_packet == m_bytes.size() but m_bytes may contain + // multiple packets. + // size_of_first_packet is the size of the initial packet which we'll replace + // with the decompressed + // version of, leaving the rest of m_bytes unmodified. + size_t size_of_first_packet = hash_mark_idx + 3; + + // Compressed packets ("$C") start with a base10 number which is the size of + // the uncompressed payload, + // then a : and then the compressed data. e.g. $C1024:<binary>#00 + // Update content_start and content_length to only include the <binary> part + // of the packet. + + uint64_t decompressed_bufsize = ULONG_MAX; + if (m_bytes[1] == 'C') { + size_t i = content_start; + while (i < hash_mark_idx && isdigit(m_bytes[i])) + i++; + if (i < hash_mark_idx && m_bytes[i] == ':') { + i++; + content_start = i; + content_length = hash_mark_idx - content_start; + std::string bufsize_str(m_bytes.data() + 2, i - 2 - 1); + errno = 0; + decompressed_bufsize = ::strtoul(bufsize_str.c_str(), NULL, 10); + if (errno != 0 || decompressed_bufsize == ULONG_MAX) { + m_bytes.erase(0, size_of_first_packet); + return false; + } } -#endif - -#if defined (HAVE_LIBZ) - if (decompressed_bytes == 0 - && decompressed_bufsize != ULONG_MAX - && decompressed_buffer != nullptr - && m_compression_type == CompressionType::ZlibDeflate) - { - z_stream stream; - memset (&stream, 0, sizeof (z_stream)); - stream.next_in = (Bytef *) unescaped_content.data(); - stream.avail_in = (uInt) unescaped_content.size(); - stream.total_in = 0; - stream.next_out = (Bytef *) decompressed_buffer; - stream.avail_out = decompressed_bufsize; - stream.total_out = 0; - stream.zalloc = Z_NULL; - stream.zfree = Z_NULL; - stream.opaque = Z_NULL; - - if (inflateInit2 (&stream, -15) == Z_OK) - { - int status = inflate (&stream, Z_NO_FLUSH); - inflateEnd (&stream); - if (status == Z_STREAM_END) - { - decompressed_bytes = stream.total_out; - } - } + } + + if (GetSendAcks()) { + char packet_checksum_cstr[3]; + packet_checksum_cstr[0] = m_bytes[checksum_idx]; + packet_checksum_cstr[1] = m_bytes[checksum_idx + 1]; + packet_checksum_cstr[2] = '\0'; + long packet_checksum = strtol(packet_checksum_cstr, NULL, 16); + + long actual_checksum = CalculcateChecksum( + llvm::StringRef(m_bytes).substr(1, hash_mark_idx - 1)); + bool success = packet_checksum == actual_checksum; + if (!success) { + if (log) + log->Printf( + "error: checksum mismatch: %.*s expected 0x%2.2x, got 0x%2.2x", + (int)(pkt_size), m_bytes.c_str(), (uint8_t)packet_checksum, + (uint8_t)actual_checksum); } -#endif + // Send the ack or nack if needed + if (!success) { + SendNack(); + m_bytes.erase(0, size_of_first_packet); + return false; + } else { + SendAck(); + } + } - if (decompressed_bytes == 0 || decompressed_buffer == nullptr) - { - if (decompressed_buffer) - free (decompressed_buffer); - m_bytes.erase (0, size_of_first_packet); - return false; + if (m_bytes[1] == 'N') { + // This packet was not compressed -- delete the 'N' character at the + // start and the packet may be processed as-is. + m_bytes.erase(1, 1); + return true; + } + + // Reverse the gdb-remote binary escaping that was done to the compressed text + // to + // guard characters like '$', '#', '}', etc. + std::vector<uint8_t> unescaped_content; + unescaped_content.reserve(content_length); + size_t i = content_start; + while (i < hash_mark_idx) { + if (m_bytes[i] == '}') { + i++; + unescaped_content.push_back(m_bytes[i] ^ 0x20); + } else { + unescaped_content.push_back(m_bytes[i]); } + i++; + } + + uint8_t *decompressed_buffer = nullptr; + size_t decompressed_bytes = 0; - std::string new_packet; - new_packet.reserve (decompressed_bytes + 6); - new_packet.push_back (m_bytes[0]); - new_packet.append ((const char *) decompressed_buffer, decompressed_bytes); - new_packet.push_back ('#'); - if (GetSendAcks ()) - { - uint8_t decompressed_checksum = CalculcateChecksum ((const char *) decompressed_buffer, decompressed_bytes); - char decompressed_checksum_str[3]; - snprintf (decompressed_checksum_str, 3, "%02x", decompressed_checksum); - new_packet.append (decompressed_checksum_str); + if (decompressed_bufsize != ULONG_MAX) { + decompressed_buffer = (uint8_t *)malloc(decompressed_bufsize + 1); + if (decompressed_buffer == nullptr) { + m_bytes.erase(0, size_of_first_packet); + return false; } - else - { - new_packet.push_back ('0'); - new_packet.push_back ('0'); + } + +#if defined(HAVE_LIBCOMPRESSION) + // libcompression is weak linked so check that compression_decode_buffer() is + // available + if (compression_decode_buffer != NULL && + (m_compression_type == CompressionType::ZlibDeflate || + m_compression_type == CompressionType::LZFSE || + m_compression_type == CompressionType::LZ4)) { + compression_algorithm compression_type; + if (m_compression_type == CompressionType::ZlibDeflate) + compression_type = COMPRESSION_ZLIB; + else if (m_compression_type == CompressionType::LZFSE) + compression_type = COMPRESSION_LZFSE; + else if (m_compression_type == CompressionType::LZ4) + compression_type = COMPRESSION_LZ4_RAW; + else if (m_compression_type == CompressionType::LZMA) + compression_type = COMPRESSION_LZMA; + + // If we have the expected size of the decompressed payload, we can allocate + // the right-sized buffer and do it. If we don't have that information, + // we'll + // need to try decoding into a big buffer and if the buffer wasn't big + // enough, + // increase it and try again. + + if (decompressed_bufsize != ULONG_MAX && decompressed_buffer != nullptr) { + decompressed_bytes = compression_decode_buffer( + decompressed_buffer, decompressed_bufsize + 10, + (uint8_t *)unescaped_content.data(), unescaped_content.size(), NULL, + compression_type); } + } +#endif - m_bytes.replace (0, size_of_first_packet, new_packet.data(), new_packet.size()); +#if defined(HAVE_LIBZ) + if (decompressed_bytes == 0 && decompressed_bufsize != ULONG_MAX && + decompressed_buffer != nullptr && + m_compression_type == CompressionType::ZlibDeflate) { + z_stream stream; + memset(&stream, 0, sizeof(z_stream)); + stream.next_in = (Bytef *)unescaped_content.data(); + stream.avail_in = (uInt)unescaped_content.size(); + stream.total_in = 0; + stream.next_out = (Bytef *)decompressed_buffer; + stream.avail_out = decompressed_bufsize; + stream.total_out = 0; + stream.zalloc = Z_NULL; + stream.zfree = Z_NULL; + stream.opaque = Z_NULL; + + if (inflateInit2(&stream, -15) == Z_OK) { + int status = inflate(&stream, Z_NO_FLUSH); + inflateEnd(&stream); + if (status == Z_STREAM_END) { + decompressed_bytes = stream.total_out; + } + } + } +#endif - free (decompressed_buffer); - return true; + if (decompressed_bytes == 0 || decompressed_buffer == nullptr) { + if (decompressed_buffer) + free(decompressed_buffer); + m_bytes.erase(0, size_of_first_packet); + return false; + } + + std::string new_packet; + new_packet.reserve(decompressed_bytes + 6); + new_packet.push_back(m_bytes[0]); + new_packet.append((const char *)decompressed_buffer, decompressed_bytes); + new_packet.push_back('#'); + if (GetSendAcks()) { + uint8_t decompressed_checksum = CalculcateChecksum( + llvm::StringRef((const char *)decompressed_buffer, decompressed_bytes)); + char decompressed_checksum_str[3]; + snprintf(decompressed_checksum_str, 3, "%02x", decompressed_checksum); + new_packet.append(decompressed_checksum_str); + } else { + new_packet.push_back('0'); + new_packet.push_back('0'); + } + + m_bytes.replace(0, size_of_first_packet, new_packet.data(), + new_packet.size()); + + free(decompressed_buffer); + return true; } GDBRemoteCommunication::PacketType -GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, StringExtractorGDBRemote &packet) -{ - // Put the packet data into the buffer in a thread safe fashion - std::lock_guard<std::recursive_mutex> guard(m_bytes_mutex); - - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS)); - - if (src && src_len > 0) - { - if (log && log->GetVerbose()) - { - StreamString s; - log->Printf ("GDBRemoteCommunication::%s adding %u bytes: %.*s", - __FUNCTION__, - (uint32_t)src_len, - (uint32_t)src_len, - src); - } - m_bytes.append ((const char *)src, src_len); +GDBRemoteCommunication::CheckForPacket(const uint8_t *src, size_t src_len, + StringExtractorGDBRemote &packet) { + // Put the packet data into the buffer in a thread safe fashion + std::lock_guard<std::recursive_mutex> guard(m_bytes_mutex); + + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS)); + + if (src && src_len > 0) { + if (log && log->GetVerbose()) { + StreamString s; + log->Printf("GDBRemoteCommunication::%s adding %u bytes: %.*s", + __FUNCTION__, (uint32_t)src_len, (uint32_t)src_len, src); + } + m_bytes.append((const char *)src, src_len); + } + + bool isNotifyPacket = false; + + // Parse up the packets into gdb remote packets + if (!m_bytes.empty()) { + // end_idx must be one past the last valid packet byte. Start + // it off with an invalid value that is the same as the current + // index. + size_t content_start = 0; + size_t content_length = 0; + size_t total_length = 0; + size_t checksum_idx = std::string::npos; + + // Size of packet before it is decompressed, for logging purposes + size_t original_packet_size = m_bytes.size(); + if (CompressionIsEnabled()) { + if (DecompressPacket() == false) { + packet.Clear(); + return GDBRemoteCommunication::PacketType::Standard; + } } - bool isNotifyPacket = false; - - // Parse up the packets into gdb remote packets - if (!m_bytes.empty()) - { - // end_idx must be one past the last valid packet byte. Start - // it off with an invalid value that is the same as the current - // index. - size_t content_start = 0; - size_t content_length = 0; - size_t total_length = 0; - size_t checksum_idx = std::string::npos; - - // Size of packet before it is decompressed, for logging purposes - size_t original_packet_size = m_bytes.size(); - if (CompressionIsEnabled()) - { - if (DecompressPacket() == false) - { - packet.Clear(); - return GDBRemoteCommunication::PacketType::Standard; - } + switch (m_bytes[0]) { + case '+': // Look for ack + case '-': // Look for cancel + case '\x03': // ^C to halt target + content_length = total_length = 1; // The command is one byte long... + break; + + case '%': // Async notify packet + isNotifyPacket = true; + LLVM_FALLTHROUGH; + + case '$': + // Look for a standard gdb packet? + { + size_t hash_pos = m_bytes.find('#'); + if (hash_pos != std::string::npos) { + if (hash_pos + 2 < m_bytes.size()) { + checksum_idx = hash_pos + 1; + // Skip the dollar sign + content_start = 1; + // Don't include the # in the content or the $ in the content length + content_length = hash_pos - 1; + + total_length = + hash_pos + 3; // Skip the # and the two hex checksum bytes + } else { + // Checksum bytes aren't all here yet + content_length = std::string::npos; + } } - - switch (m_bytes[0]) - { - case '+': // Look for ack - case '-': // Look for cancel - case '\x03': // ^C to halt target - content_length = total_length = 1; // The command is one byte long... - break; - - case '%': // Async notify packet - isNotifyPacket = true; - LLVM_FALLTHROUGH; - - case '$': - // Look for a standard gdb packet? - { - size_t hash_pos = m_bytes.find('#'); - if (hash_pos != std::string::npos) - { - if (hash_pos + 2 < m_bytes.size()) - { - checksum_idx = hash_pos + 1; - // Skip the dollar sign - content_start = 1; - // Don't include the # in the content or the $ in the content length - content_length = hash_pos - 1; - - total_length = hash_pos + 3; // Skip the # and the two hex checksum bytes - } - else - { - // Checksum bytes aren't all here yet - content_length = std::string::npos; - } - } - } - break; - - default: - { - // We have an unexpected byte and we need to flush all bad - // data that is in m_bytes, so we need to find the first - // byte that is a '+' (ACK), '-' (NACK), \x03 (CTRL+C interrupt), - // or '$' character (start of packet header) or of course, - // the end of the data in m_bytes... - const size_t bytes_len = m_bytes.size(); - bool done = false; - uint32_t idx; - for (idx = 1; !done && idx < bytes_len; ++idx) - { - switch (m_bytes[idx]) - { - case '+': - case '-': - case '\x03': - case '%': - case '$': - done = true; - break; - - default: - break; - } - } - if (log) - log->Printf ("GDBRemoteCommunication::%s tossing %u junk bytes: '%.*s'", - __FUNCTION__, idx - 1, idx - 1, m_bytes.c_str()); - m_bytes.erase(0, idx - 1); - } - break; + } + break; + + default: { + // We have an unexpected byte and we need to flush all bad + // data that is in m_bytes, so we need to find the first + // byte that is a '+' (ACK), '-' (NACK), \x03 (CTRL+C interrupt), + // or '$' character (start of packet header) or of course, + // the end of the data in m_bytes... + const size_t bytes_len = m_bytes.size(); + bool done = false; + uint32_t idx; + for (idx = 1; !done && idx < bytes_len; ++idx) { + switch (m_bytes[idx]) { + case '+': + case '-': + case '\x03': + case '%': + case '$': + done = true; + break; + + default: + break; } + } + if (log) + log->Printf("GDBRemoteCommunication::%s tossing %u junk bytes: '%.*s'", + __FUNCTION__, idx - 1, idx - 1, m_bytes.c_str()); + m_bytes.erase(0, idx - 1); + } break; + } - if (content_length == std::string::npos) - { - packet.Clear(); - return GDBRemoteCommunication::PacketType::Invalid; - } - else if (total_length > 0) - { - - // We have a valid packet... - assert (content_length <= m_bytes.size()); - assert (total_length <= m_bytes.size()); - assert (content_length <= total_length); - size_t content_end = content_start + content_length; - - bool success = true; - std::string &packet_str = packet.GetStringRef(); - if (log) - { - // If logging was just enabled and we have history, then dump out what - // we have to the log so we get the historical context. The Dump() call that - // logs all of the packet will set a boolean so that we don't dump this more - // than once - if (!m_history.DidDumpToLog ()) - m_history.Dump (log); - - bool binary = false; - // Only detect binary for packets that start with a '$' and have a '#CC' checksum - if (m_bytes[0] == '$' && total_length > 4) - { - for (size_t i=0; !binary && i<total_length; ++i) - { - if (isprint (m_bytes[i]) == 0 && isspace (m_bytes[i]) == 0) - { - binary = true; - } - } - } - if (binary) - { - StreamString strm; - // Packet header... - if (CompressionIsEnabled()) - strm.Printf("<%4" PRIu64 ":%" PRIu64 "> read packet: %c", (uint64_t) original_packet_size, (uint64_t)total_length, m_bytes[0]); - else - strm.Printf("<%4" PRIu64 "> read packet: %c", (uint64_t)total_length, m_bytes[0]); - for (size_t i=content_start; i<content_end; ++i) - { - // Remove binary escaped bytes when displaying the packet... - const char ch = m_bytes[i]; - if (ch == 0x7d) - { - // 0x7d is the escape character. The next character is to - // be XOR'd with 0x20. - const char escapee = m_bytes[++i] ^ 0x20; - strm.Printf("%2.2x", escapee); - } - else - { - strm.Printf("%2.2x", (uint8_t)ch); - } - } - // Packet footer... - strm.Printf("%c%c%c", m_bytes[total_length-3], m_bytes[total_length-2], m_bytes[total_length-1]); - log->PutCString(strm.GetString().c_str()); - } - else - { - if (CompressionIsEnabled()) - log->Printf("<%4" PRIu64 ":%" PRIu64 "> read packet: %.*s", (uint64_t) original_packet_size, (uint64_t)total_length, (int)(total_length), m_bytes.c_str()); - else - log->Printf("<%4" PRIu64 "> read packet: %.*s", (uint64_t)total_length, (int)(total_length), m_bytes.c_str()); - } + if (content_length == std::string::npos) { + packet.Clear(); + return GDBRemoteCommunication::PacketType::Invalid; + } else if (total_length > 0) { + + // We have a valid packet... + assert(content_length <= m_bytes.size()); + assert(total_length <= m_bytes.size()); + assert(content_length <= total_length); + size_t content_end = content_start + content_length; + + bool success = true; + std::string &packet_str = packet.GetStringRef(); + if (log) { + // If logging was just enabled and we have history, then dump out what + // we have to the log so we get the historical context. The Dump() call + // that + // logs all of the packet will set a boolean so that we don't dump this + // more + // than once + if (!m_history.DidDumpToLog()) + m_history.Dump(log); + + bool binary = false; + // Only detect binary for packets that start with a '$' and have a '#CC' + // checksum + if (m_bytes[0] == '$' && total_length > 4) { + for (size_t i = 0; !binary && i < total_length; ++i) { + if (isprint(m_bytes[i]) == 0 && isspace(m_bytes[i]) == 0) { + binary = true; } - - m_history.AddPacket (m_bytes.c_str(), total_length, History::ePacketTypeRecv, total_length); - - // Clear packet_str in case there is some existing data in it. - packet_str.clear(); - // Copy the packet from m_bytes to packet_str expanding the - // run-length encoding in the process. - // Reserve enough byte for the most common case (no RLE used) - packet_str.reserve(m_bytes.length()); - for (std::string::const_iterator c = m_bytes.begin() + content_start; c != m_bytes.begin() + content_end; ++c) - { - if (*c == '*') - { - // '*' indicates RLE. Next character will give us the - // repeat count and previous character is what is to be - // repeated. - char char_to_repeat = packet_str.back(); - // Number of time the previous character is repeated - int repeat_count = *++c + 3 - ' '; - // We have the char_to_repeat and repeat_count. Now push - // it in the packet. - for (int i = 0; i < repeat_count; ++i) - packet_str.push_back(char_to_repeat); - } - else if (*c == 0x7d) - { - // 0x7d is the escape character. The next character is to - // be XOR'd with 0x20. - char escapee = *++c ^ 0x20; - packet_str.push_back(escapee); - } - else - { - packet_str.push_back(*c); - } + } + } + if (binary) { + StreamString strm; + // Packet header... + if (CompressionIsEnabled()) + strm.Printf("<%4" PRIu64 ":%" PRIu64 "> read packet: %c", + (uint64_t)original_packet_size, (uint64_t)total_length, + m_bytes[0]); + else + strm.Printf("<%4" PRIu64 "> read packet: %c", + (uint64_t)total_length, m_bytes[0]); + for (size_t i = content_start; i < content_end; ++i) { + // Remove binary escaped bytes when displaying the packet... + const char ch = m_bytes[i]; + if (ch == 0x7d) { + // 0x7d is the escape character. The next character is to + // be XOR'd with 0x20. + const char escapee = m_bytes[++i] ^ 0x20; + strm.Printf("%2.2x", escapee); + } else { + strm.Printf("%2.2x", (uint8_t)ch); } - - if (m_bytes[0] == '$' || m_bytes[0] == '%') - { - assert (checksum_idx < m_bytes.size()); - if (::isxdigit (m_bytes[checksum_idx+0]) || - ::isxdigit (m_bytes[checksum_idx+1])) - { - if (GetSendAcks ()) - { - const char *packet_checksum_cstr = &m_bytes[checksum_idx]; - char packet_checksum = strtol (packet_checksum_cstr, NULL, 16); - char actual_checksum = CalculcateChecksum (packet_str.c_str(), packet_str.size()); - success = packet_checksum == actual_checksum; - if (!success) - { - if (log) - log->Printf ("error: checksum mismatch: %.*s expected 0x%2.2x, got 0x%2.2x", - (int)(total_length), - m_bytes.c_str(), - (uint8_t)packet_checksum, - (uint8_t)actual_checksum); - } - // Send the ack or nack if needed - if (!success) - SendNack(); - else - SendAck(); - } - } - else - { - success = false; - if (log) - log->Printf ("error: invalid checksum in packet: '%s'\n", m_bytes.c_str()); - } + } + // Packet footer... + strm.Printf("%c%c%c", m_bytes[total_length - 3], + m_bytes[total_length - 2], m_bytes[total_length - 1]); + log->PutString(strm.GetString()); + } else { + if (CompressionIsEnabled()) + log->Printf("<%4" PRIu64 ":%" PRIu64 "> read packet: %.*s", + (uint64_t)original_packet_size, (uint64_t)total_length, + (int)(total_length), m_bytes.c_str()); + else + log->Printf("<%4" PRIu64 "> read packet: %.*s", + (uint64_t)total_length, (int)(total_length), + m_bytes.c_str()); + } + } + + m_history.AddPacket(m_bytes, total_length, History::ePacketTypeRecv, + total_length); + + // Clear packet_str in case there is some existing data in it. + packet_str.clear(); + // Copy the packet from m_bytes to packet_str expanding the + // run-length encoding in the process. + // Reserve enough byte for the most common case (no RLE used) + packet_str.reserve(m_bytes.length()); + for (std::string::const_iterator c = m_bytes.begin() + content_start; + c != m_bytes.begin() + content_end; ++c) { + if (*c == '*') { + // '*' indicates RLE. Next character will give us the + // repeat count and previous character is what is to be + // repeated. + char char_to_repeat = packet_str.back(); + // Number of time the previous character is repeated + int repeat_count = *++c + 3 - ' '; + // We have the char_to_repeat and repeat_count. Now push + // it in the packet. + for (int i = 0; i < repeat_count; ++i) + packet_str.push_back(char_to_repeat); + } else if (*c == 0x7d) { + // 0x7d is the escape character. The next character is to + // be XOR'd with 0x20. + char escapee = *++c ^ 0x20; + packet_str.push_back(escapee); + } else { + packet_str.push_back(*c); + } + } + + if (m_bytes[0] == '$' || m_bytes[0] == '%') { + assert(checksum_idx < m_bytes.size()); + if (::isxdigit(m_bytes[checksum_idx + 0]) || + ::isxdigit(m_bytes[checksum_idx + 1])) { + if (GetSendAcks()) { + const char *packet_checksum_cstr = &m_bytes[checksum_idx]; + char packet_checksum = strtol(packet_checksum_cstr, NULL, 16); + char actual_checksum = CalculcateChecksum(packet_str); + success = packet_checksum == actual_checksum; + if (!success) { + if (log) + log->Printf("error: checksum mismatch: %.*s expected 0x%2.2x, " + "got 0x%2.2x", + (int)(total_length), m_bytes.c_str(), + (uint8_t)packet_checksum, (uint8_t)actual_checksum); } - - m_bytes.erase(0, total_length); - packet.SetFilePos(0); - - if (isNotifyPacket) - return GDBRemoteCommunication::PacketType::Notify; + // Send the ack or nack if needed + if (!success) + SendNack(); else - return GDBRemoteCommunication::PacketType::Standard; + SendAck(); + } + } else { + success = false; + if (log) + log->Printf("error: invalid checksum in packet: '%s'\n", + m_bytes.c_str()); } + } + + m_bytes.erase(0, total_length); + packet.SetFilePos(0); + + if (isNotifyPacket) + return GDBRemoteCommunication::PacketType::Notify; + else + return GDBRemoteCommunication::PacketType::Standard; } - packet.Clear(); - return GDBRemoteCommunication::PacketType::Invalid; + } + packet.Clear(); + return GDBRemoteCommunication::PacketType::Invalid; } -Error -GDBRemoteCommunication::StartListenThread (const char *hostname, uint16_t port) -{ - Error error; - if (m_listen_thread.IsJoinable()) - { - error.SetErrorString("listen thread already running"); - } +Error GDBRemoteCommunication::StartListenThread(const char *hostname, + uint16_t port) { + Error error; + if (m_listen_thread.IsJoinable()) { + error.SetErrorString("listen thread already running"); + } else { + char listen_url[512]; + if (hostname && hostname[0]) + snprintf(listen_url, sizeof(listen_url), "listen://%s:%i", hostname, + port); else - { - char listen_url[512]; - if (hostname && hostname[0]) - snprintf(listen_url, sizeof(listen_url), "listen://%s:%i", hostname, port); - else - snprintf(listen_url, sizeof(listen_url), "listen://%i", port); - m_listen_url = listen_url; - SetConnection(new ConnectionFileDescriptor()); - m_listen_thread = ThreadLauncher::LaunchThread(listen_url, GDBRemoteCommunication::ListenThread, this, &error); - } - return error; + snprintf(listen_url, sizeof(listen_url), "listen://%i", port); + m_listen_url = listen_url; + SetConnection(new ConnectionFileDescriptor()); + m_listen_thread = ThreadLauncher::LaunchThread( + listen_url, GDBRemoteCommunication::ListenThread, this, &error); + } + return error; } -bool -GDBRemoteCommunication::JoinListenThread () -{ - if (m_listen_thread.IsJoinable()) - m_listen_thread.Join(nullptr); - return true; +bool GDBRemoteCommunication::JoinListenThread() { + if (m_listen_thread.IsJoinable()) + m_listen_thread.Join(nullptr); + return true; } lldb::thread_result_t -GDBRemoteCommunication::ListenThread (lldb::thread_arg_t arg) -{ - GDBRemoteCommunication *comm = (GDBRemoteCommunication *)arg; - Error error; - ConnectionFileDescriptor *connection = (ConnectionFileDescriptor *)comm->GetConnection (); - - if (connection) - { - // Do the listen on another thread so we can continue on... - if (connection->Connect(comm->m_listen_url.c_str(), &error) != eConnectionStatusSuccess) - comm->SetConnection(NULL); - } - return NULL; +GDBRemoteCommunication::ListenThread(lldb::thread_arg_t arg) { + GDBRemoteCommunication *comm = (GDBRemoteCommunication *)arg; + Error error; + ConnectionFileDescriptor *connection = + (ConnectionFileDescriptor *)comm->GetConnection(); + + if (connection) { + // Do the listen on another thread so we can continue on... + if (connection->Connect(comm->m_listen_url.c_str(), &error) != + eConnectionStatusSuccess) + comm->SetConnection(NULL); + } + return NULL; } -Error -GDBRemoteCommunication::StartDebugserverProcess (const char *url, - Platform *platform, - ProcessLaunchInfo &launch_info, - uint16_t *port, - const Args& inferior_args) -{ - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); +Error GDBRemoteCommunication::StartDebugserverProcess( + const char *url, Platform *platform, ProcessLaunchInfo &launch_info, + uint16_t *port, const Args *inferior_args, int pass_comm_fd) { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + if (log) + log->Printf("GDBRemoteCommunication::%s(url=%s, port=%" PRIu16 ")", + __FUNCTION__, url ? url : "<empty>", + port ? *port : uint16_t(0)); + + Error error; + // If we locate debugserver, keep that located version around + static FileSpec g_debugserver_file_spec; + + char debugserver_path[PATH_MAX]; + FileSpec &debugserver_file_spec = launch_info.GetExecutableFile(); + + // Always check to see if we have an environment override for the path + // to the debugserver to use and use it if we do. + const char *env_debugserver_path = getenv("LLDB_DEBUGSERVER_PATH"); + if (env_debugserver_path) { + debugserver_file_spec.SetFile(env_debugserver_path, false); if (log) - log->Printf ("GDBRemoteCommunication::%s(url=%s, port=%" PRIu16 ")", __FUNCTION__, url ? url : "<empty>", port ? *port : uint16_t(0)); - - Error error; - // If we locate debugserver, keep that located version around - static FileSpec g_debugserver_file_spec; - - char debugserver_path[PATH_MAX]; - FileSpec &debugserver_file_spec = launch_info.GetExecutableFile(); - - // Always check to see if we have an environment override for the path - // to the debugserver to use and use it if we do. - const char *env_debugserver_path = getenv("LLDB_DEBUGSERVER_PATH"); - if (env_debugserver_path) - { - debugserver_file_spec.SetFile (env_debugserver_path, false); + log->Printf("GDBRemoteCommunication::%s() gdb-remote stub exe path set " + "from environment variable: %s", + __FUNCTION__, env_debugserver_path); + } else + debugserver_file_spec = g_debugserver_file_spec; + bool debugserver_exists = debugserver_file_spec.Exists(); + if (!debugserver_exists) { + // The debugserver binary is in the LLDB.framework/Resources + // directory. + if (HostInfo::GetLLDBPath(ePathTypeSupportExecutableDir, + debugserver_file_spec)) { + debugserver_file_spec.AppendPathComponent(DEBUGSERVER_BASENAME); + debugserver_exists = debugserver_file_spec.Exists(); + if (debugserver_exists) { if (log) - log->Printf ("GDBRemoteCommunication::%s() gdb-remote stub exe path set from environment variable: %s", __FUNCTION__, env_debugserver_path); - } - else - debugserver_file_spec = g_debugserver_file_spec; - bool debugserver_exists = debugserver_file_spec.Exists(); - if (!debugserver_exists) - { - // The debugserver binary is in the LLDB.framework/Resources - // directory. - if (HostInfo::GetLLDBPath(ePathTypeSupportExecutableDir, debugserver_file_spec)) - { - debugserver_file_spec.AppendPathComponent (DEBUGSERVER_BASENAME); - debugserver_exists = debugserver_file_spec.Exists(); - if (debugserver_exists) - { - if (log) - log->Printf ("GDBRemoteCommunication::%s() found gdb-remote stub exe '%s'", __FUNCTION__, debugserver_file_spec.GetPath ().c_str ()); - - g_debugserver_file_spec = debugserver_file_spec; - } - else - { - debugserver_file_spec = platform->LocateExecutable(DEBUGSERVER_BASENAME); - if (debugserver_file_spec) - { - // Platform::LocateExecutable() wouldn't return a path if it doesn't exist - debugserver_exists = true; - } - else - { - if (log) - log->Printf ("GDBRemoteCommunication::%s() could not find gdb-remote stub exe '%s'", __FUNCTION__, debugserver_file_spec.GetPath ().c_str ()); - } - // Don't cache the platform specific GDB server binary as it could change - // from platform to platform - g_debugserver_file_spec.Clear(); - } + log->Printf( + "GDBRemoteCommunication::%s() found gdb-remote stub exe '%s'", + __FUNCTION__, debugserver_file_spec.GetPath().c_str()); + + g_debugserver_file_spec = debugserver_file_spec; + } else { + debugserver_file_spec = + platform->LocateExecutable(DEBUGSERVER_BASENAME); + if (debugserver_file_spec) { + // Platform::LocateExecutable() wouldn't return a path if it doesn't + // exist + debugserver_exists = true; + } else { + if (log) + log->Printf("GDBRemoteCommunication::%s() could not find " + "gdb-remote stub exe '%s'", + __FUNCTION__, debugserver_file_spec.GetPath().c_str()); } + // Don't cache the platform specific GDB server binary as it could + // change + // from platform to platform + g_debugserver_file_spec.Clear(); + } } - - if (debugserver_exists) - { - debugserver_file_spec.GetPath (debugserver_path, sizeof(debugserver_path)); + } + + if (debugserver_exists) { + debugserver_file_spec.GetPath(debugserver_path, sizeof(debugserver_path)); - Args &debugserver_args = launch_info.GetArguments(); - debugserver_args.Clear(); - char arg_cstr[PATH_MAX]; + Args &debugserver_args = launch_info.GetArguments(); + debugserver_args.Clear(); + char arg_cstr[PATH_MAX]; - // Start args with "debugserver /file/path -r --" - debugserver_args.AppendArgument(debugserver_path); + // Start args with "debugserver /file/path -r --" + debugserver_args.AppendArgument(llvm::StringRef(debugserver_path)); #if !defined(__APPLE__) - // First argument to lldb-server must be mode in which to run. - debugserver_args.AppendArgument("gdbserver"); + // First argument to lldb-server must be mode in which to run. + debugserver_args.AppendArgument(llvm::StringRef("gdbserver")); #endif - // If a url is supplied then use it - if (url) - debugserver_args.AppendArgument(url); + // If a url is supplied then use it + if (url) + debugserver_args.AppendArgument(llvm::StringRef(url)); + + if (pass_comm_fd >= 0) { + StreamString fd_arg; + fd_arg.Printf("--fd=%i", pass_comm_fd); + debugserver_args.AppendArgument(fd_arg.GetString()); + // Send "pass_comm_fd" down to the inferior so it can use it to + // communicate back with this process + launch_info.AppendDuplicateFileAction(pass_comm_fd, pass_comm_fd); + } - // use native registers, not the GDB registers - debugserver_args.AppendArgument("--native-regs"); + // use native registers, not the GDB registers + debugserver_args.AppendArgument(llvm::StringRef("--native-regs")); - if (launch_info.GetLaunchInSeparateProcessGroup()) - { - debugserver_args.AppendArgument("--setsid"); - } + if (launch_info.GetLaunchInSeparateProcessGroup()) { + debugserver_args.AppendArgument(llvm::StringRef("--setsid")); + } - llvm::SmallString<PATH_MAX> named_pipe_path; - // socket_pipe is used by debug server to communicate back either - // TCP port or domain socket name which it listens on. - // The second purpose of the pipe to serve as a synchronization point - - // once data is written to the pipe, debug server is up and running. - Pipe socket_pipe; - - // port is null when debug server should listen on domain socket - - // we're not interested in port value but rather waiting for debug server - // to become available. - if ((port != nullptr && *port == 0) || port == nullptr) - { - if (url) - { - // Create a temporary file to get the stdout/stderr and redirect the - // output of the command into this file. We will later read this file - // if all goes well and fill the data into "command_output_ptr" - -#if defined(__APPLE__) - // Binding to port zero, we need to figure out what port it ends up - // using using a named pipe... - error = socket_pipe.CreateWithUniqueName("debugserver-named-pipe", false, named_pipe_path); - if (error.Fail()) - { - if (log) - log->Printf("GDBRemoteCommunication::%s() " - "named pipe creation failed: %s", - __FUNCTION__, error.AsCString()); - return error; - } - debugserver_args.AppendArgument("--named-pipe"); - debugserver_args.AppendArgument(named_pipe_path.c_str()); -#else - // Binding to port zero, we need to figure out what port it ends up - // using using an unnamed pipe... - error = socket_pipe.CreateNew(true); - if (error.Fail()) - { - if (log) - log->Printf("GDBRemoteCommunication::%s() " - "unnamed pipe creation failed: %s", - __FUNCTION__, error.AsCString()); - return error; - } - int write_fd = socket_pipe.GetWriteFileDescriptor(); - debugserver_args.AppendArgument("--pipe"); - debugserver_args.AppendArgument(std::to_string(write_fd).c_str()); - launch_info.AppendCloseFileAction(socket_pipe.GetReadFileDescriptor()); -#endif - } - else - { - // No host and port given, so lets listen on our end and make the debugserver - // connect to us.. - error = StartListenThread ("127.0.0.1", 0); - if (error.Fail()) - { - if (log) - log->Printf ("GDBRemoteCommunication::%s() unable to start listen thread: %s", __FUNCTION__, error.AsCString()); - return error; - } - - ConnectionFileDescriptor *connection = (ConnectionFileDescriptor *)GetConnection (); - // Wait for 10 seconds to resolve the bound port - *port = connection->GetListeningPort(10); - if (*port > 0) - { - char port_cstr[32]; - snprintf(port_cstr, sizeof(port_cstr), "127.0.0.1:%i", *port); - // Send the host and port down that debugserver and specify an option - // so that it connects back to the port we are listening to in this process - debugserver_args.AppendArgument("--reverse-connect"); - debugserver_args.AppendArgument(port_cstr); - } - else - { - error.SetErrorString ("failed to bind to port 0 on 127.0.0.1"); - if (log) - log->Printf ("GDBRemoteCommunication::%s() failed: %s", __FUNCTION__, error.AsCString()); - return error; - } - } - } - - const char *env_debugserver_log_file = getenv("LLDB_DEBUGSERVER_LOG_FILE"); - if (env_debugserver_log_file) - { - ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-file=%s", env_debugserver_log_file); - debugserver_args.AppendArgument(arg_cstr); - } - + llvm::SmallString<PATH_MAX> named_pipe_path; + // socket_pipe is used by debug server to communicate back either + // TCP port or domain socket name which it listens on. + // The second purpose of the pipe to serve as a synchronization point - + // once data is written to the pipe, debug server is up and running. + Pipe socket_pipe; + + // port is null when debug server should listen on domain socket - + // we're not interested in port value but rather waiting for debug server + // to become available. + if (pass_comm_fd == -1 && + ((port != nullptr && *port == 0) || port == nullptr)) { + if (url) { +// Create a temporary file to get the stdout/stderr and redirect the +// output of the command into this file. We will later read this file +// if all goes well and fill the data into "command_output_ptr" #if defined(__APPLE__) - const char *env_debugserver_log_flags = getenv("LLDB_DEBUGSERVER_LOG_FLAGS"); - if (env_debugserver_log_flags) - { - ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-flags=%s", env_debugserver_log_flags); - debugserver_args.AppendArgument(arg_cstr); + // Binding to port zero, we need to figure out what port it ends up + // using using a named pipe... + error = socket_pipe.CreateWithUniqueName("debugserver-named-pipe", + false, named_pipe_path); + if (error.Fail()) { + if (log) + log->Printf("GDBRemoteCommunication::%s() " + "named pipe creation failed: %s", + __FUNCTION__, error.AsCString()); + return error; } + debugserver_args.AppendArgument(llvm::StringRef("--named-pipe")); + debugserver_args.AppendArgument(named_pipe_path); #else - const char *env_debugserver_log_channels = getenv("LLDB_SERVER_LOG_CHANNELS"); - if (env_debugserver_log_channels) - { - ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-channels=%s", env_debugserver_log_channels); - debugserver_args.AppendArgument(arg_cstr); + // Binding to port zero, we need to figure out what port it ends up + // using using an unnamed pipe... + error = socket_pipe.CreateNew(true); + if (error.Fail()) { + if (log) + log->Printf("GDBRemoteCommunication::%s() " + "unnamed pipe creation failed: %s", + __FUNCTION__, error.AsCString()); + return error; } + int write_fd = socket_pipe.GetWriteFileDescriptor(); + debugserver_args.AppendArgument(llvm::StringRef("--pipe")); + debugserver_args.AppendArgument(llvm::to_string(write_fd)); + launch_info.AppendCloseFileAction(socket_pipe.GetReadFileDescriptor()); #endif - - // Add additional args, starting with LLDB_DEBUGSERVER_EXTRA_ARG_1 until an env var doesn't come back. - uint32_t env_var_index = 1; - bool has_env_var; - do - { - char env_var_name[64]; - snprintf (env_var_name, sizeof (env_var_name), "LLDB_DEBUGSERVER_EXTRA_ARG_%" PRIu32, env_var_index++); - const char *extra_arg = getenv(env_var_name); - has_env_var = extra_arg != nullptr; - - if (has_env_var) - { - debugserver_args.AppendArgument (extra_arg); - if (log) - log->Printf ("GDBRemoteCommunication::%s adding env var %s contents to stub command line (%s)", __FUNCTION__, env_var_name, extra_arg); - } - } while (has_env_var); - - if (inferior_args.GetArgumentCount() > 0) - { - debugserver_args.AppendArgument ("--"); - debugserver_args.AppendArguments (inferior_args); + } else { + // No host and port given, so lets listen on our end and make the + // debugserver + // connect to us.. + error = StartListenThread("127.0.0.1", 0); + if (error.Fail()) { + if (log) + log->Printf("GDBRemoteCommunication::%s() unable to start listen " + "thread: %s", + __FUNCTION__, error.AsCString()); + return error; } - // Copy the current environment to the gdbserver/debugserver instance - StringList env; - if (Host::GetEnvironment(env)) - { - for (size_t i = 0; i < env.GetSize(); ++i) - launch_info.GetEnvironmentEntries().AppendArgument(env[i].c_str()); + ConnectionFileDescriptor *connection = + (ConnectionFileDescriptor *)GetConnection(); + // Wait for 10 seconds to resolve the bound port + uint16_t port_ = connection->GetListeningPort(10); + if (port_ > 0) { + char port_cstr[32]; + snprintf(port_cstr, sizeof(port_cstr), "127.0.0.1:%i", port_); + // Send the host and port down that debugserver and specify an option + // so that it connects back to the port we are listening to in this + // process + debugserver_args.AppendArgument(llvm::StringRef("--reverse-connect")); + debugserver_args.AppendArgument(llvm::StringRef(port_cstr)); + if (port) + *port = port_; + } else { + error.SetErrorString("failed to bind to port 0 on 127.0.0.1"); + if (log) + log->Printf("GDBRemoteCommunication::%s() failed: %s", __FUNCTION__, + error.AsCString()); + return error; } + } + } - // Close STDIN, STDOUT and STDERR. - launch_info.AppendCloseFileAction (STDIN_FILENO); - launch_info.AppendCloseFileAction (STDOUT_FILENO); - launch_info.AppendCloseFileAction (STDERR_FILENO); + const char *env_debugserver_log_file = getenv("LLDB_DEBUGSERVER_LOG_FILE"); + if (env_debugserver_log_file) { + ::snprintf(arg_cstr, sizeof(arg_cstr), "--log-file=%s", + env_debugserver_log_file); + debugserver_args.AppendArgument(llvm::StringRef(arg_cstr)); + } - // Redirect STDIN, STDOUT and STDERR to "/dev/null". - launch_info.AppendSuppressFileAction (STDIN_FILENO, true, false); - launch_info.AppendSuppressFileAction (STDOUT_FILENO, false, true); - launch_info.AppendSuppressFileAction (STDERR_FILENO, false, true); +#if defined(__APPLE__) + const char *env_debugserver_log_flags = + getenv("LLDB_DEBUGSERVER_LOG_FLAGS"); + if (env_debugserver_log_flags) { + ::snprintf(arg_cstr, sizeof(arg_cstr), "--log-flags=%s", + env_debugserver_log_flags); + debugserver_args.AppendArgument(llvm::StringRef(arg_cstr)); + } +#else + const char *env_debugserver_log_channels = + getenv("LLDB_SERVER_LOG_CHANNELS"); + if (env_debugserver_log_channels) { + ::snprintf(arg_cstr, sizeof(arg_cstr), "--log-channels=%s", + env_debugserver_log_channels); + debugserver_args.AppendArgument(llvm::StringRef(arg_cstr)); + } +#endif + // Add additional args, starting with LLDB_DEBUGSERVER_EXTRA_ARG_1 until an + // env var doesn't come back. + uint32_t env_var_index = 1; + bool has_env_var; + do { + char env_var_name[64]; + snprintf(env_var_name, sizeof(env_var_name), + "LLDB_DEBUGSERVER_EXTRA_ARG_%" PRIu32, env_var_index++); + const char *extra_arg = getenv(env_var_name); + has_env_var = extra_arg != nullptr; + + if (has_env_var) { + debugserver_args.AppendArgument(llvm::StringRef(extra_arg)); if (log) - { - StreamString string_stream; - Platform *const platform = nullptr; - launch_info.Dump(string_stream, platform); - log->Printf("launch info for gdb-remote stub:\n%s", string_stream.GetString().c_str()); - } - error = Host::LaunchProcess(launch_info); - - if (error.Success() && - launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) - { - if (named_pipe_path.size() > 0) - { - error = socket_pipe.OpenAsReader(named_pipe_path, false); - if (error.Fail()) - if (log) - log->Printf("GDBRemoteCommunication::%s() " - "failed to open named pipe %s for reading: %s", - __FUNCTION__, named_pipe_path.c_str(), error.AsCString()); - } - - if (socket_pipe.CanWrite()) - socket_pipe.CloseWriteFileDescriptor(); - if (socket_pipe.CanRead()) - { - char port_cstr[PATH_MAX] = {0}; - port_cstr[0] = '\0'; - size_t num_bytes = sizeof(port_cstr); - // Read port from pipe with 10 second timeout. - error = socket_pipe.ReadWithTimeout(port_cstr, num_bytes, - std::chrono::seconds{10}, num_bytes); - if (error.Success() && (port != nullptr)) - { - assert(num_bytes > 0 && port_cstr[num_bytes-1] == '\0'); - *port = StringConvert::ToUInt32(port_cstr, 0); - if (log) - log->Printf("GDBRemoteCommunication::%s() " - "debugserver listens %u port", - __FUNCTION__, *port); - } - else - { - if (log) - log->Printf("GDBRemoteCommunication::%s() " - "failed to read a port value from pipe %s: %s", - __FUNCTION__, named_pipe_path.c_str(), error.AsCString()); - - } - socket_pipe.Close(); - } - - if (named_pipe_path.size() > 0) - { - const auto err = socket_pipe.Delete(named_pipe_path); - if (err.Fail()) - { - if (log) - log->Printf ("GDBRemoteCommunication::%s failed to delete pipe %s: %s", - __FUNCTION__, named_pipe_path.c_str(), err.AsCString()); - } - } + log->Printf("GDBRemoteCommunication::%s adding env var %s contents " + "to stub command line (%s)", + __FUNCTION__, env_var_name, extra_arg); + } + } while (has_env_var); + + if (inferior_args && inferior_args->GetArgumentCount() > 0) { + debugserver_args.AppendArgument(llvm::StringRef("--")); + debugserver_args.AppendArguments(*inferior_args); + } - // Make sure we actually connect with the debugserver... - JoinListenThread(); - } + // Copy the current environment to the gdbserver/debugserver instance + StringList env; + if (Host::GetEnvironment(env)) { + for (size_t i = 0; i < env.GetSize(); ++i) + launch_info.GetEnvironmentEntries().AppendArgument(env[i]); } - else - { - error.SetErrorStringWithFormat ("unable to locate " DEBUGSERVER_BASENAME ); + + // Close STDIN, STDOUT and STDERR. + launch_info.AppendCloseFileAction(STDIN_FILENO); + launch_info.AppendCloseFileAction(STDOUT_FILENO); + launch_info.AppendCloseFileAction(STDERR_FILENO); + + // Redirect STDIN, STDOUT and STDERR to "/dev/null". + launch_info.AppendSuppressFileAction(STDIN_FILENO, true, false); + launch_info.AppendSuppressFileAction(STDOUT_FILENO, false, true); + launch_info.AppendSuppressFileAction(STDERR_FILENO, false, true); + + if (log) { + StreamString string_stream; + Platform *const platform = nullptr; + launch_info.Dump(string_stream, platform); + log->Printf("launch info for gdb-remote stub:\n%s", + string_stream.GetData()); } + error = Host::LaunchProcess(launch_info); + + if (error.Success() && + (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) && + pass_comm_fd == -1) { + if (named_pipe_path.size() > 0) { + error = socket_pipe.OpenAsReader(named_pipe_path, false); + if (error.Fail()) + if (log) + log->Printf("GDBRemoteCommunication::%s() " + "failed to open named pipe %s for reading: %s", + __FUNCTION__, named_pipe_path.c_str(), + error.AsCString()); + } + + if (socket_pipe.CanWrite()) + socket_pipe.CloseWriteFileDescriptor(); + if (socket_pipe.CanRead()) { + char port_cstr[PATH_MAX] = {0}; + port_cstr[0] = '\0'; + size_t num_bytes = sizeof(port_cstr); + // Read port from pipe with 10 second timeout. + error = socket_pipe.ReadWithTimeout( + port_cstr, num_bytes, std::chrono::seconds{10}, num_bytes); + if (error.Success() && (port != nullptr)) { + assert(num_bytes > 0 && port_cstr[num_bytes - 1] == '\0'); + *port = StringConvert::ToUInt32(port_cstr, 0); + if (log) + log->Printf("GDBRemoteCommunication::%s() " + "debugserver listens %u port", + __FUNCTION__, *port); + } else { + if (log) + log->Printf("GDBRemoteCommunication::%s() " + "failed to read a port value from pipe %s: %s", + __FUNCTION__, named_pipe_path.c_str(), + error.AsCString()); + } + socket_pipe.Close(); + } + + if (named_pipe_path.size() > 0) { + const auto err = socket_pipe.Delete(named_pipe_path); + if (err.Fail()) { + if (log) + log->Printf( + "GDBRemoteCommunication::%s failed to delete pipe %s: %s", + __FUNCTION__, named_pipe_path.c_str(), err.AsCString()); + } + } - if (error.Fail()) - { - if (log) - log->Printf ("GDBRemoteCommunication::%s() failed: %s", __FUNCTION__, error.AsCString()); + // Make sure we actually connect with the debugserver... + JoinListenThread(); } + } else { + error.SetErrorStringWithFormat("unable to locate " DEBUGSERVER_BASENAME); + } - return error; -} + if (error.Fail()) { + if (log) + log->Printf("GDBRemoteCommunication::%s() failed: %s", __FUNCTION__, + error.AsCString()); + } -void -GDBRemoteCommunication::DumpHistory(Stream &strm) -{ - m_history.Dump (strm); + return error; } -GDBRemoteCommunication::ScopedTimeout::ScopedTimeout (GDBRemoteCommunication& gdb_comm, - uint32_t timeout) : - m_gdb_comm (gdb_comm) -{ - m_saved_timeout = m_gdb_comm.SetPacketTimeout (timeout); +void GDBRemoteCommunication::DumpHistory(Stream &strm) { m_history.Dump(strm); } + +GDBRemoteCommunication::ScopedTimeout::ScopedTimeout( + GDBRemoteCommunication &gdb_comm, std::chrono::seconds timeout) + : m_gdb_comm(gdb_comm) { + m_saved_timeout = m_gdb_comm.SetPacketTimeout(timeout); } -GDBRemoteCommunication::ScopedTimeout::~ScopedTimeout () -{ - m_gdb_comm.SetPacketTimeout (m_saved_timeout); +GDBRemoteCommunication::ScopedTimeout::~ScopedTimeout() { + m_gdb_comm.SetPacketTimeout(m_saved_timeout); } -// This function is called via the Communications class read thread when bytes become available -// for this connection. This function will consume all incoming bytes and try to parse whole -// packets as they become available. Full packets are placed in a queue, so that all packet -// requests can simply pop from this queue. Async notification packets will be dispatched +// This function is called via the Communications class read thread when bytes +// become available +// for this connection. This function will consume all incoming bytes and try to +// parse whole +// packets as they become available. Full packets are placed in a queue, so that +// all packet +// requests can simply pop from this queue. Async notification packets will be +// dispatched // immediately to the ProcessGDBRemote Async thread via an event. -void GDBRemoteCommunication::AppendBytesToCache (const uint8_t * bytes, size_t len, bool broadcast, lldb::ConnectionStatus status) -{ - StringExtractorGDBRemote packet; - - while (true) - { - PacketType type = CheckForPacket(bytes, len, packet); - - // scrub the data so we do not pass it back to CheckForPacket - // on future passes of the loop - bytes = nullptr; - len = 0; - - // we may have received no packet so lets bail out - if (type == PacketType::Invalid) - break; - - if (type == PacketType::Standard) - { - // scope for the mutex - { - // lock down the packet queue - Mutex::Locker locker(m_packet_queue_mutex); - // push a new packet into the queue - m_packet_queue.push(packet); - // Signal condition variable that we have a packet - m_condition_queue_not_empty.Signal(); - - } - } +void GDBRemoteCommunication::AppendBytesToCache(const uint8_t *bytes, + size_t len, bool broadcast, + lldb::ConnectionStatus status) { + StringExtractorGDBRemote packet; + + while (true) { + PacketType type = CheckForPacket(bytes, len, packet); + + // scrub the data so we do not pass it back to CheckForPacket + // on future passes of the loop + bytes = nullptr; + len = 0; + + // we may have received no packet so lets bail out + if (type == PacketType::Invalid) + break; + + if (type == PacketType::Standard) { + // scope for the mutex + { + // lock down the packet queue + std::lock_guard<std::mutex> guard(m_packet_queue_mutex); + // push a new packet into the queue + m_packet_queue.push(packet); + // Signal condition variable that we have a packet + m_condition_queue_not_empty.notify_one(); + } + } - if (type == PacketType::Notify) - { - // put this packet into an event - const char *pdata = packet.GetStringRef().c_str(); + if (type == PacketType::Notify) { + // put this packet into an event + const char *pdata = packet.GetStringRef().c_str(); - // as the communication class, we are a broadcaster and the - // async thread is tuned to listen to us - BroadcastEvent( - eBroadcastBitGdbReadThreadGotNotify, - new EventDataBytes(pdata)); - } + // as the communication class, we are a broadcaster and the + // async thread is tuned to listen to us + BroadcastEvent(eBroadcastBitGdbReadThreadGotNotify, + new EventDataBytes(pdata)); } + } } diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h index 2a01bce..1f3fa17 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h @@ -12,365 +12,275 @@ // C Includes // C++ Includes -#include <string> +#include <condition_variable> +#include <mutex> #include <queue> +#include <string> #include <vector> // Other libraries and framework includes // Project includes -#include "lldb/lldb-public.h" #include "lldb/Core/Communication.h" #include "lldb/Core/Listener.h" #include "lldb/Host/HostThread.h" -#include "lldb/Host/Mutex.h" #include "lldb/Host/Predicate.h" -#include "lldb/Host/TimeValue.h" #include "lldb/Interpreter/Args.h" +#include "lldb/lldb-public.h" #include "Utility/StringExtractorGDBRemote.h" namespace lldb_private { namespace process_gdb_remote { -typedef enum -{ - eStoppointInvalid = -1, - eBreakpointSoftware = 0, - eBreakpointHardware, - eWatchpointWrite, - eWatchpointRead, - eWatchpointReadWrite +typedef enum { + eStoppointInvalid = -1, + eBreakpointSoftware = 0, + eBreakpointHardware, + eWatchpointWrite, + eWatchpointRead, + eWatchpointReadWrite } GDBStoppointType; -enum class CompressionType -{ - None = 0, // no compression - ZlibDeflate, // zlib's deflate compression scheme, requires zlib or Apple's libcompression - LZFSE, // an Apple compression scheme, requires Apple's libcompression - LZ4, // lz compression - called "lz4 raw" in libcompression terms, compat with https://code.google.com/p/lz4/ - LZMA, // Lempel–Ziv–Markov chain algorithm +enum class CompressionType { + None = 0, // no compression + ZlibDeflate, // zlib's deflate compression scheme, requires zlib or Apple's + // libcompression + LZFSE, // an Apple compression scheme, requires Apple's libcompression + LZ4, // lz compression - called "lz4 raw" in libcompression terms, compat with + // https://code.google.com/p/lz4/ + LZMA, // Lempel–Ziv–Markov chain algorithm }; class ProcessGDBRemote; -class GDBRemoteCommunication : public Communication -{ +class GDBRemoteCommunication : public Communication { public: - enum - { - eBroadcastBitRunPacketSent = kLoUserBroadcastBit, - eBroadcastBitGdbReadThreadGotNotify = kLoUserBroadcastBit << 1 // Sent when we received a notify packet. - }; + enum { + eBroadcastBitRunPacketSent = kLoUserBroadcastBit, + eBroadcastBitGdbReadThreadGotNotify = + kLoUserBroadcastBit << 1 // Sent when we received a notify packet. + }; + + enum class PacketType { Invalid = 0, Standard, Notify }; + + enum class PacketResult { + Success = 0, // Success + ErrorSendFailed, // Error sending the packet + ErrorSendAck, // Didn't get an ack back after sending a packet + ErrorReplyFailed, // Error getting the reply + ErrorReplyTimeout, // Timed out waiting for reply + ErrorReplyInvalid, // Got a reply but it wasn't valid for the packet that + // was sent + ErrorReplyAck, // Sending reply ack failed + ErrorDisconnected, // We were disconnected + ErrorNoSequenceLock // We couldn't get the sequence lock for a multi-packet + // request + }; + + // Class to change the timeout for a given scope and restore it to the + // original value when the + // created ScopedTimeout object got out of scope + class ScopedTimeout { + public: + ScopedTimeout(GDBRemoteCommunication &gdb_comm, + std::chrono::seconds timeout); + ~ScopedTimeout(); + + private: + GDBRemoteCommunication &m_gdb_comm; + std::chrono::seconds m_saved_timeout; + }; + + GDBRemoteCommunication(const char *comm_name, const char *listener_name); + + ~GDBRemoteCommunication() override; + + PacketResult GetAck(); + + size_t SendAck(); + + size_t SendNack(); + + char CalculcateChecksum(llvm::StringRef payload); + + PacketType CheckForPacket(const uint8_t *src, size_t src_len, + StringExtractorGDBRemote &packet); + + bool GetSendAcks() { return m_send_acks; } + + //------------------------------------------------------------------ + // Set the global packet timeout. + // + // For clients, this is the timeout that gets used when sending + // packets and waiting for responses. For servers, this is used when waiting + // for ACKs. + //------------------------------------------------------------------ + std::chrono::seconds SetPacketTimeout(std::chrono::seconds packet_timeout) { + const auto old_packet_timeout = m_packet_timeout; + m_packet_timeout = packet_timeout; + return old_packet_timeout; + } + + std::chrono::seconds GetPacketTimeout() const { return m_packet_timeout; } + + //------------------------------------------------------------------ + // Start a debugserver instance on the current host using the + // supplied connection URL. + //------------------------------------------------------------------ + Error StartDebugserverProcess( + const char *url, + Platform *platform, // If non nullptr, then check with the platform for + // the GDB server binary if it can't be located + ProcessLaunchInfo &launch_info, uint16_t *port, const Args *inferior_args, + int pass_comm_fd); // Communication file descriptor to pass during + // fork/exec to avoid having to connect/accept + + void DumpHistory(Stream &strm); - enum class PacketType - { - Invalid = 0, - Standard, - Notify - }; - - enum class PacketResult - { - Success = 0, // Success - ErrorSendFailed, // Error sending the packet - ErrorSendAck, // Didn't get an ack back after sending a packet - ErrorReplyFailed, // Error getting the reply - ErrorReplyTimeout, // Timed out waiting for reply - ErrorReplyInvalid, // Got a reply but it wasn't valid for the packet that was sent - ErrorReplyAck, // Sending reply ack failed - ErrorDisconnected, // We were disconnected - ErrorNoSequenceLock // We couldn't get the sequence lock for a multi-packet request +protected: + class History { + public: + enum PacketType { + ePacketTypeInvalid = 0, + ePacketTypeSend, + ePacketTypeRecv }; - // Class to change the timeout for a given scope and restore it to the original value when the - // created ScopedTimeout object got out of scope - class ScopedTimeout - { - public: - ScopedTimeout (GDBRemoteCommunication& gdb_comm, uint32_t timeout); - ~ScopedTimeout (); - - private: - GDBRemoteCommunication& m_gdb_comm; - uint32_t m_saved_timeout; + struct Entry { + Entry() + : packet(), type(ePacketTypeInvalid), bytes_transmitted(0), + packet_idx(0), tid(LLDB_INVALID_THREAD_ID) {} + + void Clear() { + packet.clear(); + type = ePacketTypeInvalid; + bytes_transmitted = 0; + packet_idx = 0; + tid = LLDB_INVALID_THREAD_ID; + } + std::string packet; + PacketType type; + uint32_t bytes_transmitted; + uint32_t packet_idx; + lldb::tid_t tid; }; - GDBRemoteCommunication(const char *comm_name, - const char *listener_name); - - ~GDBRemoteCommunication() override; - - PacketResult - GetAck (); - - size_t - SendAck (); + History(uint32_t size); - size_t - SendNack (); + ~History(); - char - CalculcateChecksum (const char *payload, - size_t payload_length); + // For single char packets for ack, nack and /x03 + void AddPacket(char packet_char, PacketType type, + uint32_t bytes_transmitted); - bool - GetSequenceMutex(Mutex::Locker& locker, const char *failure_message = nullptr); + void AddPacket(const std::string &src, uint32_t src_len, PacketType type, + uint32_t bytes_transmitted); - PacketType - CheckForPacket (const uint8_t *src, - size_t src_len, - StringExtractorGDBRemote &packet); + void Dump(Stream &strm) const; - bool - IsRunning() const - { - return m_public_is_running.GetValue(); - } + void Dump(Log *log) const; - bool - GetSendAcks () - { - return m_send_acks; - } + bool DidDumpToLog() const { return m_dumped_to_log; } - //------------------------------------------------------------------ - // Client and server must implement these pure virtual functions - //------------------------------------------------------------------ - virtual bool - GetThreadSuffixSupported () = 0; - - //------------------------------------------------------------------ - // Set the global packet timeout. - // - // For clients, this is the timeout that gets used when sending - // packets and waiting for responses. For servers, this might not - // get used, and if it doesn't this should be moved to the - // GDBRemoteCommunicationClient. - //------------------------------------------------------------------ - uint32_t - SetPacketTimeout (uint32_t packet_timeout) - { - const uint32_t old_packet_timeout = m_packet_timeout; - m_packet_timeout = packet_timeout; - return old_packet_timeout; + protected: + uint32_t GetFirstSavedPacketIndex() const { + if (m_total_packet_count < m_packets.size()) + return 0; + else + return m_curr_idx + 1; } - uint32_t - GetPacketTimeoutInMicroSeconds () const - { - return m_packet_timeout * TimeValue::MicroSecPerSec; + uint32_t GetNumPacketsInHistory() const { + if (m_total_packet_count < m_packets.size()) + return m_total_packet_count; + else + return (uint32_t)m_packets.size(); } - //------------------------------------------------------------------ - // Start a debugserver instance on the current host using the - // supplied connection URL. - //------------------------------------------------------------------ - Error - StartDebugserverProcess(const char *url, - Platform *platform, // If non nullptr, then check with the platform for the GDB server binary if it can't be located - ProcessLaunchInfo &launch_info, - uint16_t *port, - const Args& inferior_args = Args()); - - void - DumpHistory(Stream &strm); - -protected: - class History - { - public: - enum PacketType - { - ePacketTypeInvalid = 0, - ePacketTypeSend, - ePacketTypeRecv - }; - - struct Entry - { - Entry() : - packet(), - type (ePacketTypeInvalid), - bytes_transmitted (0), - packet_idx (0), - tid (LLDB_INVALID_THREAD_ID) - { - } - - void - Clear () - { - packet.clear(); - type = ePacketTypeInvalid; - bytes_transmitted = 0; - packet_idx = 0; - tid = LLDB_INVALID_THREAD_ID; - } - std::string packet; - PacketType type; - uint32_t bytes_transmitted; - uint32_t packet_idx; - lldb::tid_t tid; - }; - - History (uint32_t size); - - ~History (); - - // For single char packets for ack, nack and /x03 - void - AddPacket (char packet_char, - PacketType type, - uint32_t bytes_transmitted); - - void - AddPacket (const std::string &src, - uint32_t src_len, - PacketType type, - uint32_t bytes_transmitted); - - void - Dump (Stream &strm) const; - - void - Dump (Log *log) const; - - bool - DidDumpToLog () const - { - return m_dumped_to_log; - } - - protected: - uint32_t - GetFirstSavedPacketIndex () const - { - if (m_total_packet_count < m_packets.size()) - return 0; - else - return m_curr_idx + 1; - } - - uint32_t - GetNumPacketsInHistory () const - { - if (m_total_packet_count < m_packets.size()) - return m_total_packet_count; - else - return (uint32_t)m_packets.size(); - } - - uint32_t - GetNextIndex() - { - ++m_total_packet_count; - const uint32_t idx = m_curr_idx; - m_curr_idx = NormalizeIndex(idx + 1); - return idx; - } - - uint32_t - NormalizeIndex (uint32_t i) const - { - return i % m_packets.size(); - } - - std::vector<Entry> m_packets; - uint32_t m_curr_idx; - uint32_t m_total_packet_count; - mutable bool m_dumped_to_log; - }; - - uint32_t m_packet_timeout; - uint32_t m_echo_number; - LazyBool m_supports_qEcho; -#ifdef ENABLE_MUTEX_ERROR_CHECKING - TrackingMutex m_sequence_mutex; -#else - Mutex m_sequence_mutex; // Restrict access to sending/receiving packets to a single thread at a time -#endif - Predicate<bool> m_public_is_running; - Predicate<bool> m_private_is_running; - History m_history; - bool m_send_acks; - bool m_is_platform; // Set to true if this class represents a platform, - // false if this class represents a debug session for - // a single process - - CompressionType m_compression_type; - - PacketResult - SendPacket (const char *payload, - size_t payload_length); - - PacketResult - SendPacketNoLock (const char *payload, - size_t payload_length); - - PacketResult - ReadPacket (StringExtractorGDBRemote &response, uint32_t timeout_usec, bool sync_on_timeout); - - // Pop a packet from the queue in a thread safe manner - PacketResult - PopPacketFromQueue (StringExtractorGDBRemote &response, uint32_t timeout_usec); - - PacketResult - WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtractorGDBRemote &response, - uint32_t timeout_usec, - bool sync_on_timeout); - - bool - WaitForNotRunningPrivate (const TimeValue *timeout_ptr); - - bool - CompressionIsEnabled () - { - return m_compression_type != CompressionType::None; + uint32_t GetNextIndex() { + ++m_total_packet_count; + const uint32_t idx = m_curr_idx; + m_curr_idx = NormalizeIndex(idx + 1); + return idx; } - // If compression is enabled, decompress the packet in m_bytes and update - // m_bytes with the uncompressed version. - // Returns 'true' packet was decompressed and m_bytes is the now-decompressed text. - // Returns 'false' if unable to decompress or if the checksum was invalid. - // - // NB: Once the packet has been decompressed, checksum cannot be computed based - // on m_bytes. The checksum was for the compressed packet. - bool - DecompressPacket (); - - Error - StartListenThread (const char *hostname = "127.0.0.1", uint16_t port = 0); - - bool - JoinListenThread (); - - static lldb::thread_result_t - ListenThread (lldb::thread_arg_t arg); - - // GDB-Remote read thread - // . this thread constantly tries to read from the communication - // class and stores all packets received in a queue. The usual - // threads read requests simply pop packets off the queue in the - // usual order. - // This setup allows us to intercept and handle async packets, such - // as the notify packet. - - // This method is defined as part of communication.h - // when the read thread gets any bytes it will pass them on to this function - void AppendBytesToCache(const uint8_t * bytes, - size_t len, - bool broadcast, - lldb::ConnectionStatus status) override; + uint32_t NormalizeIndex(uint32_t i) const { return i % m_packets.size(); } + + std::vector<Entry> m_packets; + uint32_t m_curr_idx; + uint32_t m_total_packet_count; + mutable bool m_dumped_to_log; + }; + + std::chrono::seconds m_packet_timeout; + uint32_t m_echo_number; + LazyBool m_supports_qEcho; + History m_history; + bool m_send_acks; + bool m_is_platform; // Set to true if this class represents a platform, + // false if this class represents a debug session for + // a single process + + CompressionType m_compression_type; + + PacketResult SendPacketNoLock(llvm::StringRef payload); + + PacketResult ReadPacket(StringExtractorGDBRemote &response, + Timeout<std::micro> timeout, bool sync_on_timeout); + + // Pop a packet from the queue in a thread safe manner + PacketResult PopPacketFromQueue(StringExtractorGDBRemote &response, + Timeout<std::micro> timeout); + + PacketResult WaitForPacketNoLock(StringExtractorGDBRemote &response, + Timeout<std::micro> timeout, + bool sync_on_timeout); + + bool CompressionIsEnabled() { + return m_compression_type != CompressionType::None; + } + + // If compression is enabled, decompress the packet in m_bytes and update + // m_bytes with the uncompressed version. + // Returns 'true' packet was decompressed and m_bytes is the now-decompressed + // text. + // Returns 'false' if unable to decompress or if the checksum was invalid. + // + // NB: Once the packet has been decompressed, checksum cannot be computed + // based + // on m_bytes. The checksum was for the compressed packet. + bool DecompressPacket(); + + Error StartListenThread(const char *hostname = "127.0.0.1", + uint16_t port = 0); + + bool JoinListenThread(); + + static lldb::thread_result_t ListenThread(lldb::thread_arg_t arg); + + // GDB-Remote read thread + // . this thread constantly tries to read from the communication + // class and stores all packets received in a queue. The usual + // threads read requests simply pop packets off the queue in the + // usual order. + // This setup allows us to intercept and handle async packets, such + // as the notify packet. + + // This method is defined as part of communication.h + // when the read thread gets any bytes it will pass them on to this function + void AppendBytesToCache(const uint8_t *bytes, size_t len, bool broadcast, + lldb::ConnectionStatus status) override; private: - std::queue<StringExtractorGDBRemote> m_packet_queue; // The packet queue - lldb_private::Mutex m_packet_queue_mutex; // Mutex for accessing queue - Condition m_condition_queue_not_empty; // Condition variable to wait for packets + std::queue<StringExtractorGDBRemote> m_packet_queue; // The packet queue + std::mutex m_packet_queue_mutex; // Mutex for accessing queue + std::condition_variable + m_condition_queue_not_empty; // Condition variable to wait for packets - HostThread m_listen_thread; - std::string m_listen_url; + HostThread m_listen_thread; + std::string m_listen_url; - DISALLOW_COPY_AND_ASSIGN (GDBRemoteCommunication); + DISALLOW_COPY_AND_ASSIGN(GDBRemoteCommunication); }; } // namespace process_gdb_remote diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index a792bbb..b70f090 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -7,7 +7,6 @@ // //===----------------------------------------------------------------------===// - #include "GDBRemoteCommunicationClient.h" // C Includes @@ -15,48 +14,48 @@ #include <sys/stat.h> // C++ Includes -#include <sstream> #include <numeric> +#include <sstream> // Other libraries and framework includes -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/Triple.h" -#include "lldb/Interpreter/Args.h" +#include "lldb/Core/DataBufferHeap.h" #include "lldb/Core/Log.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/State.h" #include "lldb/Core/StreamGDBRemote.h" #include "lldb/Core/StreamString.h" -#include "lldb/Host/ConnectionFileDescriptor.h" -#include "lldb/Host/Endian.h" -#include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" #include "lldb/Host/StringConvert.h" -#include "lldb/Host/TimeValue.h" +#include "lldb/Interpreter/Args.h" #include "lldb/Symbol/Symbol.h" -#include "lldb/Target/Target.h" #include "lldb/Target/MemoryRegionInfo.h" +#include "lldb/Target/Target.h" #include "lldb/Target/UnixSignals.h" +#include "lldb/Utility/JSON.h" +#include "lldb/Utility/LLDBAssert.h" // Project includes -#include "Utility/StringExtractorGDBRemote.h" #include "ProcessGDBRemote.h" #include "ProcessGDBRemoteLog.h" +#include "Utility/StringExtractorGDBRemote.h" #include "lldb/Host/Config.h" -#if defined (HAVE_LIBCOMPRESSION) +#include "llvm/ADT/StringSwitch.h" + +#if defined(HAVE_LIBCOMPRESSION) #include <compression.h> #endif using namespace lldb; using namespace lldb_private; using namespace lldb_private::process_gdb_remote; +using namespace std::chrono; //---------------------------------------------------------------------- // GDBRemoteCommunicationClient constructor //---------------------------------------------------------------------- GDBRemoteCommunicationClient::GDBRemoteCommunicationClient() - : GDBRemoteCommunication("gdb-remote.client", "gdb-remote.client.rx_packet"), + : GDBRemoteClientBase("gdb-remote.client", "gdb-remote.client.rx_packet"), m_supports_not_sending_acks(eLazyBoolCalculate), m_supports_thread_suffix(eLazyBoolCalculate), m_supports_threads_in_stop_reply(eLazyBoolCalculate), @@ -77,8 +76,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient() m_watchpoints_trigger_after_instruction(eLazyBoolCalculate), m_attach_or_wait_reply(eLazyBoolCalculate), m_prepare_for_reg_writing_reply(eLazyBoolCalculate), - m_supports_p(eLazyBoolCalculate), - m_supports_x(eLazyBoolCalculate), + m_supports_p(eLazyBoolCalculate), m_supports_x(eLazyBoolCalculate), m_avoid_g_packets(eLazyBoolCalculate), m_supports_QSaveRegisterState(eLazyBoolCalculate), m_supports_qXfer_auxv_read(eLazyBoolCalculate), @@ -88,503 +86,449 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient() m_supports_augmented_libraries_svr4_read(eLazyBoolCalculate), m_supports_jThreadExtendedInfo(eLazyBoolCalculate), m_supports_jLoadedDynamicLibrariesInfos(eLazyBoolCalculate), - m_supports_qProcessInfoPID(true), - m_supports_qfProcessInfo(true), - m_supports_qUserName(true), - m_supports_qGroupName(true), - m_supports_qThreadStopInfo(true), - m_supports_z0(true), - m_supports_z1(true), - m_supports_z2(true), - m_supports_z3(true), - m_supports_z4(true), - m_supports_QEnvironment(true), - m_supports_QEnvironmentHexEncoded(true), - m_supports_qSymbol(true), - m_qSymbol_requests_done(false), - m_supports_qModuleInfo(true), - m_supports_jThreadsInfo(true), - m_curr_pid(LLDB_INVALID_PROCESS_ID), - m_curr_tid(LLDB_INVALID_THREAD_ID), + m_supports_jGetSharedCacheInfo(eLazyBoolCalculate), + m_supports_qProcessInfoPID(true), m_supports_qfProcessInfo(true), + m_supports_qUserName(true), m_supports_qGroupName(true), + m_supports_qThreadStopInfo(true), m_supports_z0(true), + m_supports_z1(true), m_supports_z2(true), m_supports_z3(true), + m_supports_z4(true), m_supports_QEnvironment(true), + m_supports_QEnvironmentHexEncoded(true), m_supports_qSymbol(true), + m_qSymbol_requests_done(false), m_supports_qModuleInfo(true), + m_supports_jThreadsInfo(true), m_supports_jModulesInfo(true), + m_curr_pid(LLDB_INVALID_PROCESS_ID), m_curr_tid(LLDB_INVALID_THREAD_ID), m_curr_tid_run(LLDB_INVALID_THREAD_ID), - m_num_supported_hardware_watchpoints(0), - m_async_mutex(), - m_async_packet_predicate(false), - m_async_packet(), - m_async_result(PacketResult::Success), - m_async_response(), - m_async_signal(-1), - m_interrupt_sent(false), - m_thread_id_to_used_usec_map(), - m_host_arch(), - m_process_arch(), - m_os_version_major(UINT32_MAX), - m_os_version_minor(UINT32_MAX), - m_os_version_update(UINT32_MAX), - m_os_build(), - m_os_kernel(), - m_hostname(), - m_gdb_server_name(), - m_gdb_server_version(UINT32_MAX), - m_default_packet_timeout(0), - m_max_packet_size(0) -{ -} + m_num_supported_hardware_watchpoints(0), m_host_arch(), m_process_arch(), + m_os_version_major(UINT32_MAX), m_os_version_minor(UINT32_MAX), + m_os_version_update(UINT32_MAX), m_os_build(), m_os_kernel(), + m_hostname(), m_gdb_server_name(), m_gdb_server_version(UINT32_MAX), + m_default_packet_timeout(0), m_max_packet_size(0), + m_qSupported_response(), m_supported_async_json_packets_is_valid(false), + m_supported_async_json_packets_sp() {} //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- -GDBRemoteCommunicationClient::~GDBRemoteCommunicationClient() -{ - if (IsConnected()) - Disconnect(); -} - -bool -GDBRemoteCommunicationClient::HandshakeWithServer (Error *error_ptr) -{ - ResetDiscoverableSettings(false); - - // Start the read thread after we send the handshake ack since if we - // fail to send the handshake ack, there is no reason to continue... - if (SendAck()) - { - // Wait for any responses that might have been queued up in the remote - // GDB server and flush them all - StringExtractorGDBRemote response; - PacketResult packet_result = PacketResult::Success; - const uint32_t timeout_usec = 10 * 1000; // Wait for 10 ms for a response - while (packet_result == PacketResult::Success) - packet_result = ReadPacket (response, timeout_usec, false); - - // The return value from QueryNoAckModeSupported() is true if the packet - // was sent and _any_ response (including UNIMPLEMENTED) was received), - // or false if no response was received. This quickly tells us if we have - // a live connection to a remote GDB server... - if (QueryNoAckModeSupported()) - { - return true; - } - else - { - if (error_ptr) - error_ptr->SetErrorString("failed to get reply to handshake packet"); - } - } - else - { - if (error_ptr) - error_ptr->SetErrorString("failed to send the handshake ack"); - } - return false; +GDBRemoteCommunicationClient::~GDBRemoteCommunicationClient() { + if (IsConnected()) + Disconnect(); } -bool -GDBRemoteCommunicationClient::GetEchoSupported () -{ - if (m_supports_qEcho == eLazyBoolCalculate) - { - GetRemoteQSupported(); - } - return m_supports_qEcho == eLazyBoolYes; -} +bool GDBRemoteCommunicationClient::HandshakeWithServer(Error *error_ptr) { + ResetDiscoverableSettings(false); + // Start the read thread after we send the handshake ack since if we + // fail to send the handshake ack, there is no reason to continue... + if (SendAck()) { + // Wait for any responses that might have been queued up in the remote + // GDB server and flush them all + StringExtractorGDBRemote response; + PacketResult packet_result = PacketResult::Success; + while (packet_result == PacketResult::Success) + packet_result = ReadPacket(response, milliseconds(10), false); -bool -GDBRemoteCommunicationClient::GetAugmentedLibrariesSVR4ReadSupported () -{ - if (m_supports_augmented_libraries_svr4_read == eLazyBoolCalculate) - { - GetRemoteQSupported(); + // The return value from QueryNoAckModeSupported() is true if the packet + // was sent and _any_ response (including UNIMPLEMENTED) was received), + // or false if no response was received. This quickly tells us if we have + // a live connection to a remote GDB server... + if (QueryNoAckModeSupported()) { + return true; + } else { + if (error_ptr) + error_ptr->SetErrorString("failed to get reply to handshake packet"); } - return m_supports_augmented_libraries_svr4_read == eLazyBoolYes; + } else { + if (error_ptr) + error_ptr->SetErrorString("failed to send the handshake ack"); + } + return false; } -bool -GDBRemoteCommunicationClient::GetQXferLibrariesSVR4ReadSupported () -{ - if (m_supports_qXfer_libraries_svr4_read == eLazyBoolCalculate) - { - GetRemoteQSupported(); - } - return m_supports_qXfer_libraries_svr4_read == eLazyBoolYes; +bool GDBRemoteCommunicationClient::GetEchoSupported() { + if (m_supports_qEcho == eLazyBoolCalculate) { + GetRemoteQSupported(); + } + return m_supports_qEcho == eLazyBoolYes; } -bool -GDBRemoteCommunicationClient::GetQXferLibrariesReadSupported () -{ - if (m_supports_qXfer_libraries_read == eLazyBoolCalculate) - { - GetRemoteQSupported(); - } - return m_supports_qXfer_libraries_read == eLazyBoolYes; +bool GDBRemoteCommunicationClient::GetAugmentedLibrariesSVR4ReadSupported() { + if (m_supports_augmented_libraries_svr4_read == eLazyBoolCalculate) { + GetRemoteQSupported(); + } + return m_supports_augmented_libraries_svr4_read == eLazyBoolYes; } -bool -GDBRemoteCommunicationClient::GetQXferAuxvReadSupported () -{ - if (m_supports_qXfer_auxv_read == eLazyBoolCalculate) - { - GetRemoteQSupported(); - } - return m_supports_qXfer_auxv_read == eLazyBoolYes; +bool GDBRemoteCommunicationClient::GetQXferLibrariesSVR4ReadSupported() { + if (m_supports_qXfer_libraries_svr4_read == eLazyBoolCalculate) { + GetRemoteQSupported(); + } + return m_supports_qXfer_libraries_svr4_read == eLazyBoolYes; } -bool -GDBRemoteCommunicationClient::GetQXferFeaturesReadSupported () -{ - if (m_supports_qXfer_features_read == eLazyBoolCalculate) - { - GetRemoteQSupported(); - } - return m_supports_qXfer_features_read == eLazyBoolYes; +bool GDBRemoteCommunicationClient::GetQXferLibrariesReadSupported() { + if (m_supports_qXfer_libraries_read == eLazyBoolCalculate) { + GetRemoteQSupported(); + } + return m_supports_qXfer_libraries_read == eLazyBoolYes; } -uint64_t -GDBRemoteCommunicationClient::GetRemoteMaxPacketSize() -{ - if (m_max_packet_size == 0) - { - GetRemoteQSupported(); - } - return m_max_packet_size; +bool GDBRemoteCommunicationClient::GetQXferAuxvReadSupported() { + if (m_supports_qXfer_auxv_read == eLazyBoolCalculate) { + GetRemoteQSupported(); + } + return m_supports_qXfer_auxv_read == eLazyBoolYes; } -bool -GDBRemoteCommunicationClient::QueryNoAckModeSupported () -{ - if (m_supports_not_sending_acks == eLazyBoolCalculate) - { - m_send_acks = true; - m_supports_not_sending_acks = eLazyBoolNo; - - // This is the first real packet that we'll send in a debug session and it may take a little - // longer than normal to receive a reply. Wait at least 6 seconds for a reply to this packet. - - const uint32_t minimum_timeout = 6; - uint32_t old_timeout = GetPacketTimeoutInMicroSeconds() / lldb_private::TimeValue::MicroSecPerSec; - GDBRemoteCommunication::ScopedTimeout timeout (*this, std::max (old_timeout, minimum_timeout)); - - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("QStartNoAckMode", response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - { - m_send_acks = false; - m_supports_not_sending_acks = eLazyBoolYes; - } - return true; - } - } - return false; +bool GDBRemoteCommunicationClient::GetQXferFeaturesReadSupported() { + if (m_supports_qXfer_features_read == eLazyBoolCalculate) { + GetRemoteQSupported(); + } + return m_supports_qXfer_features_read == eLazyBoolYes; } -void -GDBRemoteCommunicationClient::GetListThreadsInStopReplySupported () -{ - if (m_supports_threads_in_stop_reply == eLazyBoolCalculate) - { - m_supports_threads_in_stop_reply = eLazyBoolNo; - - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("QListThreadsInStopReply", response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - m_supports_threads_in_stop_reply = eLazyBoolYes; - } - } +uint64_t GDBRemoteCommunicationClient::GetRemoteMaxPacketSize() { + if (m_max_packet_size == 0) { + GetRemoteQSupported(); + } + return m_max_packet_size; } -bool -GDBRemoteCommunicationClient::GetVAttachOrWaitSupported () -{ - if (m_attach_or_wait_reply == eLazyBoolCalculate) - { - m_attach_or_wait_reply = eLazyBoolNo; - - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("qVAttachOrWaitSupported", response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - m_attach_or_wait_reply = eLazyBoolYes; - } - } - if (m_attach_or_wait_reply == eLazyBoolYes) - return true; - else - return false; -} +bool GDBRemoteCommunicationClient::QueryNoAckModeSupported() { + if (m_supports_not_sending_acks == eLazyBoolCalculate) { + m_send_acks = true; + m_supports_not_sending_acks = eLazyBoolNo; -bool -GDBRemoteCommunicationClient::GetSyncThreadStateSupported () -{ - if (m_prepare_for_reg_writing_reply == eLazyBoolCalculate) - { - m_prepare_for_reg_writing_reply = eLazyBoolNo; - - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("qSyncThreadStateSupported", response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - m_prepare_for_reg_writing_reply = eLazyBoolYes; - } + // This is the first real packet that we'll send in a debug session and it + // may take a little + // longer than normal to receive a reply. Wait at least 6 seconds for a + // reply to this packet. + + ScopedTimeout timeout(*this, std::max(GetPacketTimeout(), seconds(6))); + + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse("QStartNoAckMode", response, false) == + PacketResult::Success) { + if (response.IsOKResponse()) { + m_send_acks = false; + m_supports_not_sending_acks = eLazyBoolYes; + } + return true; } - if (m_prepare_for_reg_writing_reply == eLazyBoolYes) - return true; - else - return false; + } + return false; } +void GDBRemoteCommunicationClient::GetListThreadsInStopReplySupported() { + if (m_supports_threads_in_stop_reply == eLazyBoolCalculate) { + m_supports_threads_in_stop_reply = eLazyBoolNo; -void -GDBRemoteCommunicationClient::ResetDiscoverableSettings (bool did_exec) -{ - if (did_exec == false) - { - // Hard reset everything, this is when we first connect to a GDB server - m_supports_not_sending_acks = eLazyBoolCalculate; - m_supports_thread_suffix = eLazyBoolCalculate; - m_supports_threads_in_stop_reply = eLazyBoolCalculate; - m_supports_vCont_c = eLazyBoolCalculate; - m_supports_vCont_C = eLazyBoolCalculate; - m_supports_vCont_s = eLazyBoolCalculate; - m_supports_vCont_S = eLazyBoolCalculate; - m_supports_p = eLazyBoolCalculate; - m_supports_x = eLazyBoolCalculate; - m_supports_QSaveRegisterState = eLazyBoolCalculate; - m_qHostInfo_is_valid = eLazyBoolCalculate; - m_curr_pid_is_valid = eLazyBoolCalculate; - m_qGDBServerVersion_is_valid = eLazyBoolCalculate; - m_supports_alloc_dealloc_memory = eLazyBoolCalculate; - m_supports_memory_region_info = eLazyBoolCalculate; - m_prepare_for_reg_writing_reply = eLazyBoolCalculate; - m_attach_or_wait_reply = eLazyBoolCalculate; - m_avoid_g_packets = eLazyBoolCalculate; - m_supports_qXfer_auxv_read = eLazyBoolCalculate; - m_supports_qXfer_libraries_read = eLazyBoolCalculate; - m_supports_qXfer_libraries_svr4_read = eLazyBoolCalculate; - m_supports_qXfer_features_read = eLazyBoolCalculate; - m_supports_augmented_libraries_svr4_read = eLazyBoolCalculate; - m_supports_qProcessInfoPID = true; - m_supports_qfProcessInfo = true; - m_supports_qUserName = true; - m_supports_qGroupName = true; - m_supports_qThreadStopInfo = true; - m_supports_z0 = true; - m_supports_z1 = true; - m_supports_z2 = true; - m_supports_z3 = true; - m_supports_z4 = true; - m_supports_QEnvironment = true; - m_supports_QEnvironmentHexEncoded = true; - m_supports_qSymbol = true; - m_qSymbol_requests_done = false; - m_supports_qModuleInfo = true; - m_host_arch.Clear(); - m_os_version_major = UINT32_MAX; - m_os_version_minor = UINT32_MAX; - m_os_version_update = UINT32_MAX; - m_os_build.clear(); - m_os_kernel.clear(); - m_hostname.clear(); - m_gdb_server_name.clear(); - m_gdb_server_version = UINT32_MAX; - m_default_packet_timeout = 0; - m_max_packet_size = 0; + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse("QListThreadsInStopReply", response, + false) == PacketResult::Success) { + if (response.IsOKResponse()) + m_supports_threads_in_stop_reply = eLazyBoolYes; } - - // These flags should be reset when we first connect to a GDB server - // and when our inferior process execs - m_qProcessInfo_is_valid = eLazyBoolCalculate; - m_process_arch.Clear(); + } } -void -GDBRemoteCommunicationClient::GetRemoteQSupported () -{ - // Clear out any capabilities we expect to see in the qSupported response - m_supports_qXfer_auxv_read = eLazyBoolNo; - m_supports_qXfer_libraries_read = eLazyBoolNo; - m_supports_qXfer_libraries_svr4_read = eLazyBoolNo; - m_supports_augmented_libraries_svr4_read = eLazyBoolNo; - m_supports_qXfer_features_read = eLazyBoolNo; - m_max_packet_size = UINT64_MAX; // It's supposed to always be there, but if not, we assume no limit - - // build the qSupported packet - std::vector<std::string> features = {"xmlRegisters=i386,arm,mips"}; - StreamString packet; - packet.PutCString( "qSupported" ); - for ( uint32_t i = 0; i < features.size( ); ++i ) - { - packet.PutCString( i==0 ? ":" : ";"); - packet.PutCString( features[i].c_str( ) ); - } +bool GDBRemoteCommunicationClient::GetVAttachOrWaitSupported() { + if (m_attach_or_wait_reply == eLazyBoolCalculate) { + m_attach_or_wait_reply = eLazyBoolNo; StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet.GetData(), - response, - /*send_async=*/false) == PacketResult::Success) - { - const char *response_cstr = response.GetStringRef().c_str(); - if (::strstr (response_cstr, "qXfer:auxv:read+")) - m_supports_qXfer_auxv_read = eLazyBoolYes; - if (::strstr (response_cstr, "qXfer:libraries-svr4:read+")) - m_supports_qXfer_libraries_svr4_read = eLazyBoolYes; - if (::strstr (response_cstr, "augmented-libraries-svr4-read")) - { - m_supports_qXfer_libraries_svr4_read = eLazyBoolYes; // implied - m_supports_augmented_libraries_svr4_read = eLazyBoolYes; - } - if (::strstr (response_cstr, "qXfer:libraries:read+")) - m_supports_qXfer_libraries_read = eLazyBoolYes; - if (::strstr (response_cstr, "qXfer:features:read+")) - m_supports_qXfer_features_read = eLazyBoolYes; - - - // Look for a list of compressions in the features list e.g. - // qXfer:features:read+;PacketSize=20000;qEcho+;SupportedCompressions=zlib-deflate,lzma - const char *features_list = ::strstr (response_cstr, "qXfer:features:"); - if (features_list) - { - const char *compressions = ::strstr (features_list, "SupportedCompressions="); - if (compressions) - { - std::vector<std::string> supported_compressions; - compressions += sizeof ("SupportedCompressions=") - 1; - const char *end_of_compressions = strchr (compressions, ';'); - if (end_of_compressions == NULL) - { - end_of_compressions = strchr (compressions, '\0'); - } - const char *current_compression = compressions; - while (current_compression < end_of_compressions) - { - const char *next_compression_name = strchr (current_compression, ','); - const char *end_of_this_word = next_compression_name; - if (next_compression_name == NULL || end_of_compressions < next_compression_name) - { - end_of_this_word = end_of_compressions; - } - - if (end_of_this_word) - { - if (end_of_this_word == current_compression) - { - current_compression++; - } - else - { - std::string this_compression (current_compression, end_of_this_word - current_compression); - supported_compressions.push_back (this_compression); - current_compression = end_of_this_word + 1; - } - } - else - { - supported_compressions.push_back (current_compression); - current_compression = end_of_compressions; - } - } + if (SendPacketAndWaitForResponse("qVAttachOrWaitSupported", response, + false) == PacketResult::Success) { + if (response.IsOKResponse()) + m_attach_or_wait_reply = eLazyBoolYes; + } + } + if (m_attach_or_wait_reply == eLazyBoolYes) + return true; + else + return false; +} - if (supported_compressions.size() > 0) - { - MaybeEnableCompression (supported_compressions); - } - } - } +bool GDBRemoteCommunicationClient::GetSyncThreadStateSupported() { + if (m_prepare_for_reg_writing_reply == eLazyBoolCalculate) { + m_prepare_for_reg_writing_reply = eLazyBoolNo; - if (::strstr (response_cstr, "qEcho")) - m_supports_qEcho = eLazyBoolYes; - else - m_supports_qEcho = eLazyBoolNo; - - const char *packet_size_str = ::strstr (response_cstr, "PacketSize="); - if (packet_size_str) - { - StringExtractorGDBRemote packet_response(packet_size_str + strlen("PacketSize=")); - m_max_packet_size = packet_response.GetHexMaxU64(/*little_endian=*/false, UINT64_MAX); - if (m_max_packet_size == 0) - { - m_max_packet_size = UINT64_MAX; // Must have been a garbled response - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); - if (log) - log->Printf ("Garbled PacketSize spec in qSupported response"); - } - } + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse("qSyncThreadStateSupported", response, + false) == PacketResult::Success) { + if (response.IsOKResponse()) + m_prepare_for_reg_writing_reply = eLazyBoolYes; } + } + if (m_prepare_for_reg_writing_reply == eLazyBoolYes) + return true; + else + return false; } -bool -GDBRemoteCommunicationClient::GetThreadSuffixSupported () -{ - if (m_supports_thread_suffix == eLazyBoolCalculate) - { - StringExtractorGDBRemote response; - m_supports_thread_suffix = eLazyBoolNo; - if (SendPacketAndWaitForResponse("QThreadSuffixSupported", response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - m_supports_thread_suffix = eLazyBoolYes; - } +void GDBRemoteCommunicationClient::ResetDiscoverableSettings(bool did_exec) { + if (did_exec == false) { + // Hard reset everything, this is when we first connect to a GDB server + m_supports_not_sending_acks = eLazyBoolCalculate; + m_supports_thread_suffix = eLazyBoolCalculate; + m_supports_threads_in_stop_reply = eLazyBoolCalculate; + m_supports_vCont_c = eLazyBoolCalculate; + m_supports_vCont_C = eLazyBoolCalculate; + m_supports_vCont_s = eLazyBoolCalculate; + m_supports_vCont_S = eLazyBoolCalculate; + m_supports_p = eLazyBoolCalculate; + m_supports_x = eLazyBoolCalculate; + m_supports_QSaveRegisterState = eLazyBoolCalculate; + m_qHostInfo_is_valid = eLazyBoolCalculate; + m_curr_pid_is_valid = eLazyBoolCalculate; + m_qGDBServerVersion_is_valid = eLazyBoolCalculate; + m_supports_alloc_dealloc_memory = eLazyBoolCalculate; + m_supports_memory_region_info = eLazyBoolCalculate; + m_prepare_for_reg_writing_reply = eLazyBoolCalculate; + m_attach_or_wait_reply = eLazyBoolCalculate; + m_avoid_g_packets = eLazyBoolCalculate; + m_supports_qXfer_auxv_read = eLazyBoolCalculate; + m_supports_qXfer_libraries_read = eLazyBoolCalculate; + m_supports_qXfer_libraries_svr4_read = eLazyBoolCalculate; + m_supports_qXfer_features_read = eLazyBoolCalculate; + m_supports_augmented_libraries_svr4_read = eLazyBoolCalculate; + m_supports_qProcessInfoPID = true; + m_supports_qfProcessInfo = true; + m_supports_qUserName = true; + m_supports_qGroupName = true; + m_supports_qThreadStopInfo = true; + m_supports_z0 = true; + m_supports_z1 = true; + m_supports_z2 = true; + m_supports_z3 = true; + m_supports_z4 = true; + m_supports_QEnvironment = true; + m_supports_QEnvironmentHexEncoded = true; + m_supports_qSymbol = true; + m_qSymbol_requests_done = false; + m_supports_qModuleInfo = true; + m_host_arch.Clear(); + m_os_version_major = UINT32_MAX; + m_os_version_minor = UINT32_MAX; + m_os_version_update = UINT32_MAX; + m_os_build.clear(); + m_os_kernel.clear(); + m_hostname.clear(); + m_gdb_server_name.clear(); + m_gdb_server_version = UINT32_MAX; + m_default_packet_timeout = seconds(0); + m_max_packet_size = 0; + m_qSupported_response.clear(); + m_supported_async_json_packets_is_valid = false; + m_supported_async_json_packets_sp.reset(); + m_supports_jModulesInfo = true; + } + + // These flags should be reset when we first connect to a GDB server + // and when our inferior process execs + m_qProcessInfo_is_valid = eLazyBoolCalculate; + m_process_arch.Clear(); +} + +void GDBRemoteCommunicationClient::GetRemoteQSupported() { + // Clear out any capabilities we expect to see in the qSupported response + m_supports_qXfer_auxv_read = eLazyBoolNo; + m_supports_qXfer_libraries_read = eLazyBoolNo; + m_supports_qXfer_libraries_svr4_read = eLazyBoolNo; + m_supports_augmented_libraries_svr4_read = eLazyBoolNo; + m_supports_qXfer_features_read = eLazyBoolNo; + m_max_packet_size = UINT64_MAX; // It's supposed to always be there, but if + // not, we assume no limit + + // build the qSupported packet + std::vector<std::string> features = {"xmlRegisters=i386,arm,mips"}; + StreamString packet; + packet.PutCString("qSupported"); + for (uint32_t i = 0; i < features.size(); ++i) { + packet.PutCString(i == 0 ? ":" : ";"); + packet.PutCString(features[i]); + } + + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet.GetString(), response, + /*send_async=*/false) == + PacketResult::Success) { + const char *response_cstr = response.GetStringRef().c_str(); + + // Hang on to the qSupported packet, so that platforms can do custom + // configuration of the transport before attaching/launching the + // process. + m_qSupported_response = response_cstr; + + if (::strstr(response_cstr, "qXfer:auxv:read+")) + m_supports_qXfer_auxv_read = eLazyBoolYes; + if (::strstr(response_cstr, "qXfer:libraries-svr4:read+")) + m_supports_qXfer_libraries_svr4_read = eLazyBoolYes; + if (::strstr(response_cstr, "augmented-libraries-svr4-read")) { + m_supports_qXfer_libraries_svr4_read = eLazyBoolYes; // implied + m_supports_augmented_libraries_svr4_read = eLazyBoolYes; + } + if (::strstr(response_cstr, "qXfer:libraries:read+")) + m_supports_qXfer_libraries_read = eLazyBoolYes; + if (::strstr(response_cstr, "qXfer:features:read+")) + m_supports_qXfer_features_read = eLazyBoolYes; + + // Look for a list of compressions in the features list e.g. + // qXfer:features:read+;PacketSize=20000;qEcho+;SupportedCompressions=zlib-deflate,lzma + const char *features_list = ::strstr(response_cstr, "qXfer:features:"); + if (features_list) { + const char *compressions = + ::strstr(features_list, "SupportedCompressions="); + if (compressions) { + std::vector<std::string> supported_compressions; + compressions += sizeof("SupportedCompressions=") - 1; + const char *end_of_compressions = strchr(compressions, ';'); + if (end_of_compressions == NULL) { + end_of_compressions = strchr(compressions, '\0'); + } + const char *current_compression = compressions; + while (current_compression < end_of_compressions) { + const char *next_compression_name = strchr(current_compression, ','); + const char *end_of_this_word = next_compression_name; + if (next_compression_name == NULL || + end_of_compressions < next_compression_name) { + end_of_this_word = end_of_compressions; + } + + if (end_of_this_word) { + if (end_of_this_word == current_compression) { + current_compression++; + } else { + std::string this_compression( + current_compression, end_of_this_word - current_compression); + supported_compressions.push_back(this_compression); + current_compression = end_of_this_word + 1; + } + } else { + supported_compressions.push_back(current_compression); + current_compression = end_of_compressions; + } + } + + if (supported_compressions.size() > 0) { + MaybeEnableCompression(supported_compressions); + } + } + } + + if (::strstr(response_cstr, "qEcho")) + m_supports_qEcho = eLazyBoolYes; + else + m_supports_qEcho = eLazyBoolNo; + + const char *packet_size_str = ::strstr(response_cstr, "PacketSize="); + if (packet_size_str) { + StringExtractorGDBRemote packet_response(packet_size_str + + strlen("PacketSize=")); + m_max_packet_size = + packet_response.GetHexMaxU64(/*little_endian=*/false, UINT64_MAX); + if (m_max_packet_size == 0) { + m_max_packet_size = UINT64_MAX; // Must have been a garbled response + Log *log( + ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + if (log) + log->Printf("Garbled PacketSize spec in qSupported response"); + } } - return m_supports_thread_suffix; + } } -bool -GDBRemoteCommunicationClient::GetVContSupported (char flavor) -{ - if (m_supports_vCont_c == eLazyBoolCalculate) - { - StringExtractorGDBRemote response; - m_supports_vCont_any = eLazyBoolNo; - m_supports_vCont_all = eLazyBoolNo; - m_supports_vCont_c = eLazyBoolNo; - m_supports_vCont_C = eLazyBoolNo; - m_supports_vCont_s = eLazyBoolNo; - m_supports_vCont_S = eLazyBoolNo; - if (SendPacketAndWaitForResponse("vCont?", response, false) == PacketResult::Success) - { - const char *response_cstr = response.GetStringRef().c_str(); - if (::strstr (response_cstr, ";c")) - m_supports_vCont_c = eLazyBoolYes; - - if (::strstr (response_cstr, ";C")) - m_supports_vCont_C = eLazyBoolYes; - - if (::strstr (response_cstr, ";s")) - m_supports_vCont_s = eLazyBoolYes; - - if (::strstr (response_cstr, ";S")) - m_supports_vCont_S = eLazyBoolYes; - - if (m_supports_vCont_c == eLazyBoolYes && - m_supports_vCont_C == eLazyBoolYes && - m_supports_vCont_s == eLazyBoolYes && - m_supports_vCont_S == eLazyBoolYes) - { - m_supports_vCont_all = eLazyBoolYes; - } - - if (m_supports_vCont_c == eLazyBoolYes || - m_supports_vCont_C == eLazyBoolYes || - m_supports_vCont_s == eLazyBoolYes || - m_supports_vCont_S == eLazyBoolYes) - { - m_supports_vCont_any = eLazyBoolYes; - } - } - } - - switch (flavor) - { - case 'a': return m_supports_vCont_any; - case 'A': return m_supports_vCont_all; - case 'c': return m_supports_vCont_c; - case 'C': return m_supports_vCont_C; - case 's': return m_supports_vCont_s; - case 'S': return m_supports_vCont_S; - default: break; + +bool GDBRemoteCommunicationClient::GetThreadSuffixSupported() { + if (m_supports_thread_suffix == eLazyBoolCalculate) { + StringExtractorGDBRemote response; + m_supports_thread_suffix = eLazyBoolNo; + if (SendPacketAndWaitForResponse("QThreadSuffixSupported", response, + false) == PacketResult::Success) { + if (response.IsOKResponse()) + m_supports_thread_suffix = eLazyBoolYes; } - return false; + } + return m_supports_thread_suffix; +} +bool GDBRemoteCommunicationClient::GetVContSupported(char flavor) { + if (m_supports_vCont_c == eLazyBoolCalculate) { + StringExtractorGDBRemote response; + m_supports_vCont_any = eLazyBoolNo; + m_supports_vCont_all = eLazyBoolNo; + m_supports_vCont_c = eLazyBoolNo; + m_supports_vCont_C = eLazyBoolNo; + m_supports_vCont_s = eLazyBoolNo; + m_supports_vCont_S = eLazyBoolNo; + if (SendPacketAndWaitForResponse("vCont?", response, false) == + PacketResult::Success) { + const char *response_cstr = response.GetStringRef().c_str(); + if (::strstr(response_cstr, ";c")) + m_supports_vCont_c = eLazyBoolYes; + + if (::strstr(response_cstr, ";C")) + m_supports_vCont_C = eLazyBoolYes; + + if (::strstr(response_cstr, ";s")) + m_supports_vCont_s = eLazyBoolYes; + + if (::strstr(response_cstr, ";S")) + m_supports_vCont_S = eLazyBoolYes; + + if (m_supports_vCont_c == eLazyBoolYes && + m_supports_vCont_C == eLazyBoolYes && + m_supports_vCont_s == eLazyBoolYes && + m_supports_vCont_S == eLazyBoolYes) { + m_supports_vCont_all = eLazyBoolYes; + } + + if (m_supports_vCont_c == eLazyBoolYes || + m_supports_vCont_C == eLazyBoolYes || + m_supports_vCont_s == eLazyBoolYes || + m_supports_vCont_S == eLazyBoolYes) { + m_supports_vCont_any = eLazyBoolYes; + } + } + } + + switch (flavor) { + case 'a': + return m_supports_vCont_any; + case 'A': + return m_supports_vCont_all; + case 'c': + return m_supports_vCont_c; + case 'C': + return m_supports_vCont_C; + case 's': + return m_supports_vCont_s; + case 'S': + return m_supports_vCont_S; + default: + break; + } + return false; +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationClient::SendThreadSpecificPacketAndWaitForResponse( + lldb::tid_t tid, StreamString &&payload, StringExtractorGDBRemote &response, + bool send_async) { + Lock lock(*this, send_async); + if (!lock) { + if (Log *log = ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet( + GDBR_LOG_PROCESS | GDBR_LOG_PACKETS)) + log->Printf("GDBRemoteCommunicationClient::%s: Didn't get sequence mutex " + "for %s packet.", + __FUNCTION__, payload.GetData()); + return PacketResult::ErrorNoSequenceLock; + } + + if (GetThreadSuffixSupported()) + payload.Printf(";thread:%4.4" PRIx64 ";", tid); + else { + if (!SetCurrentThread(tid)) + return PacketResult::ErrorSendFailed; + } + + return SendPacketAndWaitForResponseNoLock(payload.GetString(), response); } // Check if the target supports 'p' packet. It sends out a 'p' @@ -592,4043 +536,3095 @@ GDBRemoteCommunicationClient::GetVContSupported (char flavor) // that support is available. // // Takes a valid thread ID because p needs to apply to a thread. -bool -GDBRemoteCommunicationClient::GetpPacketSupported (lldb::tid_t tid) -{ - if (m_supports_p == eLazyBoolCalculate) - { - StringExtractorGDBRemote response; - m_supports_p = eLazyBoolNo; - char packet[256]; - if (GetThreadSuffixSupported()) - snprintf(packet, sizeof(packet), "p0;thread:%" PRIx64 ";", tid); - else - snprintf(packet, sizeof(packet), "p0"); - - if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success) - { - if (response.IsNormalResponse()) - m_supports_p = eLazyBoolYes; - } - } - return m_supports_p; -} - -StructuredData::ObjectSP -GDBRemoteCommunicationClient::GetThreadsInfo() -{ - // Get information on all threads at one using the "jThreadsInfo" packet - StructuredData::ObjectSP object_sp; - - if (m_supports_jThreadsInfo) - { - StringExtractorGDBRemote response; - response.SetResponseValidatorToJSON(); - if (SendPacketAndWaitForResponse("jThreadsInfo", response, false) == PacketResult::Success) - { - if (response.IsUnsupportedResponse()) - { - m_supports_jThreadsInfo = false; - } - else if (!response.Empty()) - { - object_sp = StructuredData::ParseJSON (response.GetStringRef()); - } - } +bool GDBRemoteCommunicationClient::GetpPacketSupported(lldb::tid_t tid) { + if (m_supports_p == eLazyBoolCalculate) { + m_supports_p = eLazyBoolNo; + StreamString payload; + payload.PutCString("p0"); + StringExtractorGDBRemote response; + if (SendThreadSpecificPacketAndWaitForResponse(tid, std::move(payload), + response, false) == + PacketResult::Success && + response.IsNormalResponse()) { + m_supports_p = eLazyBoolYes; } - return object_sp; + } + return m_supports_p; } +StructuredData::ObjectSP GDBRemoteCommunicationClient::GetThreadsInfo() { + // Get information on all threads at one using the "jThreadsInfo" packet + StructuredData::ObjectSP object_sp; -bool -GDBRemoteCommunicationClient::GetThreadExtendedInfoSupported () -{ - if (m_supports_jThreadExtendedInfo == eLazyBoolCalculate) - { - StringExtractorGDBRemote response; - m_supports_jThreadExtendedInfo = eLazyBoolNo; - if (SendPacketAndWaitForResponse("jThreadExtendedInfo:", response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - { - m_supports_jThreadExtendedInfo = eLazyBoolYes; - } - } + if (m_supports_jThreadsInfo) { + StringExtractorGDBRemote response; + response.SetResponseValidatorToJSON(); + if (SendPacketAndWaitForResponse("jThreadsInfo", response, false) == + PacketResult::Success) { + if (response.IsUnsupportedResponse()) { + m_supports_jThreadsInfo = false; + } else if (!response.Empty()) { + object_sp = StructuredData::ParseJSON(response.GetStringRef()); + } } - return m_supports_jThreadExtendedInfo; + } + return object_sp; } -bool -GDBRemoteCommunicationClient::GetLoadedDynamicLibrariesInfosSupported () -{ - if (m_supports_jLoadedDynamicLibrariesInfos == eLazyBoolCalculate) - { - StringExtractorGDBRemote response; - m_supports_jLoadedDynamicLibrariesInfos = eLazyBoolNo; - if (SendPacketAndWaitForResponse("jGetLoadedDynamicLibrariesInfos:", response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - { - m_supports_jLoadedDynamicLibrariesInfos = eLazyBoolYes; - } - } +bool GDBRemoteCommunicationClient::GetThreadExtendedInfoSupported() { + if (m_supports_jThreadExtendedInfo == eLazyBoolCalculate) { + StringExtractorGDBRemote response; + m_supports_jThreadExtendedInfo = eLazyBoolNo; + if (SendPacketAndWaitForResponse("jThreadExtendedInfo:", response, false) == + PacketResult::Success) { + if (response.IsOKResponse()) { + m_supports_jThreadExtendedInfo = eLazyBoolYes; + } } - return m_supports_jLoadedDynamicLibrariesInfos; + } + return m_supports_jThreadExtendedInfo; } -bool -GDBRemoteCommunicationClient::GetxPacketSupported () -{ - if (m_supports_x == eLazyBoolCalculate) - { - StringExtractorGDBRemote response; - m_supports_x = eLazyBoolNo; - char packet[256]; - snprintf (packet, sizeof (packet), "x0,0"); - if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - m_supports_x = eLazyBoolYes; - } +bool GDBRemoteCommunicationClient::GetLoadedDynamicLibrariesInfosSupported() { + if (m_supports_jLoadedDynamicLibrariesInfos == eLazyBoolCalculate) { + StringExtractorGDBRemote response; + m_supports_jLoadedDynamicLibrariesInfos = eLazyBoolNo; + if (SendPacketAndWaitForResponse("jGetLoadedDynamicLibrariesInfos:", + response, + false) == PacketResult::Success) { + if (response.IsOKResponse()) { + m_supports_jLoadedDynamicLibrariesInfos = eLazyBoolYes; + } } - return m_supports_x; + } + return m_supports_jLoadedDynamicLibrariesInfos; } -GDBRemoteCommunicationClient::PacketResult -GDBRemoteCommunicationClient::SendPacketsAndConcatenateResponses -( - const char *payload_prefix, - std::string &response_string -) -{ - Mutex::Locker locker; - if (!GetSequenceMutex(locker, - "ProcessGDBRemote::SendPacketsAndConcatenateResponses() failed due to not getting the sequence mutex")) - { - Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_PROCESS | GDBR_LOG_PACKETS)); - if (log) - log->Printf("error: failed to get packet sequence mutex, not sending packets with prefix '%s'", - payload_prefix); - return PacketResult::ErrorNoSequenceLock; - } - - response_string = ""; - std::string payload_prefix_str(payload_prefix); - unsigned int response_size = 0x1000; - if (response_size > GetRemoteMaxPacketSize()) { // May send qSupported packet - response_size = GetRemoteMaxPacketSize(); - } - - for (unsigned int offset = 0; true; offset += response_size) - { - StringExtractorGDBRemote this_response; - // Construct payload - char sizeDescriptor[128]; - snprintf(sizeDescriptor, sizeof(sizeDescriptor), "%x,%x", offset, response_size); - PacketResult result = SendPacketAndWaitForResponse((payload_prefix_str + sizeDescriptor).c_str(), - this_response, - /*send_async=*/false); - if (result != PacketResult::Success) - return result; - - const std::string &this_string = this_response.GetStringRef(); - - // Check for m or l as first character; l seems to mean this is the last chunk - char first_char = *this_string.c_str(); - if (first_char != 'm' && first_char != 'l') - { - return PacketResult::ErrorReplyInvalid; - } - // Concatenate the result so far (skipping 'm' or 'l') - response_string.append(this_string, 1, std::string::npos); - if (first_char == 'l') - // We're done - return PacketResult::Success; +bool GDBRemoteCommunicationClient::GetSharedCacheInfoSupported() { + if (m_supports_jGetSharedCacheInfo == eLazyBoolCalculate) { + StringExtractorGDBRemote response; + m_supports_jGetSharedCacheInfo = eLazyBoolNo; + if (SendPacketAndWaitForResponse("jGetSharedCacheInfo:", response, false) == + PacketResult::Success) { + if (response.IsOKResponse()) { + m_supports_jGetSharedCacheInfo = eLazyBoolYes; + } } + } + return m_supports_jGetSharedCacheInfo; } -GDBRemoteCommunicationClient::PacketResult -GDBRemoteCommunicationClient::SendPacketAndWaitForResponse -( - const char *payload, - StringExtractorGDBRemote &response, - bool send_async -) -{ - return SendPacketAndWaitForResponse (payload, - ::strlen (payload), - response, - send_async); -} - -GDBRemoteCommunicationClient::PacketResult -GDBRemoteCommunicationClient::SendPacketAndWaitForResponseNoLock (const char *payload, - size_t payload_length, - StringExtractorGDBRemote &response) -{ - PacketResult packet_result = SendPacketNoLock(payload, payload_length); - if (packet_result == PacketResult::Success) - { - const size_t max_response_retries = 3; - for (size_t i=0; i<max_response_retries; ++i) - { - packet_result = ReadPacket(response, GetPacketTimeoutInMicroSeconds (), true); - // Make sure we received a response - if (packet_result != PacketResult::Success) - return packet_result; - // Make sure our response is valid for the payload that was sent - if (response.ValidateResponse()) - return packet_result; - // Response says it wasn't valid - Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS); - if (log) - log->Printf("error: packet with payload \"%*s\" got invalid response \"%s\": %s", - (int)payload_length, - payload, - response.GetStringRef().c_str(), - (i == (max_response_retries - 1)) ? "using invalid response and giving up" : "ignoring response and waiting for another"); - } +bool GDBRemoteCommunicationClient::GetxPacketSupported() { + if (m_supports_x == eLazyBoolCalculate) { + StringExtractorGDBRemote response; + m_supports_x = eLazyBoolNo; + char packet[256]; + snprintf(packet, sizeof(packet), "x0,0"); + if (SendPacketAndWaitForResponse(packet, response, false) == + PacketResult::Success) { + if (response.IsOKResponse()) + m_supports_x = eLazyBoolYes; } - return packet_result; + } + return m_supports_x; } GDBRemoteCommunicationClient::PacketResult -GDBRemoteCommunicationClient::SendPacketAndWaitForResponse -( - const char *payload, - size_t payload_length, - StringExtractorGDBRemote &response, - bool send_async -) -{ - PacketResult packet_result = PacketResult::ErrorSendFailed; - Mutex::Locker locker; - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); - - // In order to stop async notifications from being processed in the middle of the - // send/receive sequence Hijack the broadcast. Then rebroadcast any events when we are done. - static ListenerSP hijack_listener_sp(Listener::MakeListener("lldb.NotifyHijacker")); - HijackBroadcaster(hijack_listener_sp, eBroadcastBitGdbReadThreadGotNotify); - - if (GetSequenceMutex (locker)) - { - packet_result = SendPacketAndWaitForResponseNoLock (payload, payload_length, response); - } - else - { - if (send_async) - { - if (IsRunning()) - { - std::lock_guard<std::recursive_mutex> guard(m_async_mutex); - m_async_packet.assign(payload, payload_length); - m_async_response.CopyResponseValidator(response); - m_async_packet_predicate.SetValue (true, eBroadcastNever); - - if (log) - log->Printf ("async: async packet = %s", m_async_packet.c_str()); - - bool timed_out = false; - if (SendInterrupt(locker, 2, timed_out)) - { - if (m_interrupt_sent) - { - m_interrupt_sent = false; - TimeValue timeout_time; - timeout_time = TimeValue::Now(); - timeout_time.OffsetWithSeconds (m_packet_timeout); - - if (log) - log->Printf ("async: sent interrupt"); - - if (m_async_packet_predicate.WaitForValueEqualTo (false, &timeout_time, &timed_out)) - { - if (log) - log->Printf ("async: got response"); - - // Swap the response buffer to avoid malloc and string copy - response.GetStringRef().swap (m_async_response.GetStringRef()); - packet_result = m_async_result; - } - else - { - if (log) - log->Printf ("async: timed out waiting for response"); - } - - // Make sure we wait until the continue packet has been sent again... - if (m_private_is_running.WaitForValueEqualTo (true, &timeout_time, &timed_out)) - { - if (log) - { - if (timed_out) - log->Printf ("async: timed out waiting for process to resume, but process was resumed"); - else - log->Printf ("async: async packet sent"); - } - } - else - { - if (log) - log->Printf ("async: timed out waiting for process to resume"); - } - } - else - { - // We had a racy condition where we went to send the interrupt - // yet we were able to get the lock, so the process must have - // just stopped? - if (log) - log->Printf ("async: got lock without sending interrupt"); - // Send the packet normally since we got the lock - packet_result = SendPacketAndWaitForResponseNoLock (payload, payload_length, response); - } - } - else - { - if (log) - log->Printf ("async: failed to interrupt"); - } - - m_async_response.SetResponseValidator(nullptr, nullptr); - - } - else - { - if (log) - log->Printf ("async: not running, async is ignored"); - } - } - else - { - if (log) - log->Printf("error: failed to get packet sequence mutex, not sending packet '%*s'", (int) payload_length, payload); - } - } - - // Remove our Hijacking listener from the broadcast. - RestoreBroadcaster(); - - // If a notification event occurred, rebroadcast since it can now be processed safely. - EventSP event_sp; - if (hijack_listener_sp->GetNextEvent(event_sp)) - BroadcastEvent(event_sp); - - return packet_result; -} - -static const char *end_delimiter = "--end--;"; -static const int end_delimiter_len = 8; - -std::string -GDBRemoteCommunicationClient::HarmonizeThreadIdsForProfileData -( ProcessGDBRemote *process, - StringExtractorGDBRemote& profileDataExtractor -) -{ - std::map<uint64_t, uint32_t> new_thread_id_to_used_usec_map; - std::stringstream final_output; - std::string name, value; - - // Going to assuming thread_used_usec comes first, else bail out. - while (profileDataExtractor.GetNameColonValue(name, value)) - { - if (name.compare("thread_used_id") == 0) - { - StringExtractor threadIDHexExtractor(value.c_str()); - uint64_t thread_id = threadIDHexExtractor.GetHexMaxU64(false, 0); - - bool has_used_usec = false; - uint32_t curr_used_usec = 0; - std::string usec_name, usec_value; - uint32_t input_file_pos = profileDataExtractor.GetFilePos(); - if (profileDataExtractor.GetNameColonValue(usec_name, usec_value)) - { - if (usec_name.compare("thread_used_usec") == 0) - { - has_used_usec = true; - curr_used_usec = strtoull(usec_value.c_str(), NULL, 0); - } - else - { - // We didn't find what we want, it is probably - // an older version. Bail out. - profileDataExtractor.SetFilePos(input_file_pos); - } - } - - if (has_used_usec) - { - uint32_t prev_used_usec = 0; - std::map<uint64_t, uint32_t>::iterator iterator = m_thread_id_to_used_usec_map.find(thread_id); - if (iterator != m_thread_id_to_used_usec_map.end()) - { - prev_used_usec = m_thread_id_to_used_usec_map[thread_id]; - } - - uint32_t real_used_usec = curr_used_usec - prev_used_usec; - // A good first time record is one that runs for at least 0.25 sec - bool good_first_time = (prev_used_usec == 0) && (real_used_usec > 250000); - bool good_subsequent_time = (prev_used_usec > 0) && - ((real_used_usec > 0) || (process->HasAssignedIndexIDToThread(thread_id))); - - if (good_first_time || good_subsequent_time) - { - // We try to avoid doing too many index id reservation, - // resulting in fast increase of index ids. - - final_output << name << ":"; - int32_t index_id = process->AssignIndexIDToThread(thread_id); - final_output << index_id << ";"; - - final_output << usec_name << ":" << usec_value << ";"; - } - else - { - // Skip past 'thread_used_name'. - std::string local_name, local_value; - profileDataExtractor.GetNameColonValue(local_name, local_value); - } - - // Store current time as previous time so that they can be compared later. - new_thread_id_to_used_usec_map[thread_id] = curr_used_usec; - } - else - { - // Bail out and use old string. - final_output << name << ":" << value << ";"; - } - } - else - { - final_output << name << ":" << value << ";"; - } - } - final_output << end_delimiter; - m_thread_id_to_used_usec_map = new_thread_id_to_used_usec_map; - - return final_output.str(); -} - -bool -GDBRemoteCommunicationClient::SendvContPacket -( - ProcessGDBRemote *process, - const char *payload, - size_t packet_length, - StringExtractorGDBRemote &response -) -{ - - m_curr_tid = LLDB_INVALID_THREAD_ID; - Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); - if (log) - log->Printf("GDBRemoteCommunicationClient::%s ()", __FUNCTION__); - - // we want to lock down packet sending while we continue - Mutex::Locker locker(m_sequence_mutex); - - // here we broadcast this before we even send the packet!! - // this signals doContinue() to exit - BroadcastEvent(eBroadcastBitRunPacketSent, NULL); - - // set the public state to running - m_public_is_running.SetValue(true, eBroadcastNever); - - // Set the starting continue packet into "continue_packet". This packet - // may change if we are interrupted and we continue after an async packet... - std::string continue_packet(payload, packet_length); - - if (log) - log->Printf("GDBRemoteCommunicationClient::%s () sending vCont packet: %s", __FUNCTION__, continue_packet.c_str()); - - if (SendPacketNoLock(continue_packet.c_str(), continue_packet.size()) != PacketResult::Success) - return false; - - // set the private state to running and broadcast this - m_private_is_running.SetValue(true, eBroadcastAlways); - +GDBRemoteCommunicationClient::SendPacketsAndConcatenateResponses( + const char *payload_prefix, std::string &response_string) { + Lock lock(*this, false); + if (!lock) { + Log *log(ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(GDBR_LOG_PROCESS | + GDBR_LOG_PACKETS)); if (log) - log->Printf("GDBRemoteCommunicationClient::%s () ReadPacket(%s)", __FUNCTION__, continue_packet.c_str()); - - // wait for the response to the vCont - if (ReadPacket(response, UINT32_MAX, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - return true; - } - - return false; -} - -StateType -GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse -( - ProcessGDBRemote *process, - const char *payload, - size_t packet_length, - StringExtractorGDBRemote &response -) -{ - m_curr_tid = LLDB_INVALID_THREAD_ID; - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); - if (log) - log->Printf ("GDBRemoteCommunicationClient::%s ()", __FUNCTION__); - - Mutex::Locker locker(m_sequence_mutex); - StateType state = eStateRunning; - - m_public_is_running.SetValue (true, eBroadcastNever); - // Set the starting continue packet into "continue_packet". This packet - // may change if we are interrupted and we continue after an async packet... - std::string continue_packet(payload, packet_length); - - const auto sigstop_signo = process->GetUnixSignals()->GetSignalNumberFromName("SIGSTOP"); - const auto sigint_signo = process->GetUnixSignals()->GetSignalNumberFromName("SIGINT"); - - bool got_async_packet = false; - bool broadcast_sent = false; - - while (state == eStateRunning) - { - if (!got_async_packet) - { - if (log) - log->Printf ("GDBRemoteCommunicationClient::%s () sending continue packet: %s", __FUNCTION__, continue_packet.c_str()); - if (SendPacketNoLock(continue_packet.c_str(), continue_packet.size()) != PacketResult::Success) - state = eStateInvalid; - else - m_interrupt_sent = false; - - if (! broadcast_sent) - { - BroadcastEvent(eBroadcastBitRunPacketSent, NULL); - broadcast_sent = true; - } - - m_private_is_running.SetValue (true, eBroadcastAlways); - } - - got_async_packet = false; - - if (log) - log->Printf ("GDBRemoteCommunicationClient::%s () ReadPacket(%s)", __FUNCTION__, continue_packet.c_str()); - - if (ReadPacket(response, UINT32_MAX, false) == PacketResult::Success) - { - if (response.Empty()) - state = eStateInvalid; - else - { - const char stop_type = response.GetChar(); - if (log) - log->Printf ("GDBRemoteCommunicationClient::%s () got packet: %s", __FUNCTION__, response.GetStringRef().c_str()); - switch (stop_type) - { - case 'T': - case 'S': - { - if (process->GetStopID() == 0) - { - if (process->GetID() == LLDB_INVALID_PROCESS_ID) - { - lldb::pid_t pid = GetCurrentProcessID (); - if (pid != LLDB_INVALID_PROCESS_ID) - process->SetID (pid); - } - process->BuildDynamicRegisterInfo (true); - } - - // Privately notify any internal threads that we have stopped - // in case we wanted to interrupt our process, yet we might - // send a packet and continue without returning control to the - // user. - m_private_is_running.SetValue (false, eBroadcastAlways); - - const uint8_t signo = response.GetHexU8 (UINT8_MAX); - - bool continue_after_async = m_async_signal != -1 || m_async_packet_predicate.GetValue(); - if (continue_after_async || m_interrupt_sent) - { - // We sent an interrupt packet to stop the inferior process - // for an async signal or to send an async packet while running - // but we might have been single stepping and received the - // stop packet for the step instead of for the interrupt packet. - // Typically when an interrupt is sent a SIGINT or SIGSTOP - // is used, so if we get anything else, we need to try and - // get another stop reply packet that may have been sent - // due to sending the interrupt when the target is stopped - // which will just re-send a copy of the last stop reply - // packet. If we don't do this, then the reply for our - // async packet will be the repeat stop reply packet and cause - // a lot of trouble for us! We also have some debugserver - // binaries that would send two stop replies anytime the process - // was interrupted, so we need to also check for an extra - // stop reply packet if we interrupted the process - const bool received_nonstop_signal = signo != sigint_signo && signo != sigstop_signo; - if (m_interrupt_sent || received_nonstop_signal) - { - if (received_nonstop_signal) - continue_after_async = false; - - // Try for a very brief time (0.1s) to get another stop reply - // packet to make sure it doesn't get in the way - StringExtractorGDBRemote extra_stop_reply_packet; - uint32_t timeout_usec = 100000; - if (ReadPacket (extra_stop_reply_packet, timeout_usec, false) == PacketResult::Success) - { - switch (extra_stop_reply_packet.GetChar()) - { - case 'T': - case 'S': - // We did get an extra stop reply, which means - // our interrupt didn't stop the target so we - // shouldn't continue after the async signal - // or packet is sent... - continue_after_async = false; - break; - } - } - } - } - - if (m_async_signal != -1) - { - if (log) - log->Printf ("async: send signo = %s", Host::GetSignalAsCString (m_async_signal)); - - // Save off the async signal we are supposed to send - const int async_signal = m_async_signal; - // Clear the async signal member so we don't end up - // sending the signal multiple times... - m_async_signal = -1; - // Check which signal we stopped with - if (signo == async_signal) - { - if (log) - log->Printf ("async: stopped with signal %s, we are done running", Host::GetSignalAsCString (signo)); - - // We already stopped with a signal that we wanted - // to stop with, so we are done - } - else - { - // We stopped with a different signal that the one - // we wanted to stop with, so now we must resume - // with the signal we want - char signal_packet[32]; - int signal_packet_len = 0; - signal_packet_len = ::snprintf (signal_packet, - sizeof (signal_packet), - "C%2.2x", - async_signal); - - if (log) - log->Printf ("async: stopped with signal %s, resume with %s", - Host::GetSignalAsCString (signo), - Host::GetSignalAsCString (async_signal)); - - // Set the continue packet to resume even if the - // interrupt didn't cause our stop (ignore continue_after_async) - continue_packet.assign(signal_packet, signal_packet_len); - continue; - } - } - else if (m_async_packet_predicate.GetValue()) - { - Log * packet_log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS)); - - // We are supposed to send an asynchronous packet while - // we are running. - m_async_response.Clear(); - if (m_async_packet.empty()) - { - m_async_result = PacketResult::ErrorSendFailed; - if (packet_log) - packet_log->Printf ("async: error: empty async packet"); - - } - else - { - if (packet_log) - packet_log->Printf ("async: sending packet"); - - m_async_result = SendPacketAndWaitForResponse (&m_async_packet[0], - m_async_packet.size(), - m_async_response, - false); - } - // Let the other thread that was trying to send the async - // packet know that the packet has been sent and response is - // ready... - m_async_packet_predicate.SetValue(false, eBroadcastAlways); - - if (packet_log) - packet_log->Printf ("async: sent packet, continue_after_async = %i", continue_after_async); - - // Set the continue packet to resume if our interrupt - // for the async packet did cause the stop - if (continue_after_async) - { - // Reverting this for now as it is causing deadlocks - // in programs (<rdar://problem/11529853>). In the future - // we should check our thread list and "do the right thing" - // for new threads that show up while we stop and run async - // packets. Setting the packet to 'c' to continue all threads - // is the right thing to do 99.99% of the time because if a - // thread was single stepping, and we sent an interrupt, we - // will notice above that we didn't stop due to an interrupt - // but stopped due to stepping and we would _not_ continue. - continue_packet.assign (1, 'c'); - continue; - } - } - // Stop with signal and thread info - state = eStateStopped; - } - break; - - case 'W': - case 'X': - // process exited - state = eStateExited; - break; - - case 'O': - // STDOUT - { - got_async_packet = true; - std::string inferior_stdout; - inferior_stdout.reserve(response.GetBytesLeft () / 2); - - uint8_t ch; - while (response.GetHexU8Ex(ch)) - { - if (ch != 0) - inferior_stdout.append(1, (char)ch); - } - process->AppendSTDOUT (inferior_stdout.c_str(), inferior_stdout.size()); - } - break; - - case 'A': - // Async miscellaneous reply. Right now, only profile data is coming through this channel. - { - got_async_packet = true; - std::string input = response.GetStringRef().substr(1); // '1' to move beyond 'A' - if (m_partial_profile_data.length() > 0) - { - m_partial_profile_data.append(input); - input = m_partial_profile_data; - m_partial_profile_data.clear(); - } - - size_t found, pos = 0, len = input.length(); - while ((found = input.find(end_delimiter, pos)) != std::string::npos) - { - StringExtractorGDBRemote profileDataExtractor(input.substr(pos, found).c_str()); - std::string profile_data = HarmonizeThreadIdsForProfileData(process, profileDataExtractor); - process->BroadcastAsyncProfileData (profile_data); - - pos = found + end_delimiter_len; - } - - if (pos < len) - { - // Last incomplete chunk. - m_partial_profile_data = input.substr(pos); - } - } - break; - - case 'E': - // ERROR - state = eStateInvalid; - break; - - default: - if (log) - log->Printf ("GDBRemoteCommunicationClient::%s () unrecognized async packet", __FUNCTION__); - state = eStateInvalid; - break; - } - } - } - else - { - if (log) - log->Printf ("GDBRemoteCommunicationClient::%s () ReadPacket(...) => false", __FUNCTION__); - state = eStateInvalid; - } - } - if (log) - log->Printf ("GDBRemoteCommunicationClient::%s () => %s", __FUNCTION__, StateAsCString(state)); - response.SetFilePos(0); - m_private_is_running.SetValue (false, eBroadcastAlways); - m_public_is_running.SetValue (false, eBroadcastAlways); - return state; -} - -bool -GDBRemoteCommunicationClient::SendAsyncSignal (int signo) -{ - std::lock_guard<std::recursive_mutex> guard(m_async_mutex); - m_async_signal = signo; - bool timed_out = false; - Mutex::Locker locker; - if (SendInterrupt (locker, 1, timed_out)) - return true; - m_async_signal = -1; - return false; -} - -// This function takes a mutex locker as a parameter in case the GetSequenceMutex -// actually succeeds. If it doesn't succeed in acquiring the sequence mutex -// (the expected result), then it will send the halt packet. If it does succeed -// then the caller that requested the interrupt will want to keep the sequence -// locked down so that no one else can send packets while the caller has control. -// This function usually gets called when we are running and need to stop the -// target. It can also be used when we are running and we need to do something -// else (like read/write memory), so we need to interrupt the running process -// (gdb remote protocol requires this), and do what we need to do, then resume. - -bool -GDBRemoteCommunicationClient::SendInterrupt -( - Mutex::Locker& locker, - uint32_t seconds_to_wait_for_stop, - bool &timed_out -) -{ - timed_out = false; - Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_PROCESS | GDBR_LOG_PACKETS)); - - if (IsRunning()) - { - // Only send an interrupt if our debugserver is running... - if (GetSequenceMutex (locker)) - { - if (log) - log->Printf ("SendInterrupt () - got sequence mutex without having to interrupt"); - } - else - { - // Someone has the mutex locked waiting for a response or for the - // inferior to stop, so send the interrupt on the down low... - char ctrl_c = '\x03'; - ConnectionStatus status = eConnectionStatusSuccess; - size_t bytes_written = Write (&ctrl_c, 1, status, NULL); - if (log) - log->PutCString("send packet: \\x03"); - if (bytes_written > 0) - { - m_interrupt_sent = true; - if (seconds_to_wait_for_stop) - { - TimeValue timeout; - if (seconds_to_wait_for_stop) - { - timeout = TimeValue::Now(); - timeout.OffsetWithSeconds (seconds_to_wait_for_stop); - } - if (m_private_is_running.WaitForValueEqualTo (false, &timeout, &timed_out)) - { - if (log) - log->PutCString ("SendInterrupt () - sent interrupt, private state stopped"); - return true; - } - else - { - if (log) - log->Printf ("SendInterrupt () - sent interrupt, timed out wating for async thread resume"); - } - } - else - { - if (log) - log->Printf ("SendInterrupt () - sent interrupt, not waiting for stop..."); - return true; - } - } - else - { - if (log) - log->Printf ("SendInterrupt () - failed to write interrupt"); - } - return false; - } - } - else - { - if (log) - log->Printf ("SendInterrupt () - not running"); - } - return true; -} - -lldb::pid_t -GDBRemoteCommunicationClient::GetCurrentProcessID (bool allow_lazy) -{ - if (allow_lazy && m_curr_pid_is_valid == eLazyBoolYes) - return m_curr_pid; - - // First try to retrieve the pid via the qProcessInfo request. - GetCurrentProcessInfo (allow_lazy); - if (m_curr_pid_is_valid == eLazyBoolYes) - { - // We really got it. + log->Printf("error: failed to get packet sequence mutex, not sending " + "packets with prefix '%s'", + payload_prefix); + return PacketResult::ErrorNoSequenceLock; + } + + response_string = ""; + std::string payload_prefix_str(payload_prefix); + unsigned int response_size = 0x1000; + if (response_size > GetRemoteMaxPacketSize()) { // May send qSupported packet + response_size = GetRemoteMaxPacketSize(); + } + + for (unsigned int offset = 0; true; offset += response_size) { + StringExtractorGDBRemote this_response; + // Construct payload + char sizeDescriptor[128]; + snprintf(sizeDescriptor, sizeof(sizeDescriptor), "%x,%x", offset, + response_size); + PacketResult result = SendPacketAndWaitForResponseNoLock( + payload_prefix_str + sizeDescriptor, this_response); + if (result != PacketResult::Success) + return result; + + const std::string &this_string = this_response.GetStringRef(); + + // Check for m or l as first character; l seems to mean this is the last + // chunk + char first_char = *this_string.c_str(); + if (first_char != 'm' && first_char != 'l') { + return PacketResult::ErrorReplyInvalid; + } + // Concatenate the result so far (skipping 'm' or 'l') + response_string.append(this_string, 1, std::string::npos); + if (first_char == 'l') + // We're done + return PacketResult::Success; + } +} + +lldb::pid_t GDBRemoteCommunicationClient::GetCurrentProcessID(bool allow_lazy) { + if (allow_lazy && m_curr_pid_is_valid == eLazyBoolYes) + return m_curr_pid; + + // First try to retrieve the pid via the qProcessInfo request. + GetCurrentProcessInfo(allow_lazy); + if (m_curr_pid_is_valid == eLazyBoolYes) { + // We really got it. + return m_curr_pid; + } else { + // If we don't get a response for qProcessInfo, check if $qC gives us a + // result. + // $qC only returns a real process id on older debugserver and lldb-platform + // stubs. + // The gdb remote protocol documents $qC as returning the thread id, which + // newer + // debugserver and lldb-gdbserver stubs return correctly. + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse("qC", response, false) == + PacketResult::Success) { + if (response.GetChar() == 'Q') { + if (response.GetChar() == 'C') { + m_curr_pid = response.GetHexMaxU32(false, LLDB_INVALID_PROCESS_ID); + if (m_curr_pid != LLDB_INVALID_PROCESS_ID) { + m_curr_pid_is_valid = eLazyBoolYes; + return m_curr_pid; + } + } + } + } + + // If we don't get a response for $qC, check if $qfThreadID gives us a + // result. + if (m_curr_pid == LLDB_INVALID_PROCESS_ID) { + std::vector<lldb::tid_t> thread_ids; + bool sequence_mutex_unavailable; + size_t size; + size = GetCurrentThreadIDs(thread_ids, sequence_mutex_unavailable); + if (size && sequence_mutex_unavailable == false) { + m_curr_pid = thread_ids.front(); + m_curr_pid_is_valid = eLazyBoolYes; return m_curr_pid; + } + } + } + + return LLDB_INVALID_PROCESS_ID; +} + +bool GDBRemoteCommunicationClient::GetLaunchSuccess(std::string &error_str) { + error_str.clear(); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse("qLaunchSuccess", response, false) == + PacketResult::Success) { + if (response.IsOKResponse()) + return true; + if (response.GetChar() == 'E') { + // A string the describes what failed when launching... + error_str = response.GetStringRef().substr(1); + } else { + error_str.assign("unknown error occurred launching process"); + } + } else { + error_str.assign("timed out waiting for app to launch"); + } + return false; +} + +int GDBRemoteCommunicationClient::SendArgumentsPacket( + const ProcessLaunchInfo &launch_info) { + // Since we don't get the send argv0 separate from the executable path, we + // need to + // make sure to use the actual executable path found in the launch_info... + std::vector<const char *> argv; + FileSpec exe_file = launch_info.GetExecutableFile(); + std::string exe_path; + const char *arg = NULL; + const Args &launch_args = launch_info.GetArguments(); + if (exe_file) + exe_path = exe_file.GetPath(false); + else { + arg = launch_args.GetArgumentAtIndex(0); + if (arg) + exe_path = arg; + } + if (!exe_path.empty()) { + argv.push_back(exe_path.c_str()); + for (uint32_t i = 1; (arg = launch_args.GetArgumentAtIndex(i)) != NULL; + ++i) { + if (arg) + argv.push_back(arg); + } + } + if (!argv.empty()) { + StreamString packet; + packet.PutChar('A'); + for (size_t i = 0, n = argv.size(); i < n; ++i) { + arg = argv[i]; + const int arg_len = strlen(arg); + if (i > 0) + packet.PutChar(','); + packet.Printf("%i,%i,", arg_len * 2, (int)i); + packet.PutBytesAsRawHex8(arg, arg_len); } - else - { - // If we don't get a response for qProcessInfo, check if $qC gives us a result. - // $qC only returns a real process id on older debugserver and lldb-platform stubs. - // The gdb remote protocol documents $qC as returning the thread id, which newer - // debugserver and lldb-gdbserver stubs return correctly. - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("qC", strlen("qC"), response, false) == PacketResult::Success) - { - if (response.GetChar() == 'Q') - { - if (response.GetChar() == 'C') - { - m_curr_pid = response.GetHexMaxU32 (false, LLDB_INVALID_PROCESS_ID); - if (m_curr_pid != LLDB_INVALID_PROCESS_ID) - { - m_curr_pid_is_valid = eLazyBoolYes; - return m_curr_pid; - } - } - } - } - - // If we don't get a response for $qC, check if $qfThreadID gives us a result. - if (m_curr_pid == LLDB_INVALID_PROCESS_ID) - { - std::vector<lldb::tid_t> thread_ids; - bool sequence_mutex_unavailable; - size_t size; - size = GetCurrentThreadIDs (thread_ids, sequence_mutex_unavailable); - if (size && sequence_mutex_unavailable == false) - { - m_curr_pid = thread_ids.front(); - m_curr_pid_is_valid = eLazyBoolYes; - return m_curr_pid; - } - } - } - - return LLDB_INVALID_PROCESS_ID; -} -bool -GDBRemoteCommunicationClient::GetLaunchSuccess (std::string &error_str) -{ - error_str.clear(); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("qLaunchSuccess", strlen("qLaunchSuccess"), response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - return true; - if (response.GetChar() == 'E') - { - // A string the describes what failed when launching... - error_str = response.GetStringRef().substr(1); - } - else - { - error_str.assign ("unknown error occurred launching process"); - } - } - else - { - error_str.assign ("timed out waiting for app to launch"); + if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == + PacketResult::Success) { + if (response.IsOKResponse()) + return 0; + uint8_t error = response.GetError(); + if (error) + return error; } - return false; + } + return -1; } -int -GDBRemoteCommunicationClient::SendArgumentsPacket (const ProcessLaunchInfo &launch_info) -{ - // Since we don't get the send argv0 separate from the executable path, we need to - // make sure to use the actual executable path found in the launch_info... - std::vector<const char *> argv; - FileSpec exe_file = launch_info.GetExecutableFile(); - std::string exe_path; - const char *arg = NULL; - const Args &launch_args = launch_info.GetArguments(); - if (exe_file) - exe_path = exe_file.GetPath(false); - else - { - arg = launch_args.GetArgumentAtIndex(0); - if (arg) - exe_path = arg; - } - if (!exe_path.empty()) - { - argv.push_back(exe_path.c_str()); - for (uint32_t i=1; (arg = launch_args.GetArgumentAtIndex(i)) != NULL; ++i) - { - if (arg) - argv.push_back(arg); +int GDBRemoteCommunicationClient::SendEnvironmentPacket( + char const *name_equal_value) { + if (name_equal_value && name_equal_value[0]) { + StreamString packet; + bool send_hex_encoding = false; + for (const char *p = name_equal_value; + *p != '\0' && send_hex_encoding == false; ++p) { + if (isprint(*p)) { + switch (*p) { + case '$': + case '#': + case '*': + case '}': + send_hex_encoding = true; + break; + default: + break; } + } else { + // We have non printable characters, lets hex encode this... + send_hex_encoding = true; + } } - if (!argv.empty()) - { - StreamString packet; - packet.PutChar('A'); - for (size_t i = 0, n = argv.size(); i < n; ++i) - { - arg = argv[i]; - const int arg_len = strlen(arg); - if (i > 0) - packet.PutChar(','); - packet.Printf("%i,%i,", arg_len * 2, (int)i); - packet.PutBytesAsRawHex8 (arg, arg_len); - } - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - return 0; - uint8_t error = response.GetError(); - if (error) - return error; + StringExtractorGDBRemote response; + if (send_hex_encoding) { + if (m_supports_QEnvironmentHexEncoded) { + packet.PutCString("QEnvironmentHexEncoded:"); + packet.PutBytesAsRawHex8(name_equal_value, strlen(name_equal_value)); + if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == + PacketResult::Success) { + if (response.IsOKResponse()) + return 0; + uint8_t error = response.GetError(); + if (error) + return error; + if (response.IsUnsupportedResponse()) + m_supports_QEnvironmentHexEncoded = false; } - } - return -1; -} + } -int -GDBRemoteCommunicationClient::SendEnvironmentPacket (char const *name_equal_value) -{ - if (name_equal_value && name_equal_value[0]) - { - StreamString packet; - bool send_hex_encoding = false; - for (const char *p = name_equal_value; *p != '\0' && send_hex_encoding == false; ++p) - { - if (isprint(*p)) - { - switch (*p) - { - case '$': - case '#': - case '*': - case '}': - send_hex_encoding = true; - break; - default: - break; - } - } - else - { - // We have non printable characters, lets hex encode this... - send_hex_encoding = true; - } - } - - StringExtractorGDBRemote response; - if (send_hex_encoding) - { - if (m_supports_QEnvironmentHexEncoded) - { - packet.PutCString("QEnvironmentHexEncoded:"); - packet.PutBytesAsRawHex8 (name_equal_value, strlen(name_equal_value)); - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - return 0; - uint8_t error = response.GetError(); - if (error) - return error; - if (response.IsUnsupportedResponse()) - m_supports_QEnvironmentHexEncoded = false; - } - } - - } - else if (m_supports_QEnvironment) - { - packet.Printf("QEnvironment:%s", name_equal_value); - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - return 0; - uint8_t error = response.GetError(); - if (error) - return error; - if (response.IsUnsupportedResponse()) - m_supports_QEnvironment = false; - } - } + } else if (m_supports_QEnvironment) { + packet.Printf("QEnvironment:%s", name_equal_value); + if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == + PacketResult::Success) { + if (response.IsOKResponse()) + return 0; + uint8_t error = response.GetError(); + if (error) + return error; + if (response.IsUnsupportedResponse()) + m_supports_QEnvironment = false; + } } - return -1; + } + return -1; } -int -GDBRemoteCommunicationClient::SendLaunchArchPacket (char const *arch) -{ - if (arch && arch[0]) - { - StreamString packet; - packet.Printf("QLaunchArch:%s", arch); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - return 0; - uint8_t error = response.GetError(); - if (error) - return error; - } +int GDBRemoteCommunicationClient::SendLaunchArchPacket(char const *arch) { + if (arch && arch[0]) { + StreamString packet; + packet.Printf("QLaunchArch:%s", arch); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == + PacketResult::Success) { + if (response.IsOKResponse()) + return 0; + uint8_t error = response.GetError(); + if (error) + return error; } - return -1; + } + return -1; } -int -GDBRemoteCommunicationClient::SendLaunchEventDataPacket (char const *data, bool *was_supported) -{ - if (data && *data != '\0') - { - StreamString packet; - packet.Printf("QSetProcessEvent:%s", data); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - { - if (was_supported) - *was_supported = true; - return 0; - } - else if (response.IsUnsupportedResponse()) - { - if (was_supported) - *was_supported = false; - return -1; - } - else - { - uint8_t error = response.GetError(); - if (was_supported) - *was_supported = true; - if (error) - return error; - } - } +int GDBRemoteCommunicationClient::SendLaunchEventDataPacket( + char const *data, bool *was_supported) { + if (data && *data != '\0') { + StreamString packet; + packet.Printf("QSetProcessEvent:%s", data); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == + PacketResult::Success) { + if (response.IsOKResponse()) { + if (was_supported) + *was_supported = true; + return 0; + } else if (response.IsUnsupportedResponse()) { + if (was_supported) + *was_supported = false; + return -1; + } else { + uint8_t error = response.GetError(); + if (was_supported) + *was_supported = true; + if (error) + return error; + } } - return -1; + } + return -1; } -bool -GDBRemoteCommunicationClient::GetOSVersion (uint32_t &major, - uint32_t &minor, - uint32_t &update) -{ - if (GetHostInfo ()) - { - if (m_os_version_major != UINT32_MAX) - { - major = m_os_version_major; - minor = m_os_version_minor; - update = m_os_version_update; - return true; - } +bool GDBRemoteCommunicationClient::GetOSVersion(uint32_t &major, + uint32_t &minor, + uint32_t &update) { + if (GetHostInfo()) { + if (m_os_version_major != UINT32_MAX) { + major = m_os_version_major; + minor = m_os_version_minor; + update = m_os_version_update; + return true; } - return false; + } + return false; } -bool -GDBRemoteCommunicationClient::GetOSBuildString (std::string &s) -{ - if (GetHostInfo ()) - { - if (!m_os_build.empty()) - { - s = m_os_build; - return true; - } +bool GDBRemoteCommunicationClient::GetOSBuildString(std::string &s) { + if (GetHostInfo()) { + if (!m_os_build.empty()) { + s = m_os_build; + return true; } - s.clear(); - return false; + } + s.clear(); + return false; } - -bool -GDBRemoteCommunicationClient::GetOSKernelDescription (std::string &s) -{ - if (GetHostInfo ()) - { - if (!m_os_kernel.empty()) - { - s = m_os_kernel; - return true; - } +bool GDBRemoteCommunicationClient::GetOSKernelDescription(std::string &s) { + if (GetHostInfo()) { + if (!m_os_kernel.empty()) { + s = m_os_kernel; + return true; } - s.clear(); - return false; + } + s.clear(); + return false; } -bool -GDBRemoteCommunicationClient::GetHostname (std::string &s) -{ - if (GetHostInfo ()) - { - if (!m_hostname.empty()) - { - s = m_hostname; - return true; - } +bool GDBRemoteCommunicationClient::GetHostname(std::string &s) { + if (GetHostInfo()) { + if (!m_hostname.empty()) { + s = m_hostname; + return true; } - s.clear(); - return false; + } + s.clear(); + return false; } -ArchSpec -GDBRemoteCommunicationClient::GetSystemArchitecture () -{ - if (GetHostInfo ()) - return m_host_arch; - return ArchSpec(); +ArchSpec GDBRemoteCommunicationClient::GetSystemArchitecture() { + if (GetHostInfo()) + return m_host_arch; + return ArchSpec(); } const lldb_private::ArchSpec & -GDBRemoteCommunicationClient::GetProcessArchitecture () -{ - if (m_qProcessInfo_is_valid == eLazyBoolCalculate) - GetCurrentProcessInfo (); - return m_process_arch; +GDBRemoteCommunicationClient::GetProcessArchitecture() { + if (m_qProcessInfo_is_valid == eLazyBoolCalculate) + GetCurrentProcessInfo(); + return m_process_arch; } -bool -GDBRemoteCommunicationClient::GetGDBServerVersion() -{ - if (m_qGDBServerVersion_is_valid == eLazyBoolCalculate) - { - m_gdb_server_name.clear(); - m_gdb_server_version = 0; - m_qGDBServerVersion_is_valid = eLazyBoolNo; - - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse ("qGDBServerVersion", response, false) == PacketResult::Success) - { - if (response.IsNormalResponse()) - { - std::string name; - std::string value; - bool success = false; - while (response.GetNameColonValue(name, value)) - { - if (name.compare("name") == 0) - { - success = true; - m_gdb_server_name.swap(value); - } - else if (name.compare("version") == 0) - { - size_t dot_pos = value.find('.'); - if (dot_pos != std::string::npos) - value[dot_pos] = '\0'; - const uint32_t version = StringConvert::ToUInt32(value.c_str(), UINT32_MAX, 0); - if (version != UINT32_MAX) - { - success = true; - m_gdb_server_version = version; - } - } - } - if (success) - m_qGDBServerVersion_is_valid = eLazyBoolYes; - } - } - } - return m_qGDBServerVersion_is_valid == eLazyBoolYes; -} +bool GDBRemoteCommunicationClient::GetGDBServerVersion() { + if (m_qGDBServerVersion_is_valid == eLazyBoolCalculate) { + m_gdb_server_name.clear(); + m_gdb_server_version = 0; + m_qGDBServerVersion_is_valid = eLazyBoolNo; -void -GDBRemoteCommunicationClient::MaybeEnableCompression (std::vector<std::string> supported_compressions) -{ - CompressionType avail_type = CompressionType::None; - std::string avail_name; - -#if defined (HAVE_LIBCOMPRESSION) - // libcompression is weak linked so test if compression_decode_buffer() is available - if (compression_decode_buffer != NULL && avail_type == CompressionType::None) - { - for (auto compression : supported_compressions) - { - if (compression == "lzfse") - { - avail_type = CompressionType::LZFSE; - avail_name = compression; - break; - } - } - } + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse("qGDBServerVersion", response, false) == + PacketResult::Success) { + if (response.IsNormalResponse()) { + llvm::StringRef name, value; + bool success = false; + while (response.GetNameColonValue(name, value)) { + if (name.equals("name")) { + success = true; + m_gdb_server_name = value; + } else if (name.equals("version")) { + llvm::StringRef major, minor; + std::tie(major, minor) = value.split('.'); + if (!major.getAsInteger(0, m_gdb_server_version)) + success = true; + } + } + if (success) + m_qGDBServerVersion_is_valid = eLazyBoolYes; + } + } + } + return m_qGDBServerVersion_is_valid == eLazyBoolYes; +} + +void GDBRemoteCommunicationClient::MaybeEnableCompression( + std::vector<std::string> supported_compressions) { + CompressionType avail_type = CompressionType::None; + std::string avail_name; + +#if defined(HAVE_LIBCOMPRESSION) + // libcompression is weak linked so test if compression_decode_buffer() is + // available + if (compression_decode_buffer != NULL && + avail_type == CompressionType::None) { + for (auto compression : supported_compressions) { + if (compression == "lzfse") { + avail_type = CompressionType::LZFSE; + avail_name = compression; + break; + } + } + } #endif -#if defined (HAVE_LIBCOMPRESSION) - // libcompression is weak linked so test if compression_decode_buffer() is available - if (compression_decode_buffer != NULL && avail_type == CompressionType::None) - { - for (auto compression : supported_compressions) - { - if (compression == "zlib-deflate") - { - avail_type = CompressionType::ZlibDeflate; - avail_name = compression; - break; - } - } - } +#if defined(HAVE_LIBCOMPRESSION) + // libcompression is weak linked so test if compression_decode_buffer() is + // available + if (compression_decode_buffer != NULL && + avail_type == CompressionType::None) { + for (auto compression : supported_compressions) { + if (compression == "zlib-deflate") { + avail_type = CompressionType::ZlibDeflate; + avail_name = compression; + break; + } + } + } #endif -#if defined (HAVE_LIBZ) - if (avail_type == CompressionType::None) - { - for (auto compression : supported_compressions) - { - if (compression == "zlib-deflate") - { - avail_type = CompressionType::ZlibDeflate; - avail_name = compression; - break; - } - } +#if defined(HAVE_LIBZ) + if (avail_type == CompressionType::None) { + for (auto compression : supported_compressions) { + if (compression == "zlib-deflate") { + avail_type = CompressionType::ZlibDeflate; + avail_name = compression; + break; + } } + } #endif -#if defined (HAVE_LIBCOMPRESSION) - // libcompression is weak linked so test if compression_decode_buffer() is available - if (compression_decode_buffer != NULL && avail_type == CompressionType::None) - { - for (auto compression : supported_compressions) - { - if (compression == "lz4") - { - avail_type = CompressionType::LZ4; - avail_name = compression; - break; - } - } - } +#if defined(HAVE_LIBCOMPRESSION) + // libcompression is weak linked so test if compression_decode_buffer() is + // available + if (compression_decode_buffer != NULL && + avail_type == CompressionType::None) { + for (auto compression : supported_compressions) { + if (compression == "lz4") { + avail_type = CompressionType::LZ4; + avail_name = compression; + break; + } + } + } #endif -#if defined (HAVE_LIBCOMPRESSION) - // libcompression is weak linked so test if compression_decode_buffer() is available - if (compression_decode_buffer != NULL && avail_type == CompressionType::None) - { - for (auto compression : supported_compressions) - { - if (compression == "lzma") - { - avail_type = CompressionType::LZMA; - avail_name = compression; - break; - } - } - } +#if defined(HAVE_LIBCOMPRESSION) + // libcompression is weak linked so test if compression_decode_buffer() is + // available + if (compression_decode_buffer != NULL && + avail_type == CompressionType::None) { + for (auto compression : supported_compressions) { + if (compression == "lzma") { + avail_type = CompressionType::LZMA; + avail_name = compression; + break; + } + } + } #endif - if (avail_type != CompressionType::None) - { - StringExtractorGDBRemote response; - std::string packet = "QEnableCompression:type:" + avail_name + ";"; - if (SendPacketAndWaitForResponse (packet.c_str(), response, false) != PacketResult::Success) - return; - - if (response.IsOKResponse()) - { - m_compression_type = avail_type; - } - } -} + if (avail_type != CompressionType::None) { + StringExtractorGDBRemote response; + std::string packet = "QEnableCompression:type:" + avail_name + ";"; + if (SendPacketAndWaitForResponse(packet, response, false) != + PacketResult::Success) + return; -const char * -GDBRemoteCommunicationClient::GetGDBServerProgramName() -{ - if (GetGDBServerVersion()) - { - if (!m_gdb_server_name.empty()) - return m_gdb_server_name.c_str(); + if (response.IsOKResponse()) { + m_compression_type = avail_type; } - return NULL; + } } -uint32_t -GDBRemoteCommunicationClient::GetGDBServerProgramVersion() -{ - if (GetGDBServerVersion()) - return m_gdb_server_version; - return 0; +const char *GDBRemoteCommunicationClient::GetGDBServerProgramName() { + if (GetGDBServerVersion()) { + if (!m_gdb_server_name.empty()) + return m_gdb_server_name.c_str(); + } + return NULL; } -bool -GDBRemoteCommunicationClient::GetDefaultThreadId (lldb::tid_t &tid) -{ - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("qC",response,false) != PacketResult::Success) - return false; - - if (!response.IsNormalResponse()) - return false; - - if (response.GetChar() == 'Q' && response.GetChar() == 'C') - tid = response.GetHexMaxU32(true, -1); - - return true; +uint32_t GDBRemoteCommunicationClient::GetGDBServerProgramVersion() { + if (GetGDBServerVersion()) + return m_gdb_server_version; + return 0; } -bool -GDBRemoteCommunicationClient::GetHostInfo (bool force) -{ - Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_PROCESS)); - - if (force || m_qHostInfo_is_valid == eLazyBoolCalculate) - { - m_qHostInfo_is_valid = eLazyBoolNo; - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse ("qHostInfo", response, false) == PacketResult::Success) - { - if (response.IsNormalResponse()) - { - std::string name; - std::string value; - uint32_t cpu = LLDB_INVALID_CPUTYPE; - uint32_t sub = 0; - std::string arch_name; - std::string os_name; - std::string vendor_name; - std::string triple; - std::string distribution_id; - uint32_t pointer_byte_size = 0; - StringExtractor extractor; - ByteOrder byte_order = eByteOrderInvalid; - uint32_t num_keys_decoded = 0; - while (response.GetNameColonValue(name, value)) - { - if (name.compare("cputype") == 0) - { - // exception type in big endian hex - cpu = StringConvert::ToUInt32 (value.c_str(), LLDB_INVALID_CPUTYPE, 0); - if (cpu != LLDB_INVALID_CPUTYPE) - ++num_keys_decoded; - } - else if (name.compare("cpusubtype") == 0) - { - // exception count in big endian hex - sub = StringConvert::ToUInt32 (value.c_str(), 0, 0); - if (sub != 0) - ++num_keys_decoded; - } - else if (name.compare("arch") == 0) - { - arch_name.swap (value); - ++num_keys_decoded; - } - else if (name.compare("triple") == 0) - { - extractor.GetStringRef ().swap (value); - extractor.SetFilePos(0); - extractor.GetHexByteString (triple); - ++num_keys_decoded; - } - else if (name.compare ("distribution_id") == 0) - { - extractor.GetStringRef ().swap (value); - extractor.SetFilePos (0); - extractor.GetHexByteString (distribution_id); - ++num_keys_decoded; - } - else if (name.compare("os_build") == 0) - { - extractor.GetStringRef().swap(value); - extractor.SetFilePos(0); - extractor.GetHexByteString (m_os_build); - ++num_keys_decoded; - } - else if (name.compare("hostname") == 0) - { - extractor.GetStringRef().swap(value); - extractor.SetFilePos(0); - extractor.GetHexByteString (m_hostname); - ++num_keys_decoded; - } - else if (name.compare("os_kernel") == 0) - { - extractor.GetStringRef().swap(value); - extractor.SetFilePos(0); - extractor.GetHexByteString (m_os_kernel); - ++num_keys_decoded; - } - else if (name.compare("ostype") == 0) - { - os_name.swap (value); - ++num_keys_decoded; - } - else if (name.compare("vendor") == 0) - { - vendor_name.swap(value); - ++num_keys_decoded; - } - else if (name.compare("endian") == 0) - { - ++num_keys_decoded; - if (value.compare("little") == 0) - byte_order = eByteOrderLittle; - else if (value.compare("big") == 0) - byte_order = eByteOrderBig; - else if (value.compare("pdp") == 0) - byte_order = eByteOrderPDP; - else - --num_keys_decoded; - } - else if (name.compare("ptrsize") == 0) - { - pointer_byte_size = StringConvert::ToUInt32 (value.c_str(), 0, 0); - if (pointer_byte_size != 0) - ++num_keys_decoded; - } - else if ((name.compare("os_version") == 0) || - (name.compare("version") == 0)) // Older debugserver binaries used the "version" key instead of "os_version"... - { - Args::StringToVersion (value.c_str(), - m_os_version_major, - m_os_version_minor, - m_os_version_update); - if (m_os_version_major != UINT32_MAX) - ++num_keys_decoded; - } - else if (name.compare("watchpoint_exceptions_received") == 0) - { - ++num_keys_decoded; - if (strcmp(value.c_str(),"before") == 0) - m_watchpoints_trigger_after_instruction = eLazyBoolNo; - else if (strcmp(value.c_str(),"after") == 0) - m_watchpoints_trigger_after_instruction = eLazyBoolYes; - else - --num_keys_decoded; - } - else if (name.compare("default_packet_timeout") == 0) - { - m_default_packet_timeout = StringConvert::ToUInt32(value.c_str(), 0); - if (m_default_packet_timeout > 0) - { - SetPacketTimeout(m_default_packet_timeout); - ++num_keys_decoded; - } - } +bool GDBRemoteCommunicationClient::GetDefaultThreadId(lldb::tid_t &tid) { + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse("qC", response, false) != + PacketResult::Success) + return false; - } - - if (num_keys_decoded > 0) - m_qHostInfo_is_valid = eLazyBoolYes; - - if (triple.empty()) - { - if (arch_name.empty()) - { - if (cpu != LLDB_INVALID_CPUTYPE) - { - m_host_arch.SetArchitecture (eArchTypeMachO, cpu, sub); - if (pointer_byte_size) - { - assert (pointer_byte_size == m_host_arch.GetAddressByteSize()); - } - if (byte_order != eByteOrderInvalid) - { - assert (byte_order == m_host_arch.GetByteOrder()); - } - - if (!vendor_name.empty()) - m_host_arch.GetTriple().setVendorName (llvm::StringRef (vendor_name)); - if (!os_name.empty()) - m_host_arch.GetTriple().setOSName (llvm::StringRef (os_name)); - - } - } - else - { - std::string triple; - triple += arch_name; - if (!vendor_name.empty() || !os_name.empty()) - { - triple += '-'; - if (vendor_name.empty()) - triple += "unknown"; - else - triple += vendor_name; - triple += '-'; - if (os_name.empty()) - triple += "unknown"; - else - triple += os_name; - } - m_host_arch.SetTriple (triple.c_str()); - - llvm::Triple &host_triple = m_host_arch.GetTriple(); - if (host_triple.getVendor() == llvm::Triple::Apple && host_triple.getOS() == llvm::Triple::Darwin) - { - switch (m_host_arch.GetMachine()) - { - case llvm::Triple::aarch64: - case llvm::Triple::arm: - case llvm::Triple::thumb: - host_triple.setOS(llvm::Triple::IOS); - break; - default: - host_triple.setOS(llvm::Triple::MacOSX); - break; - } - } - if (pointer_byte_size) - { - assert (pointer_byte_size == m_host_arch.GetAddressByteSize()); - } - if (byte_order != eByteOrderInvalid) - { - assert (byte_order == m_host_arch.GetByteOrder()); - } - - } - } - else - { - m_host_arch.SetTriple (triple.c_str()); - if (pointer_byte_size) - { - assert (pointer_byte_size == m_host_arch.GetAddressByteSize()); - } - if (byte_order != eByteOrderInvalid) - { - assert (byte_order == m_host_arch.GetByteOrder()); - } + if (!response.IsNormalResponse()) + return false; - if (log) - log->Printf ("GDBRemoteCommunicationClient::%s parsed host architecture as %s, triple as %s from triple text %s", __FUNCTION__, m_host_arch.GetArchitectureName () ? m_host_arch.GetArchitectureName () : "<null-arch-name>", m_host_arch.GetTriple ().getTriple ().c_str(), triple.c_str ()); - } - if (!distribution_id.empty ()) - m_host_arch.SetDistributionId (distribution_id.c_str ()); - } - } - } - return m_qHostInfo_is_valid == eLazyBoolYes; -} + if (response.GetChar() == 'Q' && response.GetChar() == 'C') + tid = response.GetHexMaxU32(true, -1); -int -GDBRemoteCommunicationClient::SendAttach -( - lldb::pid_t pid, - StringExtractorGDBRemote& response -) -{ - if (pid != LLDB_INVALID_PROCESS_ID) - { - char packet[64]; - const int packet_len = ::snprintf (packet, sizeof(packet), "vAttach;%" PRIx64, pid); - assert (packet_len < (int)sizeof(packet)); - if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) - { - if (response.IsErrorResponse()) - return response.GetError(); - return 0; - } - } - return -1; + return true; } -int -GDBRemoteCommunicationClient::SendStdinNotification (const char* data, size_t data_len) -{ - StreamString packet; - packet.PutCString("I"); - packet.PutBytesAsRawHex8(data, data_len); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) - { - return 0; - } - return response.GetError(); +bool GDBRemoteCommunicationClient::GetHostInfo(bool force) { + Log *log(ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(GDBR_LOG_PROCESS)); + if (force || m_qHostInfo_is_valid == eLazyBoolCalculate) { + m_qHostInfo_is_valid = eLazyBoolNo; + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse("qHostInfo", response, false) == + PacketResult::Success) { + if (response.IsNormalResponse()) { + llvm::StringRef name; + llvm::StringRef value; + uint32_t cpu = LLDB_INVALID_CPUTYPE; + uint32_t sub = 0; + std::string arch_name; + std::string os_name; + std::string vendor_name; + std::string triple; + std::string distribution_id; + uint32_t pointer_byte_size = 0; + ByteOrder byte_order = eByteOrderInvalid; + uint32_t num_keys_decoded = 0; + while (response.GetNameColonValue(name, value)) { + if (name.equals("cputype")) { + // exception type in big endian hex + if (!value.getAsInteger(0, cpu)) + ++num_keys_decoded; + } else if (name.equals("cpusubtype")) { + // exception count in big endian hex + if (!value.getAsInteger(0, sub)) + ++num_keys_decoded; + } else if (name.equals("arch")) { + arch_name = value; + ++num_keys_decoded; + } else if (name.equals("triple")) { + StringExtractor extractor(value); + extractor.GetHexByteString(triple); + ++num_keys_decoded; + } else if (name.equals("distribution_id")) { + StringExtractor extractor(value); + extractor.GetHexByteString(distribution_id); + ++num_keys_decoded; + } else if (name.equals("os_build")) { + StringExtractor extractor(value); + extractor.GetHexByteString(m_os_build); + ++num_keys_decoded; + } else if (name.equals("hostname")) { + StringExtractor extractor(value); + extractor.GetHexByteString(m_hostname); + ++num_keys_decoded; + } else if (name.equals("os_kernel")) { + StringExtractor extractor(value); + extractor.GetHexByteString(m_os_kernel); + ++num_keys_decoded; + } else if (name.equals("ostype")) { + os_name = value; + ++num_keys_decoded; + } else if (name.equals("vendor")) { + vendor_name = value; + ++num_keys_decoded; + } else if (name.equals("endian")) { + byte_order = llvm::StringSwitch<lldb::ByteOrder>(value) + .Case("little", eByteOrderLittle) + .Case("big", eByteOrderBig) + .Case("pdp", eByteOrderPDP) + .Default(eByteOrderInvalid); + if (byte_order != eByteOrderInvalid) + ++num_keys_decoded; + } else if (name.equals("ptrsize")) { + if (!value.getAsInteger(0, pointer_byte_size)) + ++num_keys_decoded; + } else if (name.equals("os_version") || + name.equals( + "version")) // Older debugserver binaries used the + // "version" key instead of + // "os_version"... + { + Args::StringToVersion(value, m_os_version_major, m_os_version_minor, + m_os_version_update); + if (m_os_version_major != UINT32_MAX) + ++num_keys_decoded; + } else if (name.equals("watchpoint_exceptions_received")) { + m_watchpoints_trigger_after_instruction = + llvm::StringSwitch<LazyBool>(value) + .Case("before", eLazyBoolNo) + .Case("after", eLazyBoolYes) + .Default(eLazyBoolCalculate); + if (m_watchpoints_trigger_after_instruction != eLazyBoolCalculate) + ++num_keys_decoded; + } else if (name.equals("default_packet_timeout")) { + uint32_t timeout_seconds; + if (!value.getAsInteger(0, timeout_seconds)) { + m_default_packet_timeout = seconds(timeout_seconds); + SetPacketTimeout(m_default_packet_timeout); + ++num_keys_decoded; + } + } + } + + if (num_keys_decoded > 0) + m_qHostInfo_is_valid = eLazyBoolYes; + + if (triple.empty()) { + if (arch_name.empty()) { + if (cpu != LLDB_INVALID_CPUTYPE) { + m_host_arch.SetArchitecture(eArchTypeMachO, cpu, sub); + if (pointer_byte_size) { + assert(pointer_byte_size == m_host_arch.GetAddressByteSize()); + } + if (byte_order != eByteOrderInvalid) { + assert(byte_order == m_host_arch.GetByteOrder()); + } + + if (!vendor_name.empty()) + m_host_arch.GetTriple().setVendorName( + llvm::StringRef(vendor_name)); + if (!os_name.empty()) + m_host_arch.GetTriple().setOSName(llvm::StringRef(os_name)); + } + } else { + std::string triple; + triple += arch_name; + if (!vendor_name.empty() || !os_name.empty()) { + triple += '-'; + if (vendor_name.empty()) + triple += "unknown"; + else + triple += vendor_name; + triple += '-'; + if (os_name.empty()) + triple += "unknown"; + else + triple += os_name; + } + m_host_arch.SetTriple(triple.c_str()); + + llvm::Triple &host_triple = m_host_arch.GetTriple(); + if (host_triple.getVendor() == llvm::Triple::Apple && + host_triple.getOS() == llvm::Triple::Darwin) { + switch (m_host_arch.GetMachine()) { + case llvm::Triple::aarch64: + case llvm::Triple::arm: + case llvm::Triple::thumb: + host_triple.setOS(llvm::Triple::IOS); + break; + default: + host_triple.setOS(llvm::Triple::MacOSX); + break; + } + } + if (pointer_byte_size) { + assert(pointer_byte_size == m_host_arch.GetAddressByteSize()); + } + if (byte_order != eByteOrderInvalid) { + assert(byte_order == m_host_arch.GetByteOrder()); + } + } + } else { + m_host_arch.SetTriple(triple.c_str()); + if (pointer_byte_size) { + assert(pointer_byte_size == m_host_arch.GetAddressByteSize()); + } + if (byte_order != eByteOrderInvalid) { + assert(byte_order == m_host_arch.GetByteOrder()); + } + + if (log) + log->Printf("GDBRemoteCommunicationClient::%s parsed host " + "architecture as %s, triple as %s from triple text %s", + __FUNCTION__, m_host_arch.GetArchitectureName() + ? m_host_arch.GetArchitectureName() + : "<null-arch-name>", + m_host_arch.GetTriple().getTriple().c_str(), + triple.c_str()); + } + if (!distribution_id.empty()) + m_host_arch.SetDistributionId(distribution_id.c_str()); + } + } + } + return m_qHostInfo_is_valid == eLazyBoolYes; +} + +int GDBRemoteCommunicationClient::SendAttach( + lldb::pid_t pid, StringExtractorGDBRemote &response) { + if (pid != LLDB_INVALID_PROCESS_ID) { + char packet[64]; + const int packet_len = + ::snprintf(packet, sizeof(packet), "vAttach;%" PRIx64, pid); + UNUSED_IF_ASSERT_DISABLED(packet_len); + assert(packet_len < (int)sizeof(packet)); + if (SendPacketAndWaitForResponse(packet, response, false) == + PacketResult::Success) { + if (response.IsErrorResponse()) + return response.GetError(); + return 0; + } + } + return -1; +} + +int GDBRemoteCommunicationClient::SendStdinNotification(const char *data, + size_t data_len) { + StreamString packet; + packet.PutCString("I"); + packet.PutBytesAsRawHex8(data, data_len); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == + PacketResult::Success) { + return 0; + } + return response.GetError(); } const lldb_private::ArchSpec & -GDBRemoteCommunicationClient::GetHostArchitecture () -{ - if (m_qHostInfo_is_valid == eLazyBoolCalculate) - GetHostInfo (); - return m_host_arch; +GDBRemoteCommunicationClient::GetHostArchitecture() { + if (m_qHostInfo_is_valid == eLazyBoolCalculate) + GetHostInfo(); + return m_host_arch; } -uint32_t -GDBRemoteCommunicationClient::GetHostDefaultPacketTimeout () -{ - if (m_qHostInfo_is_valid == eLazyBoolCalculate) - GetHostInfo (); - return m_default_packet_timeout; +seconds GDBRemoteCommunicationClient::GetHostDefaultPacketTimeout() { + if (m_qHostInfo_is_valid == eLazyBoolCalculate) + GetHostInfo(); + return m_default_packet_timeout; } -addr_t -GDBRemoteCommunicationClient::AllocateMemory (size_t size, uint32_t permissions) -{ - if (m_supports_alloc_dealloc_memory != eLazyBoolNo) - { - m_supports_alloc_dealloc_memory = eLazyBoolYes; - char packet[64]; - const int packet_len = ::snprintf (packet, sizeof(packet), "_M%" PRIx64 ",%s%s%s", - (uint64_t)size, - permissions & lldb::ePermissionsReadable ? "r" : "", - permissions & lldb::ePermissionsWritable ? "w" : "", - permissions & lldb::ePermissionsExecutable ? "x" : ""); - assert (packet_len < (int)sizeof(packet)); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) - { - if (response.IsUnsupportedResponse()) - m_supports_alloc_dealloc_memory = eLazyBoolNo; - else if (!response.IsErrorResponse()) - return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS); - } - else - { - m_supports_alloc_dealloc_memory = eLazyBoolNo; - } - } - return LLDB_INVALID_ADDRESS; +addr_t GDBRemoteCommunicationClient::AllocateMemory(size_t size, + uint32_t permissions) { + if (m_supports_alloc_dealloc_memory != eLazyBoolNo) { + m_supports_alloc_dealloc_memory = eLazyBoolYes; + char packet[64]; + const int packet_len = ::snprintf( + packet, sizeof(packet), "_M%" PRIx64 ",%s%s%s", (uint64_t)size, + permissions & lldb::ePermissionsReadable ? "r" : "", + permissions & lldb::ePermissionsWritable ? "w" : "", + permissions & lldb::ePermissionsExecutable ? "x" : ""); + assert(packet_len < (int)sizeof(packet)); + UNUSED_IF_ASSERT_DISABLED(packet_len); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, response, false) == + PacketResult::Success) { + if (response.IsUnsupportedResponse()) + m_supports_alloc_dealloc_memory = eLazyBoolNo; + else if (!response.IsErrorResponse()) + return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS); + } else { + m_supports_alloc_dealloc_memory = eLazyBoolNo; + } + } + return LLDB_INVALID_ADDRESS; +} + +bool GDBRemoteCommunicationClient::DeallocateMemory(addr_t addr) { + if (m_supports_alloc_dealloc_memory != eLazyBoolNo) { + m_supports_alloc_dealloc_memory = eLazyBoolYes; + char packet[64]; + const int packet_len = + ::snprintf(packet, sizeof(packet), "_m%" PRIx64, (uint64_t)addr); + assert(packet_len < (int)sizeof(packet)); + UNUSED_IF_ASSERT_DISABLED(packet_len); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, response, false) == + PacketResult::Success) { + if (response.IsUnsupportedResponse()) + m_supports_alloc_dealloc_memory = eLazyBoolNo; + else if (response.IsOKResponse()) + return true; + } else { + m_supports_alloc_dealloc_memory = eLazyBoolNo; + } + } + return false; +} + +Error GDBRemoteCommunicationClient::Detach(bool keep_stopped) { + Error error; + + if (keep_stopped) { + if (m_supports_detach_stay_stopped == eLazyBoolCalculate) { + char packet[64]; + const int packet_len = + ::snprintf(packet, sizeof(packet), "qSupportsDetachAndStayStopped:"); + assert(packet_len < (int)sizeof(packet)); + UNUSED_IF_ASSERT_DISABLED(packet_len); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, response, false) == + PacketResult::Success && + response.IsOKResponse()) { + m_supports_detach_stay_stopped = eLazyBoolYes; + } else { + m_supports_detach_stay_stopped = eLazyBoolNo; + } + } + + if (m_supports_detach_stay_stopped == eLazyBoolNo) { + error.SetErrorString("Stays stopped not supported by this target."); + return error; + } else { + StringExtractorGDBRemote response; + PacketResult packet_result = + SendPacketAndWaitForResponse("D1", response, false); + if (packet_result != PacketResult::Success) + error.SetErrorString("Sending extended disconnect packet failed."); + } + } else { + StringExtractorGDBRemote response; + PacketResult packet_result = + SendPacketAndWaitForResponse("D", response, false); + if (packet_result != PacketResult::Success) + error.SetErrorString("Sending disconnect packet failed."); + } + return error; } -bool -GDBRemoteCommunicationClient::DeallocateMemory (addr_t addr) -{ - if (m_supports_alloc_dealloc_memory != eLazyBoolNo) - { - m_supports_alloc_dealloc_memory = eLazyBoolYes; - char packet[64]; - const int packet_len = ::snprintf(packet, sizeof(packet), "_m%" PRIx64, (uint64_t)addr); - assert (packet_len < (int)sizeof(packet)); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) - { - if (response.IsUnsupportedResponse()) - m_supports_alloc_dealloc_memory = eLazyBoolNo; - else if (response.IsOKResponse()) - return true; - } - else - { - m_supports_alloc_dealloc_memory = eLazyBoolNo; - } - } - return false; -} +Error GDBRemoteCommunicationClient::GetMemoryRegionInfo( + lldb::addr_t addr, lldb_private::MemoryRegionInfo ®ion_info) { + Error error; + region_info.Clear(); -Error -GDBRemoteCommunicationClient::Detach (bool keep_stopped) -{ - Error error; - - if (keep_stopped) - { - if (m_supports_detach_stay_stopped == eLazyBoolCalculate) - { - char packet[64]; - const int packet_len = ::snprintf(packet, sizeof(packet), "qSupportsDetachAndStayStopped:"); - assert (packet_len < (int)sizeof(packet)); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success - && response.IsOKResponse()) - { - m_supports_detach_stay_stopped = eLazyBoolYes; - } + if (m_supports_memory_region_info != eLazyBoolNo) { + m_supports_memory_region_info = eLazyBoolYes; + char packet[64]; + const int packet_len = ::snprintf( + packet, sizeof(packet), "qMemoryRegionInfo:%" PRIx64, (uint64_t)addr); + assert(packet_len < (int)sizeof(packet)); + UNUSED_IF_ASSERT_DISABLED(packet_len); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, response, false) == + PacketResult::Success) { + llvm::StringRef name; + llvm::StringRef value; + addr_t addr_value = LLDB_INVALID_ADDRESS; + bool success = true; + bool saw_permissions = false; + while (success && response.GetNameColonValue(name, value)) { + if (name.equals("start")) { + if (!value.getAsInteger(16, addr_value)) + region_info.GetRange().SetRangeBase(addr_value); + } else if (name.equals("size")) { + if (!value.getAsInteger(16, addr_value)) + region_info.GetRange().SetByteSize(addr_value); + } else if (name.equals("permissions") && + region_info.GetRange().IsValid()) { + saw_permissions = true; + if (region_info.GetRange().Contains(addr)) { + if (value.find('r') != llvm::StringRef::npos) + region_info.SetReadable(MemoryRegionInfo::eYes); else - { - m_supports_detach_stay_stopped = eLazyBoolNo; - } - } + region_info.SetReadable(MemoryRegionInfo::eNo); - if (m_supports_detach_stay_stopped == eLazyBoolNo) - { - error.SetErrorString("Stays stopped not supported by this target."); - return error; - } - else - { - StringExtractorGDBRemote response; - PacketResult packet_result = SendPacketAndWaitForResponse ("D1", 2, response, false); - if (packet_result != PacketResult::Success) - error.SetErrorString ("Sending extended disconnect packet failed."); - } - } - else - { - StringExtractorGDBRemote response; - PacketResult packet_result = SendPacketAndWaitForResponse ("D", 1, response, false); - if (packet_result != PacketResult::Success) - error.SetErrorString ("Sending disconnect packet failed."); - } - return error; -} + if (value.find('w') != llvm::StringRef::npos) + region_info.SetWritable(MemoryRegionInfo::eYes); + else + region_info.SetWritable(MemoryRegionInfo::eNo); -Error -GDBRemoteCommunicationClient::GetMemoryRegionInfo (lldb::addr_t addr, - lldb_private::MemoryRegionInfo ®ion_info) -{ - Error error; + if (value.find('x') != llvm::StringRef::npos) + region_info.SetExecutable(MemoryRegionInfo::eYes); + else + region_info.SetExecutable(MemoryRegionInfo::eNo); + + region_info.SetMapped(MemoryRegionInfo::eYes); + } else { + // The reported region does not contain this address -- we're + // looking at an unmapped page + region_info.SetReadable(MemoryRegionInfo::eNo); + region_info.SetWritable(MemoryRegionInfo::eNo); + region_info.SetExecutable(MemoryRegionInfo::eNo); + region_info.SetMapped(MemoryRegionInfo::eNo); + } + } else if (name.equals("name")) { + StringExtractorGDBRemote name_extractor(value); + std::string name; + name_extractor.GetHexByteString(name); + region_info.SetName(name.c_str()); + } else if (name.equals("error")) { + StringExtractorGDBRemote error_extractor(value); + std::string error_string; + // Now convert the HEX bytes into a string value + error_extractor.GetHexByteString(error_string); + error.SetErrorString(error_string.c_str()); + } + } + + // We got a valid address range back but no permissions -- which means + // this is an unmapped page + if (region_info.GetRange().IsValid() && saw_permissions == false) { + region_info.SetReadable(MemoryRegionInfo::eNo); + region_info.SetWritable(MemoryRegionInfo::eNo); + region_info.SetExecutable(MemoryRegionInfo::eNo); + region_info.SetMapped(MemoryRegionInfo::eNo); + } + } else { + m_supports_memory_region_info = eLazyBoolNo; + } + } + + if (m_supports_memory_region_info == eLazyBoolNo) { + error.SetErrorString("qMemoryRegionInfo is not supported"); + } + if (error.Fail()) region_info.Clear(); - - if (m_supports_memory_region_info != eLazyBoolNo) - { - m_supports_memory_region_info = eLazyBoolYes; - char packet[64]; - const int packet_len = ::snprintf(packet, sizeof(packet), "qMemoryRegionInfo:%" PRIx64, (uint64_t)addr); - assert (packet_len < (int)sizeof(packet)); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) - { - std::string name; - std::string value; - addr_t addr_value; - bool success = true; - bool saw_permissions = false; - while (success && response.GetNameColonValue(name, value)) - { - if (name.compare ("start") == 0) - { - addr_value = StringConvert::ToUInt64(value.c_str(), LLDB_INVALID_ADDRESS, 16, &success); - if (success) - region_info.GetRange().SetRangeBase(addr_value); - } - else if (name.compare ("size") == 0) - { - addr_value = StringConvert::ToUInt64(value.c_str(), 0, 16, &success); - if (success) - region_info.GetRange().SetByteSize (addr_value); - } - else if (name.compare ("permissions") == 0 && region_info.GetRange().IsValid()) - { - saw_permissions = true; - if (region_info.GetRange().Contains (addr)) - { - if (value.find('r') != std::string::npos) - region_info.SetReadable (MemoryRegionInfo::eYes); - else - region_info.SetReadable (MemoryRegionInfo::eNo); - - if (value.find('w') != std::string::npos) - region_info.SetWritable (MemoryRegionInfo::eYes); - else - region_info.SetWritable (MemoryRegionInfo::eNo); - - if (value.find('x') != std::string::npos) - region_info.SetExecutable (MemoryRegionInfo::eYes); - else - region_info.SetExecutable (MemoryRegionInfo::eNo); - - region_info.SetMapped(MemoryRegionInfo::eYes); - } - else - { - // The reported region does not contain this address -- we're looking at an unmapped page - region_info.SetReadable (MemoryRegionInfo::eNo); - region_info.SetWritable (MemoryRegionInfo::eNo); - region_info.SetExecutable (MemoryRegionInfo::eNo); - region_info.SetMapped(MemoryRegionInfo::eNo); - } - } - else if (name.compare ("error") == 0) - { - StringExtractorGDBRemote name_extractor; - // Swap "value" over into "name_extractor" - name_extractor.GetStringRef().swap(value); - // Now convert the HEX bytes into a string value - name_extractor.GetHexByteString (value); - error.SetErrorString(value.c_str()); - } - } - - // We got a valid address range back but no permissions -- which means this is an unmapped page - if (region_info.GetRange().IsValid() && saw_permissions == false) - { - region_info.SetReadable (MemoryRegionInfo::eNo); - region_info.SetWritable (MemoryRegionInfo::eNo); - region_info.SetExecutable (MemoryRegionInfo::eNo); - region_info.SetMapped(MemoryRegionInfo::eNo); - } - } - else - { - m_supports_memory_region_info = eLazyBoolNo; - } - } - - if (m_supports_memory_region_info == eLazyBoolNo) - { - error.SetErrorString("qMemoryRegionInfo is not supported"); - } - if (error.Fail()) - region_info.Clear(); - return error; - + return error; } -Error -GDBRemoteCommunicationClient::GetWatchpointSupportInfo (uint32_t &num) -{ - Error error; +Error GDBRemoteCommunicationClient::GetWatchpointSupportInfo(uint32_t &num) { + Error error; - if (m_supports_watchpoint_support_info == eLazyBoolYes) - { - num = m_num_supported_hardware_watchpoints; - return error; - } + if (m_supports_watchpoint_support_info == eLazyBoolYes) { + num = m_num_supported_hardware_watchpoints; + return error; + } - // Set num to 0 first. - num = 0; - if (m_supports_watchpoint_support_info != eLazyBoolNo) - { - char packet[64]; - const int packet_len = ::snprintf(packet, sizeof(packet), "qWatchpointSupportInfo:"); - assert (packet_len < (int)sizeof(packet)); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) - { - m_supports_watchpoint_support_info = eLazyBoolYes; - std::string name; - std::string value; - while (response.GetNameColonValue(name, value)) - { - if (name.compare ("num") == 0) - { - num = StringConvert::ToUInt32(value.c_str(), 0, 0); - m_num_supported_hardware_watchpoints = num; - } - } - } - else - { - m_supports_watchpoint_support_info = eLazyBoolNo; + // Set num to 0 first. + num = 0; + if (m_supports_watchpoint_support_info != eLazyBoolNo) { + char packet[64]; + const int packet_len = + ::snprintf(packet, sizeof(packet), "qWatchpointSupportInfo:"); + assert(packet_len < (int)sizeof(packet)); + UNUSED_IF_ASSERT_DISABLED(packet_len); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, response, false) == + PacketResult::Success) { + m_supports_watchpoint_support_info = eLazyBoolYes; + llvm::StringRef name; + llvm::StringRef value; + while (response.GetNameColonValue(name, value)) { + if (name.equals("num")) { + value.getAsInteger(0, m_num_supported_hardware_watchpoints); + num = m_num_supported_hardware_watchpoints; } + } + } else { + m_supports_watchpoint_support_info = eLazyBoolNo; } + } - if (m_supports_watchpoint_support_info == eLazyBoolNo) - { - error.SetErrorString("qWatchpointSupportInfo is not supported"); - } - return error; - + if (m_supports_watchpoint_support_info == eLazyBoolNo) { + error.SetErrorString("qWatchpointSupportInfo is not supported"); + } + return error; } -lldb_private::Error -GDBRemoteCommunicationClient::GetWatchpointSupportInfo (uint32_t &num, bool& after, const ArchSpec &arch) -{ - Error error(GetWatchpointSupportInfo(num)); - if (error.Success()) - error = GetWatchpointsTriggerAfterInstruction(after, arch); - return error; +lldb_private::Error GDBRemoteCommunicationClient::GetWatchpointSupportInfo( + uint32_t &num, bool &after, const ArchSpec &arch) { + Error error(GetWatchpointSupportInfo(num)); + if (error.Success()) + error = GetWatchpointsTriggerAfterInstruction(after, arch); + return error; } lldb_private::Error -GDBRemoteCommunicationClient::GetWatchpointsTriggerAfterInstruction (bool &after, const ArchSpec &arch) -{ - Error error; - llvm::Triple::ArchType atype = arch.GetMachine(); - - // we assume watchpoints will happen after running the relevant opcode - // and we only want to override this behavior if we have explicitly - // received a qHostInfo telling us otherwise - if (m_qHostInfo_is_valid != eLazyBoolYes) - { - // On targets like MIPS, watchpoint exceptions are always generated - // before the instruction is executed. The connected target may not - // support qHostInfo or qWatchpointSupportInfo packets. - if (atype == llvm::Triple::mips || atype == llvm::Triple::mipsel - || atype == llvm::Triple::mips64 || atype == llvm::Triple::mips64el) - after = false; - else - after = true; - } +GDBRemoteCommunicationClient::GetWatchpointsTriggerAfterInstruction( + bool &after, const ArchSpec &arch) { + Error error; + llvm::Triple::ArchType atype = arch.GetMachine(); + + // we assume watchpoints will happen after running the relevant opcode + // and we only want to override this behavior if we have explicitly + // received a qHostInfo telling us otherwise + if (m_qHostInfo_is_valid != eLazyBoolYes) { + // On targets like MIPS, watchpoint exceptions are always generated + // before the instruction is executed. The connected target may not + // support qHostInfo or qWatchpointSupportInfo packets. + if (atype == llvm::Triple::mips || atype == llvm::Triple::mipsel || + atype == llvm::Triple::mips64 || atype == llvm::Triple::mips64el) + after = false; else - { - // For MIPS, set m_watchpoints_trigger_after_instruction to eLazyBoolNo - // if it is not calculated before. - if (m_watchpoints_trigger_after_instruction == eLazyBoolCalculate && - (atype == llvm::Triple::mips || atype == llvm::Triple::mipsel - || atype == llvm::Triple::mips64 || atype == llvm::Triple::mips64el)) - m_watchpoints_trigger_after_instruction = eLazyBoolNo; - - after = (m_watchpoints_trigger_after_instruction != eLazyBoolNo); - } - return error; -} - -int -GDBRemoteCommunicationClient::SetSTDIN(const FileSpec &file_spec) -{ - if (file_spec) - { - std::string path{file_spec.GetPath(false)}; - StreamString packet; - packet.PutCString("QSetSTDIN:"); - packet.PutCStringAsRawHex8(path.c_str()); - - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - return 0; - uint8_t error = response.GetError(); - if (error) - return error; - } - } - return -1; -} + after = true; + } else { + // For MIPS, set m_watchpoints_trigger_after_instruction to eLazyBoolNo + // if it is not calculated before. + if (m_watchpoints_trigger_after_instruction == eLazyBoolCalculate && + (atype == llvm::Triple::mips || atype == llvm::Triple::mipsel || + atype == llvm::Triple::mips64 || atype == llvm::Triple::mips64el)) + m_watchpoints_trigger_after_instruction = eLazyBoolNo; + + after = (m_watchpoints_trigger_after_instruction != eLazyBoolNo); + } + return error; +} + +int GDBRemoteCommunicationClient::SetSTDIN(const FileSpec &file_spec) { + if (file_spec) { + std::string path{file_spec.GetPath(false)}; + StreamString packet; + packet.PutCString("QSetSTDIN:"); + packet.PutCStringAsRawHex8(path.c_str()); -int -GDBRemoteCommunicationClient::SetSTDOUT(const FileSpec &file_spec) -{ - if (file_spec) - { - std::string path{file_spec.GetPath(false)}; - StreamString packet; - packet.PutCString("QSetSTDOUT:"); - packet.PutCStringAsRawHex8(path.c_str()); - - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - return 0; - uint8_t error = response.GetError(); - if (error) - return error; - } + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == + PacketResult::Success) { + if (response.IsOKResponse()) + return 0; + uint8_t error = response.GetError(); + if (error) + return error; } - return -1; + } + return -1; } -int -GDBRemoteCommunicationClient::SetSTDERR(const FileSpec &file_spec) -{ - if (file_spec) - { - std::string path{file_spec.GetPath(false)}; - StreamString packet; - packet.PutCString("QSetSTDERR:"); - packet.PutCStringAsRawHex8(path.c_str()); - - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - return 0; - uint8_t error = response.GetError(); - if (error) - return error; - } - } - return -1; -} +int GDBRemoteCommunicationClient::SetSTDOUT(const FileSpec &file_spec) { + if (file_spec) { + std::string path{file_spec.GetPath(false)}; + StreamString packet; + packet.PutCString("QSetSTDOUT:"); + packet.PutCStringAsRawHex8(path.c_str()); -bool -GDBRemoteCommunicationClient::GetWorkingDir(FileSpec &working_dir) -{ StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse ("qGetWorkingDir", response, false) == PacketResult::Success) - { - if (response.IsUnsupportedResponse()) - return false; - if (response.IsErrorResponse()) - return false; - std::string cwd; - response.GetHexByteString(cwd); - working_dir.SetFile(cwd, false, GetHostArchitecture()); - return !cwd.empty(); + if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == + PacketResult::Success) { + if (response.IsOKResponse()) + return 0; + uint8_t error = response.GetError(); + if (error) + return error; } - return false; + } + return -1; } -int -GDBRemoteCommunicationClient::SetWorkingDir(const FileSpec &working_dir) -{ - if (working_dir) - { - std::string path{working_dir.GetPath(false)}; - StreamString packet; - packet.PutCString("QSetWorkingDir:"); - packet.PutCStringAsRawHex8(path.c_str()); - - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - return 0; - uint8_t error = response.GetError(); - if (error) - return error; - } - } - return -1; -} +int GDBRemoteCommunicationClient::SetSTDERR(const FileSpec &file_spec) { + if (file_spec) { + std::string path{file_spec.GetPath(false)}; + StreamString packet; + packet.PutCString("QSetSTDERR:"); + packet.PutCStringAsRawHex8(path.c_str()); -int -GDBRemoteCommunicationClient::SetDisableASLR (bool enable) -{ - char packet[32]; - const int packet_len = ::snprintf (packet, sizeof (packet), "QSetDisableASLR:%i", enable ? 1 : 0); - assert (packet_len < (int)sizeof(packet)); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - return 0; - uint8_t error = response.GetError(); - if (error) - return error; + if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == + PacketResult::Success) { + if (response.IsOKResponse()) + return 0; + uint8_t error = response.GetError(); + if (error) + return error; } - return -1; -} + } + return -1; +} + +bool GDBRemoteCommunicationClient::GetWorkingDir(FileSpec &working_dir) { + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse("qGetWorkingDir", response, false) == + PacketResult::Success) { + if (response.IsUnsupportedResponse()) + return false; + if (response.IsErrorResponse()) + return false; + std::string cwd; + response.GetHexByteString(cwd); + working_dir.SetFile(cwd, false, GetHostArchitecture()); + return !cwd.empty(); + } + return false; +} + +int GDBRemoteCommunicationClient::SetWorkingDir(const FileSpec &working_dir) { + if (working_dir) { + std::string path{working_dir.GetPath(false)}; + StreamString packet; + packet.PutCString("QSetWorkingDir:"); + packet.PutCStringAsRawHex8(path.c_str()); -int -GDBRemoteCommunicationClient::SetDetachOnError (bool enable) -{ - char packet[32]; - const int packet_len = ::snprintf (packet, sizeof (packet), "QSetDetachOnError:%i", enable ? 1 : 0); - assert (packet_len < (int)sizeof(packet)); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - return 0; - uint8_t error = response.GetError(); - if (error) - return error; + if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == + PacketResult::Success) { + if (response.IsOKResponse()) + return 0; + uint8_t error = response.GetError(); + if (error) + return error; } - return -1; -} - + } + return -1; +} + +int GDBRemoteCommunicationClient::SetDisableASLR(bool enable) { + char packet[32]; + const int packet_len = + ::snprintf(packet, sizeof(packet), "QSetDisableASLR:%i", enable ? 1 : 0); + assert(packet_len < (int)sizeof(packet)); + UNUSED_IF_ASSERT_DISABLED(packet_len); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, response, false) == + PacketResult::Success) { + if (response.IsOKResponse()) + return 0; + uint8_t error = response.GetError(); + if (error) + return error; + } + return -1; +} + +int GDBRemoteCommunicationClient::SetDetachOnError(bool enable) { + char packet[32]; + const int packet_len = ::snprintf(packet, sizeof(packet), + "QSetDetachOnError:%i", enable ? 1 : 0); + assert(packet_len < (int)sizeof(packet)); + UNUSED_IF_ASSERT_DISABLED(packet_len); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, response, false) == + PacketResult::Success) { + if (response.IsOKResponse()) + return 0; + uint8_t error = response.GetError(); + if (error) + return error; + } + return -1; +} + +bool GDBRemoteCommunicationClient::DecodeProcessInfoResponse( + StringExtractorGDBRemote &response, ProcessInstanceInfo &process_info) { + if (response.IsNormalResponse()) { + llvm::StringRef name; + llvm::StringRef value; + StringExtractor extractor; -bool -GDBRemoteCommunicationClient::DecodeProcessInfoResponse (StringExtractorGDBRemote &response, ProcessInstanceInfo &process_info) -{ - if (response.IsNormalResponse()) - { + uint32_t cpu = LLDB_INVALID_CPUTYPE; + uint32_t sub = 0; + std::string vendor; + std::string os_type; + + while (response.GetNameColonValue(name, value)) { + if (name.equals("pid")) { + lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; + value.getAsInteger(0, pid); + process_info.SetProcessID(pid); + } else if (name.equals("ppid")) { + lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; + value.getAsInteger(0, pid); + process_info.SetParentProcessID(pid); + } else if (name.equals("uid")) { + uint32_t uid = UINT32_MAX; + value.getAsInteger(0, uid); + process_info.SetUserID(uid); + } else if (name.equals("euid")) { + uint32_t uid = UINT32_MAX; + value.getAsInteger(0, uid); + process_info.SetEffectiveGroupID(uid); + } else if (name.equals("gid")) { + uint32_t gid = UINT32_MAX; + value.getAsInteger(0, gid); + process_info.SetGroupID(gid); + } else if (name.equals("egid")) { + uint32_t gid = UINT32_MAX; + value.getAsInteger(0, gid); + process_info.SetEffectiveGroupID(gid); + } else if (name.equals("triple")) { + StringExtractor extractor(value); + std::string triple; + extractor.GetHexByteString(triple); + process_info.GetArchitecture().SetTriple(triple.c_str()); + } else if (name.equals("name")) { + StringExtractor extractor(value); + // The process name from ASCII hex bytes since we can't + // control the characters in a process name std::string name; - std::string value; - StringExtractor extractor; - - uint32_t cpu = LLDB_INVALID_CPUTYPE; - uint32_t sub = 0; - std::string vendor; - std::string os_type; - - while (response.GetNameColonValue(name, value)) - { - if (name.compare("pid") == 0) - { - process_info.SetProcessID (StringConvert::ToUInt32 (value.c_str(), LLDB_INVALID_PROCESS_ID, 0)); - } - else if (name.compare("ppid") == 0) - { - process_info.SetParentProcessID (StringConvert::ToUInt32 (value.c_str(), LLDB_INVALID_PROCESS_ID, 0)); - } - else if (name.compare("uid") == 0) - { - process_info.SetUserID (StringConvert::ToUInt32 (value.c_str(), UINT32_MAX, 0)); - } - else if (name.compare("euid") == 0) - { - process_info.SetEffectiveUserID (StringConvert::ToUInt32 (value.c_str(), UINT32_MAX, 0)); - } - else if (name.compare("gid") == 0) - { - process_info.SetGroupID (StringConvert::ToUInt32 (value.c_str(), UINT32_MAX, 0)); - } - else if (name.compare("egid") == 0) - { - process_info.SetEffectiveGroupID (StringConvert::ToUInt32 (value.c_str(), UINT32_MAX, 0)); - } - else if (name.compare("triple") == 0) - { - StringExtractor extractor; - extractor.GetStringRef().swap(value); - extractor.SetFilePos(0); - extractor.GetHexByteString (value); - process_info.GetArchitecture ().SetTriple (value.c_str()); - } - else if (name.compare("name") == 0) - { - StringExtractor extractor; - // The process name from ASCII hex bytes since we can't - // control the characters in a process name - extractor.GetStringRef().swap(value); - extractor.SetFilePos(0); - extractor.GetHexByteString (value); - process_info.GetExecutableFile().SetFile (value.c_str(), false); - } - else if (name.compare("cputype") == 0) - { - cpu = StringConvert::ToUInt32 (value.c_str(), LLDB_INVALID_CPUTYPE, 16); - } - else if (name.compare("cpusubtype") == 0) - { - sub = StringConvert::ToUInt32 (value.c_str(), 0, 16); - } - else if (name.compare("vendor") == 0) - { - vendor = value; - } - else if (name.compare("ostype") == 0) - { - os_type = value; - } - } - - if (cpu != LLDB_INVALID_CPUTYPE && !vendor.empty() && !os_type.empty()) - { - if (vendor == "apple") - { - process_info.GetArchitecture().SetArchitecture (eArchTypeMachO, cpu, sub); - process_info.GetArchitecture().GetTriple().setVendorName (llvm::StringRef (vendor)); - process_info.GetArchitecture().GetTriple().setOSName (llvm::StringRef (os_type)); - } - } - - if (process_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) - return true; - } - return false; -} - -bool -GDBRemoteCommunicationClient::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info) -{ - process_info.Clear(); - - if (m_supports_qProcessInfoPID) - { - char packet[32]; - const int packet_len = ::snprintf (packet, sizeof (packet), "qProcessInfoPID:%" PRIu64, pid); - assert (packet_len < (int)sizeof(packet)); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) - { - return DecodeProcessInfoResponse (response, process_info); - } - else - { - m_supports_qProcessInfoPID = false; - return false; - } - } - return false; -} - -bool -GDBRemoteCommunicationClient::GetCurrentProcessInfo (bool allow_lazy) -{ - Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_PROCESS | GDBR_LOG_PACKETS)); - - if (allow_lazy) - { - if (m_qProcessInfo_is_valid == eLazyBoolYes) - return true; - if (m_qProcessInfo_is_valid == eLazyBoolNo) - return false; - } - - GetHostInfo (); - - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse ("qProcessInfo", response, false) == PacketResult::Success) - { - if (response.IsNormalResponse()) - { - std::string name; - std::string value; - uint32_t cpu = LLDB_INVALID_CPUTYPE; - uint32_t sub = 0; - std::string arch_name; - std::string os_name; - std::string vendor_name; - std::string triple; - std::string elf_abi; - uint32_t pointer_byte_size = 0; - StringExtractor extractor; - ByteOrder byte_order = eByteOrderInvalid; - uint32_t num_keys_decoded = 0; - lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; - while (response.GetNameColonValue(name, value)) - { - if (name.compare("cputype") == 0) - { - cpu = StringConvert::ToUInt32 (value.c_str(), LLDB_INVALID_CPUTYPE, 16); - if (cpu != LLDB_INVALID_CPUTYPE) - ++num_keys_decoded; - } - else if (name.compare("cpusubtype") == 0) - { - sub = StringConvert::ToUInt32 (value.c_str(), 0, 16); - if (sub != 0) - ++num_keys_decoded; - } - else if (name.compare("triple") == 0) - { - StringExtractor extractor; - extractor.GetStringRef().swap(value); - extractor.SetFilePos(0); - extractor.GetHexByteString (triple); - ++num_keys_decoded; - } - else if (name.compare("ostype") == 0) - { - os_name.swap (value); - ++num_keys_decoded; - } - else if (name.compare("vendor") == 0) - { - vendor_name.swap(value); - ++num_keys_decoded; - } - else if (name.compare("endian") == 0) - { - ++num_keys_decoded; - if (value.compare("little") == 0) - byte_order = eByteOrderLittle; - else if (value.compare("big") == 0) - byte_order = eByteOrderBig; - else if (value.compare("pdp") == 0) - byte_order = eByteOrderPDP; - else - --num_keys_decoded; - } - else if (name.compare("ptrsize") == 0) - { - pointer_byte_size = StringConvert::ToUInt32 (value.c_str(), 0, 16); - if (pointer_byte_size != 0) - ++num_keys_decoded; - } - else if (name.compare("pid") == 0) - { - pid = StringConvert::ToUInt64(value.c_str(), 0, 16); - if (pid != LLDB_INVALID_PROCESS_ID) - ++num_keys_decoded; - } - else if (name.compare("elf_abi") == 0) - { - elf_abi = value; - ++num_keys_decoded; - } - } - if (num_keys_decoded > 0) - m_qProcessInfo_is_valid = eLazyBoolYes; - if (pid != LLDB_INVALID_PROCESS_ID) - { - m_curr_pid_is_valid = eLazyBoolYes; - m_curr_pid = pid; - } - - // Set the ArchSpec from the triple if we have it. - if (!triple.empty ()) - { - m_process_arch.SetTriple (triple.c_str ()); - m_process_arch.SetFlags(elf_abi); - if (pointer_byte_size) - { - assert (pointer_byte_size == m_process_arch.GetAddressByteSize()); - } - } - else if (cpu != LLDB_INVALID_CPUTYPE && !os_name.empty() && !vendor_name.empty()) - { - llvm::Triple triple(llvm::Twine("-") + vendor_name + "-" + os_name); - - assert(triple.getObjectFormat() != llvm::Triple::UnknownObjectFormat); - switch (triple.getObjectFormat()) { - case llvm::Triple::MachO: - m_process_arch.SetArchitecture (eArchTypeMachO, cpu, sub); - break; - case llvm::Triple::ELF: - m_process_arch.SetArchitecture (eArchTypeELF, cpu, sub); - break; - case llvm::Triple::COFF: - m_process_arch.SetArchitecture (eArchTypeCOFF, cpu, sub); - break; - case llvm::Triple::UnknownObjectFormat: - if (log) - log->Printf("error: failed to determine target architecture"); - return false; - } - - if (pointer_byte_size) - { - assert (pointer_byte_size == m_process_arch.GetAddressByteSize()); - } - if (byte_order != eByteOrderInvalid) - { - assert (byte_order == m_process_arch.GetByteOrder()); - } - m_process_arch.GetTriple().setVendorName (llvm::StringRef (vendor_name)); - m_process_arch.GetTriple().setOSName(llvm::StringRef (os_name)); - m_host_arch.GetTriple().setVendorName (llvm::StringRef (vendor_name)); - m_host_arch.GetTriple().setOSName (llvm::StringRef (os_name)); - } - return true; - } - } - else - { - m_qProcessInfo_is_valid = eLazyBoolNo; - } - - return false; -} - - -uint32_t -GDBRemoteCommunicationClient::FindProcesses (const ProcessInstanceInfoMatch &match_info, - ProcessInstanceInfoList &process_infos) -{ - process_infos.Clear(); - - if (m_supports_qfProcessInfo) - { - StreamString packet; - packet.PutCString ("qfProcessInfo"); - if (!match_info.MatchAllProcesses()) - { - packet.PutChar (':'); - const char *name = match_info.GetProcessInfo().GetName(); - bool has_name_match = false; - if (name && name[0]) - { - has_name_match = true; - NameMatchType name_match_type = match_info.GetNameMatchType(); - switch (name_match_type) - { - case eNameMatchIgnore: - has_name_match = false; - break; - - case eNameMatchEquals: - packet.PutCString ("name_match:equals;"); - break; - - case eNameMatchContains: - packet.PutCString ("name_match:contains;"); - break; - - case eNameMatchStartsWith: - packet.PutCString ("name_match:starts_with;"); - break; - - case eNameMatchEndsWith: - packet.PutCString ("name_match:ends_with;"); - break; - - case eNameMatchRegularExpression: - packet.PutCString ("name_match:regex;"); - break; - } - if (has_name_match) - { - packet.PutCString ("name:"); - packet.PutBytesAsRawHex8(name, ::strlen(name)); - packet.PutChar (';'); - } - } - - if (match_info.GetProcessInfo().ProcessIDIsValid()) - packet.Printf("pid:%" PRIu64 ";",match_info.GetProcessInfo().GetProcessID()); - if (match_info.GetProcessInfo().ParentProcessIDIsValid()) - packet.Printf("parent_pid:%" PRIu64 ";",match_info.GetProcessInfo().GetParentProcessID()); - if (match_info.GetProcessInfo().UserIDIsValid()) - packet.Printf("uid:%u;",match_info.GetProcessInfo().GetUserID()); - if (match_info.GetProcessInfo().GroupIDIsValid()) - packet.Printf("gid:%u;",match_info.GetProcessInfo().GetGroupID()); - if (match_info.GetProcessInfo().EffectiveUserIDIsValid()) - packet.Printf("euid:%u;",match_info.GetProcessInfo().GetEffectiveUserID()); - if (match_info.GetProcessInfo().EffectiveGroupIDIsValid()) - packet.Printf("egid:%u;",match_info.GetProcessInfo().GetEffectiveGroupID()); - if (match_info.GetProcessInfo().EffectiveGroupIDIsValid()) - packet.Printf("all_users:%u;",match_info.GetMatchAllUsers() ? 1 : 0); - if (match_info.GetProcessInfo().GetArchitecture().IsValid()) - { - const ArchSpec &match_arch = match_info.GetProcessInfo().GetArchitecture(); - const llvm::Triple &triple = match_arch.GetTriple(); - packet.PutCString("triple:"); - packet.PutCString(triple.getTriple().c_str()); - packet.PutChar (';'); - } - } - StringExtractorGDBRemote response; - // Increase timeout as the first qfProcessInfo packet takes a long time - // on Android. The value of 1min was arrived at empirically. - GDBRemoteCommunication::ScopedTimeout timeout (*this, 60); - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) - { - do - { - ProcessInstanceInfo process_info; - if (!DecodeProcessInfoResponse (response, process_info)) - break; - process_infos.Append(process_info); - response.GetStringRef().clear(); - response.SetFilePos(0); - } while (SendPacketAndWaitForResponse ("qsProcessInfo", strlen ("qsProcessInfo"), response, false) == PacketResult::Success); - } - else - { - m_supports_qfProcessInfo = false; - return 0; - } - } - return process_infos.GetSize(); - -} - -bool -GDBRemoteCommunicationClient::GetUserName (uint32_t uid, std::string &name) -{ - if (m_supports_qUserName) - { - char packet[32]; - const int packet_len = ::snprintf (packet, sizeof (packet), "qUserName:%i", uid); - assert (packet_len < (int)sizeof(packet)); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) - { - if (response.IsNormalResponse()) - { - // Make sure we parsed the right number of characters. The response is - // the hex encoded user name and should make up the entire packet. - // If there are any non-hex ASCII bytes, the length won't match below.. - if (response.GetHexByteString (name) * 2 == response.GetStringRef().size()) - return true; - } - } - else - { - m_supports_qUserName = false; - return false; - } - } - return false; - -} - -bool -GDBRemoteCommunicationClient::GetGroupName (uint32_t gid, std::string &name) -{ - if (m_supports_qGroupName) - { - char packet[32]; - const int packet_len = ::snprintf (packet, sizeof (packet), "qGroupName:%i", gid); - assert (packet_len < (int)sizeof(packet)); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) - { - if (response.IsNormalResponse()) - { - // Make sure we parsed the right number of characters. The response is - // the hex encoded group name and should make up the entire packet. - // If there are any non-hex ASCII bytes, the length won't match below.. - if (response.GetHexByteString (name) * 2 == response.GetStringRef().size()) - return true; - } - } - else - { - m_supports_qGroupName = false; - return false; - } - } - return false; -} - -bool -GDBRemoteCommunicationClient::SetNonStopMode (const bool enable) -{ - // Form non-stop packet request + extractor.GetHexByteString(name); + process_info.GetExecutableFile().SetFile(name, false); + } else if (name.equals("cputype")) { + value.getAsInteger(0, cpu); + } else if (name.equals("cpusubtype")) { + value.getAsInteger(0, sub); + } else if (name.equals("vendor")) { + vendor = value; + } else if (name.equals("ostype")) { + os_type = value; + } + } + + if (cpu != LLDB_INVALID_CPUTYPE && !vendor.empty() && !os_type.empty()) { + if (vendor == "apple") { + process_info.GetArchitecture().SetArchitecture(eArchTypeMachO, cpu, + sub); + process_info.GetArchitecture().GetTriple().setVendorName( + llvm::StringRef(vendor)); + process_info.GetArchitecture().GetTriple().setOSName( + llvm::StringRef(os_type)); + } + } + + if (process_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) + return true; + } + return false; +} + +bool GDBRemoteCommunicationClient::GetProcessInfo( + lldb::pid_t pid, ProcessInstanceInfo &process_info) { + process_info.Clear(); + + if (m_supports_qProcessInfoPID) { char packet[32]; - const int packet_len = ::snprintf(packet, sizeof(packet), "QNonStop:%1d", (int)enable); + const int packet_len = + ::snprintf(packet, sizeof(packet), "qProcessInfoPID:%" PRIu64, pid); assert(packet_len < (int)sizeof(packet)); - + UNUSED_IF_ASSERT_DISABLED(packet_len); StringExtractorGDBRemote response; - // Send to target - if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) - if (response.IsOKResponse()) - return true; - - // Failed or not supported - return false; - -} - -static void -MakeSpeedTestPacket(StreamString &packet, uint32_t send_size, uint32_t recv_size) -{ - packet.Clear(); - packet.Printf ("qSpeedTest:response_size:%i;data:", recv_size); - uint32_t bytes_left = send_size; - while (bytes_left > 0) - { - if (bytes_left >= 26) - { - packet.PutCString("abcdefghijklmnopqrstuvwxyz"); - bytes_left -= 26; - } - else - { - packet.Printf ("%*.*s;", bytes_left, bytes_left, "abcdefghijklmnopqrstuvwxyz"); - bytes_left = 0; - } - } -} - -template<typename T> -T calculate_standard_deviation(const std::vector<T> &v) -{ - T sum = std::accumulate(std::begin(v), std::end(v), T(0)); - T mean = sum / (T)v.size(); - T accum = T(0); - std::for_each (std::begin(v), std::end(v), [&](const T d) { - T delta = d - mean; - accum += delta * delta; - }); - - T stdev = sqrt(accum / (v.size()-1)); - return stdev; -} - -void -GDBRemoteCommunicationClient::TestPacketSpeed (const uint32_t num_packets, uint32_t max_send, uint32_t max_recv, bool json, Stream &strm) -{ - uint32_t i; - TimeValue start_time, end_time; - uint64_t total_time_nsec; - if (SendSpeedTestPacket (0, 0)) - { - StreamString packet; - if (json) - strm.Printf("{ \"packet_speeds\" : {\n \"num_packets\" : %u,\n \"results\" : [", num_packets); - else - strm.Printf("Testing sending %u packets of various sizes:\n", num_packets); - strm.Flush(); - - uint32_t result_idx = 0; - uint32_t send_size; - std::vector<float> packet_times; - - for (send_size = 0; send_size <= max_send; send_size ? send_size *= 2 : send_size = 4) - { - for (uint32_t recv_size = 0; recv_size <= max_recv; recv_size ? recv_size *= 2 : recv_size = 4) - { - MakeSpeedTestPacket (packet, send_size, recv_size); - - packet_times.clear(); - // Test how long it takes to send 'num_packets' packets - start_time = TimeValue::Now(); - for (i=0; i<num_packets; ++i) - { - TimeValue packet_start_time = TimeValue::Now(); - StringExtractorGDBRemote response; - SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false); - TimeValue packet_end_time = TimeValue::Now(); - uint64_t packet_time_nsec = packet_end_time.GetAsNanoSecondsSinceJan1_1970() - packet_start_time.GetAsNanoSecondsSinceJan1_1970(); - packet_times.push_back((float)packet_time_nsec); - } - end_time = TimeValue::Now(); - total_time_nsec = end_time.GetAsNanoSecondsSinceJan1_1970() - start_time.GetAsNanoSecondsSinceJan1_1970(); - - float packets_per_second = (((float)num_packets)/(float)total_time_nsec) * (float)TimeValue::NanoSecPerSec; - float total_ms = (float)total_time_nsec/(float)TimeValue::NanoSecPerMilliSec; - float average_ms_per_packet = total_ms / num_packets; - const float standard_deviation = calculate_standard_deviation<float>(packet_times); - if (json) - { - strm.Printf ("%s\n {\"send_size\" : %6" PRIu32 ", \"recv_size\" : %6" PRIu32 ", \"total_time_nsec\" : %12" PRIu64 ", \"standard_deviation_nsec\" : %9" PRIu64 " }", result_idx > 0 ? "," : "", send_size, recv_size, total_time_nsec, (uint64_t)standard_deviation); - ++result_idx; - } - else - { - strm.Printf ("qSpeedTest(send=%-7u, recv=%-7u) in %" PRIu64 ".%9.9" PRIu64 " sec for %9.2f packets/sec (%10.6f ms per packet) with standard deviation of %10.6f ms\n", - send_size, - recv_size, - total_time_nsec / TimeValue::NanoSecPerSec, - total_time_nsec % TimeValue::NanoSecPerSec, - packets_per_second, - average_ms_per_packet, - standard_deviation/(float)TimeValue::NanoSecPerMilliSec); - } - strm.Flush(); - } - } - - const uint64_t k_recv_amount = 4*1024*1024; // Receive amount in bytes - - const float k_recv_amount_mb = (float)k_recv_amount/(1024.0f*1024.0f); - if (json) - strm.Printf("\n ]\n },\n \"download_speed\" : {\n \"byte_size\" : %" PRIu64 ",\n \"results\" : [", k_recv_amount); - else - strm.Printf("Testing receiving %2.1fMB of data using varying receive packet sizes:\n", k_recv_amount_mb); - strm.Flush(); - send_size = 0; - result_idx = 0; - for (uint32_t recv_size = 32; recv_size <= max_recv; recv_size *= 2) - { - MakeSpeedTestPacket (packet, send_size, recv_size); - - // If we have a receive size, test how long it takes to receive 4MB of data - if (recv_size > 0) - { - start_time = TimeValue::Now(); - uint32_t bytes_read = 0; - uint32_t packet_count = 0; - while (bytes_read < k_recv_amount) - { - StringExtractorGDBRemote response; - SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false); - bytes_read += recv_size; - ++packet_count; - } - end_time = TimeValue::Now(); - total_time_nsec = end_time.GetAsNanoSecondsSinceJan1_1970() - start_time.GetAsNanoSecondsSinceJan1_1970(); - float mb_second = ((((float)k_recv_amount)/(float)total_time_nsec) * (float)TimeValue::NanoSecPerSec) / (1024.0*1024.0); - float packets_per_second = (((float)packet_count)/(float)total_time_nsec) * (float)TimeValue::NanoSecPerSec; - float total_ms = (float)total_time_nsec/(float)TimeValue::NanoSecPerMilliSec; - float average_ms_per_packet = total_ms / packet_count; - - if (json) - { - strm.Printf ("%s\n {\"send_size\" : %6" PRIu32 ", \"recv_size\" : %6" PRIu32 ", \"total_time_nsec\" : %12" PRIu64 " }", result_idx > 0 ? "," : "", send_size, recv_size, total_time_nsec); - ++result_idx; - } - else - { - strm.Printf ("qSpeedTest(send=%-7u, recv=%-7u) %6u packets needed to receive %2.1fMB in %" PRIu64 ".%9.9" PRIu64 " sec for %f MB/sec for %9.2f packets/sec (%10.6f ms per packet)\n", - send_size, - recv_size, - packet_count, - k_recv_amount_mb, - total_time_nsec / TimeValue::NanoSecPerSec, - total_time_nsec % TimeValue::NanoSecPerSec, - mb_second, - packets_per_second, - average_ms_per_packet); - } - strm.Flush(); - } - } - if (json) - strm.Printf("\n ]\n }\n}\n"); - else - strm.EOL(); - } -} - -bool -GDBRemoteCommunicationClient::SendSpeedTestPacket (uint32_t send_size, uint32_t recv_size) -{ + if (SendPacketAndWaitForResponse(packet, response, false) == + PacketResult::Success) { + return DecodeProcessInfoResponse(response, process_info); + } else { + m_supports_qProcessInfoPID = false; + return false; + } + } + return false; +} + +bool GDBRemoteCommunicationClient::GetCurrentProcessInfo(bool allow_lazy) { + Log *log(ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(GDBR_LOG_PROCESS | + GDBR_LOG_PACKETS)); + + if (allow_lazy) { + if (m_qProcessInfo_is_valid == eLazyBoolYes) + return true; + if (m_qProcessInfo_is_valid == eLazyBoolNo) + return false; + } + + GetHostInfo(); + + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse("qProcessInfo", response, false) == + PacketResult::Success) { + if (response.IsNormalResponse()) { + llvm::StringRef name; + llvm::StringRef value; + uint32_t cpu = LLDB_INVALID_CPUTYPE; + uint32_t sub = 0; + std::string arch_name; + std::string os_name; + std::string vendor_name; + std::string triple; + std::string elf_abi; + uint32_t pointer_byte_size = 0; + StringExtractor extractor; + ByteOrder byte_order = eByteOrderInvalid; + uint32_t num_keys_decoded = 0; + lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; + while (response.GetNameColonValue(name, value)) { + if (name.equals("cputype")) { + if (!value.getAsInteger(16, cpu)) + ++num_keys_decoded; + } else if (name.equals("cpusubtype")) { + if (!value.getAsInteger(16, sub)) + ++num_keys_decoded; + } else if (name.equals("triple")) { + StringExtractor extractor(value); + extractor.GetHexByteString(triple); + ++num_keys_decoded; + } else if (name.equals("ostype")) { + os_name = value; + ++num_keys_decoded; + } else if (name.equals("vendor")) { + vendor_name = value; + ++num_keys_decoded; + } else if (name.equals("endian")) { + byte_order = llvm::StringSwitch<lldb::ByteOrder>(value) + .Case("little", eByteOrderLittle) + .Case("big", eByteOrderBig) + .Case("pdp", eByteOrderPDP) + .Default(eByteOrderInvalid); + if (byte_order != eByteOrderInvalid) + ++num_keys_decoded; + } else if (name.equals("ptrsize")) { + if (!value.getAsInteger(16, pointer_byte_size)) + ++num_keys_decoded; + } else if (name.equals("pid")) { + if (!value.getAsInteger(16, pid)) + ++num_keys_decoded; + } else if (name.equals("elf_abi")) { + elf_abi = value; + ++num_keys_decoded; + } + } + if (num_keys_decoded > 0) + m_qProcessInfo_is_valid = eLazyBoolYes; + if (pid != LLDB_INVALID_PROCESS_ID) { + m_curr_pid_is_valid = eLazyBoolYes; + m_curr_pid = pid; + } + + // Set the ArchSpec from the triple if we have it. + if (!triple.empty()) { + m_process_arch.SetTriple(triple.c_str()); + m_process_arch.SetFlags(elf_abi); + if (pointer_byte_size) { + assert(pointer_byte_size == m_process_arch.GetAddressByteSize()); + } + } else if (cpu != LLDB_INVALID_CPUTYPE && !os_name.empty() && + !vendor_name.empty()) { + llvm::Triple triple(llvm::Twine("-") + vendor_name + "-" + os_name); + + assert(triple.getObjectFormat() != llvm::Triple::UnknownObjectFormat); + switch (triple.getObjectFormat()) { + case llvm::Triple::MachO: + m_process_arch.SetArchitecture(eArchTypeMachO, cpu, sub); + break; + case llvm::Triple::ELF: + m_process_arch.SetArchitecture(eArchTypeELF, cpu, sub); + break; + case llvm::Triple::COFF: + m_process_arch.SetArchitecture(eArchTypeCOFF, cpu, sub); + break; + case llvm::Triple::UnknownObjectFormat: + if (log) + log->Printf("error: failed to determine target architecture"); + return false; + } + + if (pointer_byte_size) { + assert(pointer_byte_size == m_process_arch.GetAddressByteSize()); + } + if (byte_order != eByteOrderInvalid) { + assert(byte_order == m_process_arch.GetByteOrder()); + } + m_process_arch.GetTriple().setVendorName(llvm::StringRef(vendor_name)); + m_process_arch.GetTriple().setOSName(llvm::StringRef(os_name)); + m_host_arch.GetTriple().setVendorName(llvm::StringRef(vendor_name)); + m_host_arch.GetTriple().setOSName(llvm::StringRef(os_name)); + } + return true; + } + } else { + m_qProcessInfo_is_valid = eLazyBoolNo; + } + + return false; +} + +uint32_t GDBRemoteCommunicationClient::FindProcesses( + const ProcessInstanceInfoMatch &match_info, + ProcessInstanceInfoList &process_infos) { + process_infos.Clear(); + + if (m_supports_qfProcessInfo) { StreamString packet; - packet.Printf ("qSpeedTest:response_size:%i;data:", recv_size); - uint32_t bytes_left = send_size; - while (bytes_left > 0) - { - if (bytes_left >= 26) - { - packet.PutCString("abcdefghijklmnopqrstuvwxyz"); - bytes_left -= 26; - } - else - { - packet.Printf ("%*.*s;", bytes_left, bytes_left, "abcdefghijklmnopqrstuvwxyz"); - bytes_left = 0; - } + packet.PutCString("qfProcessInfo"); + if (!match_info.MatchAllProcesses()) { + packet.PutChar(':'); + const char *name = match_info.GetProcessInfo().GetName(); + bool has_name_match = false; + if (name && name[0]) { + has_name_match = true; + NameMatchType name_match_type = match_info.GetNameMatchType(); + switch (name_match_type) { + case eNameMatchIgnore: + has_name_match = false; + break; + + case eNameMatchEquals: + packet.PutCString("name_match:equals;"); + break; + + case eNameMatchContains: + packet.PutCString("name_match:contains;"); + break; + + case eNameMatchStartsWith: + packet.PutCString("name_match:starts_with;"); + break; + + case eNameMatchEndsWith: + packet.PutCString("name_match:ends_with;"); + break; + + case eNameMatchRegularExpression: + packet.PutCString("name_match:regex;"); + break; + } + if (has_name_match) { + packet.PutCString("name:"); + packet.PutBytesAsRawHex8(name, ::strlen(name)); + packet.PutChar(';'); + } + } + + if (match_info.GetProcessInfo().ProcessIDIsValid()) + packet.Printf("pid:%" PRIu64 ";", + match_info.GetProcessInfo().GetProcessID()); + if (match_info.GetProcessInfo().ParentProcessIDIsValid()) + packet.Printf("parent_pid:%" PRIu64 ";", + match_info.GetProcessInfo().GetParentProcessID()); + if (match_info.GetProcessInfo().UserIDIsValid()) + packet.Printf("uid:%u;", match_info.GetProcessInfo().GetUserID()); + if (match_info.GetProcessInfo().GroupIDIsValid()) + packet.Printf("gid:%u;", match_info.GetProcessInfo().GetGroupID()); + if (match_info.GetProcessInfo().EffectiveUserIDIsValid()) + packet.Printf("euid:%u;", + match_info.GetProcessInfo().GetEffectiveUserID()); + if (match_info.GetProcessInfo().EffectiveGroupIDIsValid()) + packet.Printf("egid:%u;", + match_info.GetProcessInfo().GetEffectiveGroupID()); + if (match_info.GetProcessInfo().EffectiveGroupIDIsValid()) + packet.Printf("all_users:%u;", match_info.GetMatchAllUsers() ? 1 : 0); + if (match_info.GetProcessInfo().GetArchitecture().IsValid()) { + const ArchSpec &match_arch = + match_info.GetProcessInfo().GetArchitecture(); + const llvm::Triple &triple = match_arch.GetTriple(); + packet.PutCString("triple:"); + packet.PutCString(triple.getTriple()); + packet.PutChar(';'); + } } - StringExtractorGDBRemote response; - return SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success; -} - -bool -GDBRemoteCommunicationClient::LaunchGDBServer (const char *remote_accept_hostname, - lldb::pid_t &pid, - uint16_t &port, - std::string &socket_name) -{ - pid = LLDB_INVALID_PROCESS_ID; - port = 0; - socket_name.clear(); - + // Increase timeout as the first qfProcessInfo packet takes a long time + // on Android. The value of 1min was arrived at empirically. + ScopedTimeout timeout(*this, minutes(1)); + if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == + PacketResult::Success) { + do { + ProcessInstanceInfo process_info; + if (!DecodeProcessInfoResponse(response, process_info)) + break; + process_infos.Append(process_info); + response.GetStringRef().clear(); + response.SetFilePos(0); + } while (SendPacketAndWaitForResponse("qsProcessInfo", response, false) == + PacketResult::Success); + } else { + m_supports_qfProcessInfo = false; + return 0; + } + } + return process_infos.GetSize(); +} + +bool GDBRemoteCommunicationClient::GetUserName(uint32_t uid, + std::string &name) { + if (m_supports_qUserName) { + char packet[32]; + const int packet_len = + ::snprintf(packet, sizeof(packet), "qUserName:%i", uid); + assert(packet_len < (int)sizeof(packet)); + UNUSED_IF_ASSERT_DISABLED(packet_len); StringExtractorGDBRemote response; - StreamString stream; - stream.PutCString("qLaunchGDBServer;"); - std::string hostname; - if (remote_accept_hostname && remote_accept_hostname[0]) - hostname = remote_accept_hostname; + if (SendPacketAndWaitForResponse(packet, response, false) == + PacketResult::Success) { + if (response.IsNormalResponse()) { + // Make sure we parsed the right number of characters. The response is + // the hex encoded user name and should make up the entire packet. + // If there are any non-hex ASCII bytes, the length won't match below.. + if (response.GetHexByteString(name) * 2 == + response.GetStringRef().size()) + return true; + } + } else { + m_supports_qUserName = false; + return false; + } + } + return false; +} + +bool GDBRemoteCommunicationClient::GetGroupName(uint32_t gid, + std::string &name) { + if (m_supports_qGroupName) { + char packet[32]; + const int packet_len = + ::snprintf(packet, sizeof(packet), "qGroupName:%i", gid); + assert(packet_len < (int)sizeof(packet)); + UNUSED_IF_ASSERT_DISABLED(packet_len); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, response, false) == + PacketResult::Success) { + if (response.IsNormalResponse()) { + // Make sure we parsed the right number of characters. The response is + // the hex encoded group name and should make up the entire packet. + // If there are any non-hex ASCII bytes, the length won't match below.. + if (response.GetHexByteString(name) * 2 == + response.GetStringRef().size()) + return true; + } + } else { + m_supports_qGroupName = false; + return false; + } + } + return false; +} + +bool GDBRemoteCommunicationClient::SetNonStopMode(const bool enable) { + // Form non-stop packet request + char packet[32]; + const int packet_len = + ::snprintf(packet, sizeof(packet), "QNonStop:%1d", (int)enable); + assert(packet_len < (int)sizeof(packet)); + UNUSED_IF_ASSERT_DISABLED(packet_len); + + StringExtractorGDBRemote response; + // Send to target + if (SendPacketAndWaitForResponse(packet, response, false) == + PacketResult::Success) + if (response.IsOKResponse()) + return true; + + // Failed or not supported + return false; +} + +static void MakeSpeedTestPacket(StreamString &packet, uint32_t send_size, + uint32_t recv_size) { + packet.Clear(); + packet.Printf("qSpeedTest:response_size:%i;data:", recv_size); + uint32_t bytes_left = send_size; + while (bytes_left > 0) { + if (bytes_left >= 26) { + packet.PutCString("abcdefghijklmnopqrstuvwxyz"); + bytes_left -= 26; + } else { + packet.Printf("%*.*s;", bytes_left, bytes_left, + "abcdefghijklmnopqrstuvwxyz"); + bytes_left = 0; + } + } +} + +duration<float> +calculate_standard_deviation(const std::vector<duration<float>> &v) { + using Dur = duration<float>; + Dur sum = std::accumulate(std::begin(v), std::end(v), Dur()); + Dur mean = sum / v.size(); + float accum = 0; + for (auto d : v) { + float delta = (d - mean).count(); + accum += delta * delta; + }; + + return Dur(sqrtf(accum / (v.size() - 1))); +} + +void GDBRemoteCommunicationClient::TestPacketSpeed(const uint32_t num_packets, + uint32_t max_send, + uint32_t max_recv, + uint64_t recv_amount, + bool json, Stream &strm) { + uint32_t i; + if (SendSpeedTestPacket(0, 0)) { + StreamString packet; + if (json) + strm.Printf("{ \"packet_speeds\" : {\n \"num_packets\" : %u,\n " + "\"results\" : [", + num_packets); else - { - if (HostInfo::GetHostname(hostname)) - { - // Make the GDB server we launch only accept connections from this host - stream.Printf("host:%s;", hostname.c_str()); - } - else - { - // Make the GDB server we launch accept connections from any host since we can't figure out the hostname - stream.Printf("host:*;"); + strm.Printf("Testing sending %u packets of various sizes:\n", + num_packets); + strm.Flush(); + + uint32_t result_idx = 0; + uint32_t send_size; + std::vector<duration<float>> packet_times; + + for (send_size = 0; send_size <= max_send; + send_size ? send_size *= 2 : send_size = 4) { + for (uint32_t recv_size = 0; recv_size <= max_recv; + recv_size ? recv_size *= 2 : recv_size = 4) { + MakeSpeedTestPacket(packet, send_size, recv_size); + + packet_times.clear(); + // Test how long it takes to send 'num_packets' packets + const auto start_time = steady_clock::now(); + for (i = 0; i < num_packets; ++i) { + const auto packet_start_time = steady_clock::now(); + StringExtractorGDBRemote response; + SendPacketAndWaitForResponse(packet.GetString(), response, false); + const auto packet_end_time = steady_clock::now(); + packet_times.push_back(packet_end_time - packet_start_time); + } + const auto end_time = steady_clock::now(); + const auto total_time = end_time - start_time; + + float packets_per_second = + ((float)num_packets) / duration<float>(total_time).count(); + auto average_per_packet = total_time / num_packets; + const duration<float> standard_deviation = + calculate_standard_deviation(packet_times); + if (json) { + strm.Printf("%s\n {\"send_size\" : %6" PRIu32 + ", \"recv_size\" : %6" PRIu32 + ", \"total_time_nsec\" : %12" PRIu64 + ", \"standard_deviation_nsec\" : %9" PRIu64 " }", + result_idx > 0 ? "," : "", send_size, recv_size, + duration_cast<nanoseconds>(total_time).count(), + duration_cast<nanoseconds>(standard_deviation).count()); + ++result_idx; + } else { + strm.Printf( + "qSpeedTest(send=%-7u, recv=%-7u) in %.9f" + " sec for %9.2f packets/sec (%10.6f ms per packet) with standard " + "deviation of %10.6f ms\n", + send_size, recv_size, duration<float>(total_time).count(), + packets_per_second, + duration<float, std::milli>(average_per_packet).count(), + duration<float, std::milli>(standard_deviation).count()); } + strm.Flush(); + } } - const char *packet = stream.GetData(); - int packet_len = stream.GetSize(); - - // give the process a few seconds to startup - GDBRemoteCommunication::ScopedTimeout timeout (*this, 10); - if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) - { - std::string name; - std::string value; - StringExtractor extractor; - while (response.GetNameColonValue(name, value)) - { - if (name.compare("port") == 0) - port = StringConvert::ToUInt32(value.c_str(), 0, 0); - else if (name.compare("pid") == 0) - pid = StringConvert::ToUInt64(value.c_str(), LLDB_INVALID_PROCESS_ID, 0); - else if (name.compare("socket_name") == 0) - { - extractor.GetStringRef().swap(value); - extractor.SetFilePos(0); - extractor.GetHexByteString(value); - - socket_name = value; - } + const float k_recv_amount_mb = (float)recv_amount / (1024.0f * 1024.0f); + if (json) + strm.Printf("\n ]\n },\n \"download_speed\" : {\n \"byte_size\" " + ": %" PRIu64 ",\n \"results\" : [", + recv_amount); + else + strm.Printf("Testing receiving %2.1fMB of data using varying receive " + "packet sizes:\n", + k_recv_amount_mb); + strm.Flush(); + send_size = 0; + result_idx = 0; + for (uint32_t recv_size = 32; recv_size <= max_recv; recv_size *= 2) { + MakeSpeedTestPacket(packet, send_size, recv_size); + + // If we have a receive size, test how long it takes to receive 4MB of + // data + if (recv_size > 0) { + const auto start_time = steady_clock::now(); + uint32_t bytes_read = 0; + uint32_t packet_count = 0; + while (bytes_read < recv_amount) { + StringExtractorGDBRemote response; + SendPacketAndWaitForResponse(packet.GetString(), response, false); + bytes_read += recv_size; + ++packet_count; + } + const auto end_time = steady_clock::now(); + const auto total_time = end_time - start_time; + float mb_second = ((float)recv_amount) / + duration<float>(total_time).count() / + (1024.0 * 1024.0); + float packets_per_second = + ((float)packet_count) / duration<float>(total_time).count(); + const auto average_per_packet = total_time / packet_count; + + if (json) { + strm.Printf("%s\n {\"send_size\" : %6" PRIu32 + ", \"recv_size\" : %6" PRIu32 + ", \"total_time_nsec\" : %12" PRIu64 " }", + result_idx > 0 ? "," : "", send_size, recv_size, + duration_cast<nanoseconds>(total_time).count()); + ++result_idx; + } else { + strm.Printf("qSpeedTest(send=%-7u, recv=%-7u) %6u packets needed to " + "receive %2.1fMB in %.9f" + " sec for %f MB/sec for %9.2f packets/sec (%10.6f ms per " + "packet)\n", + send_size, recv_size, packet_count, k_recv_amount_mb, + duration<float>(total_time).count(), mb_second, + packets_per_second, + duration<float, std::milli>(average_per_packet).count()); } - return true; + strm.Flush(); + } } - return false; + if (json) + strm.Printf("\n ]\n }\n}\n"); + else + strm.EOL(); + } +} + +bool GDBRemoteCommunicationClient::SendSpeedTestPacket(uint32_t send_size, + uint32_t recv_size) { + StreamString packet; + packet.Printf("qSpeedTest:response_size:%i;data:", recv_size); + uint32_t bytes_left = send_size; + while (bytes_left > 0) { + if (bytes_left >= 26) { + packet.PutCString("abcdefghijklmnopqrstuvwxyz"); + bytes_left -= 26; + } else { + packet.Printf("%*.*s;", bytes_left, bytes_left, + "abcdefghijklmnopqrstuvwxyz"); + bytes_left = 0; + } + } + + StringExtractorGDBRemote response; + return SendPacketAndWaitForResponse(packet.GetString(), response, false) == + PacketResult::Success; +} + +bool GDBRemoteCommunicationClient::LaunchGDBServer( + const char *remote_accept_hostname, lldb::pid_t &pid, uint16_t &port, + std::string &socket_name) { + pid = LLDB_INVALID_PROCESS_ID; + port = 0; + socket_name.clear(); + + StringExtractorGDBRemote response; + StreamString stream; + stream.PutCString("qLaunchGDBServer;"); + std::string hostname; + if (remote_accept_hostname && remote_accept_hostname[0]) + hostname = remote_accept_hostname; + else { + if (HostInfo::GetHostname(hostname)) { + // Make the GDB server we launch only accept connections from this host + stream.Printf("host:%s;", hostname.c_str()); + } else { + // Make the GDB server we launch accept connections from any host since we + // can't figure out the hostname + stream.Printf("host:*;"); + } + } + // give the process a few seconds to startup + ScopedTimeout timeout(*this, seconds(10)); + + if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == + PacketResult::Success) { + llvm::StringRef name; + llvm::StringRef value; + while (response.GetNameColonValue(name, value)) { + if (name.equals("port")) + value.getAsInteger(0, port); + else if (name.equals("pid")) + value.getAsInteger(0, pid); + else if (name.compare("socket_name") == 0) { + StringExtractor extractor(value); + extractor.GetHexByteString(socket_name); + } + } + return true; + } + return false; } -size_t -GDBRemoteCommunicationClient::QueryGDBServer (std::vector<std::pair<uint16_t, std::string>>& connection_urls) -{ - connection_urls.clear(); +size_t GDBRemoteCommunicationClient::QueryGDBServer( + std::vector<std::pair<uint16_t, std::string>> &connection_urls) { + connection_urls.clear(); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("qQueryGDBServer", response, false) != PacketResult::Success) - return 0; + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse("qQueryGDBServer", response, false) != + PacketResult::Success) + return 0; - StructuredData::ObjectSP data = StructuredData::ParseJSON(response.GetStringRef()); - if (!data) - return 0; + StructuredData::ObjectSP data = + StructuredData::ParseJSON(response.GetStringRef()); + if (!data) + return 0; - StructuredData::Array* array = data->GetAsArray(); - if (!array) - return 0; + StructuredData::Array *array = data->GetAsArray(); + if (!array) + return 0; - for (size_t i = 0, count = array->GetSize(); i < count; ++i) - { - StructuredData::Dictionary* element = nullptr; - if (!array->GetItemAtIndexAsDictionary(i, element)) - continue; + for (size_t i = 0, count = array->GetSize(); i < count; ++i) { + StructuredData::Dictionary *element = nullptr; + if (!array->GetItemAtIndexAsDictionary(i, element)) + continue; - uint16_t port = 0; - if (StructuredData::ObjectSP port_osp = element->GetValueForKey(llvm::StringRef("port"))) - port = port_osp->GetIntegerValue(0); + uint16_t port = 0; + if (StructuredData::ObjectSP port_osp = + element->GetValueForKey(llvm::StringRef("port"))) + port = port_osp->GetIntegerValue(0); - std::string socket_name; - if (StructuredData::ObjectSP socket_name_osp = element->GetValueForKey(llvm::StringRef("socket_name"))) - socket_name = socket_name_osp->GetStringValue(); + std::string socket_name; + if (StructuredData::ObjectSP socket_name_osp = + element->GetValueForKey(llvm::StringRef("socket_name"))) + socket_name = socket_name_osp->GetStringValue(); - if (port != 0 || !socket_name.empty()) - connection_urls.emplace_back(port, socket_name); - } - return connection_urls.size(); + if (port != 0 || !socket_name.empty()) + connection_urls.emplace_back(port, socket_name); + } + return connection_urls.size(); } -bool -GDBRemoteCommunicationClient::KillSpawnedProcess (lldb::pid_t pid) -{ - StreamString stream; - stream.Printf ("qKillSpawnedProcess:%" PRId64 , pid); - const char *packet = stream.GetData(); - int packet_len = stream.GetSize(); +bool GDBRemoteCommunicationClient::KillSpawnedProcess(lldb::pid_t pid) { + StreamString stream; + stream.Printf("qKillSpawnedProcess:%" PRId64, pid); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - return true; - } - return false; + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == + PacketResult::Success) { + if (response.IsOKResponse()) + return true; + } + return false; } -bool -GDBRemoteCommunicationClient::SetCurrentThread (uint64_t tid) -{ - if (m_curr_tid == tid) - return true; - - char packet[32]; - int packet_len; - if (tid == UINT64_MAX) - packet_len = ::snprintf (packet, sizeof(packet), "Hg-1"); - else - packet_len = ::snprintf (packet, sizeof(packet), "Hg%" PRIx64, tid); - assert (packet_len + 1 < (int)sizeof(packet)); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - { - m_curr_tid = tid; - return true; - } +bool GDBRemoteCommunicationClient::SetCurrentThread(uint64_t tid) { + if (m_curr_tid == tid) + return true; - /* - * Connected bare-iron target (like YAMON gdb-stub) may not have support for Hg packet. - * The reply from '?' packet could be as simple as 'S05'. There is no packet which can - * give us pid and/or tid. Assume pid=tid=1 in such cases. - */ - if (response.IsUnsupportedResponse() && IsConnected()) - { - m_curr_tid = 1; - return true; - } - } - return false; -} + char packet[32]; + int packet_len; + if (tid == UINT64_MAX) + packet_len = ::snprintf(packet, sizeof(packet), "Hg-1"); + else + packet_len = ::snprintf(packet, sizeof(packet), "Hg%" PRIx64, tid); + assert(packet_len + 1 < (int)sizeof(packet)); + UNUSED_IF_ASSERT_DISABLED(packet_len); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, response, false) == + PacketResult::Success) { + if (response.IsOKResponse()) { + m_curr_tid = tid; + return true; + } + + /* + * Connected bare-iron target (like YAMON gdb-stub) may not have support for + * Hg packet. + * The reply from '?' packet could be as simple as 'S05'. There is no packet + * which can + * give us pid and/or tid. Assume pid=tid=1 in such cases. + */ + if (response.IsUnsupportedResponse() && IsConnected()) { + m_curr_tid = 1; + return true; + } + } + return false; +} + +bool GDBRemoteCommunicationClient::SetCurrentThreadForRun(uint64_t tid) { + if (m_curr_tid_run == tid) + return true; -bool -GDBRemoteCommunicationClient::SetCurrentThreadForRun (uint64_t tid) -{ - if (m_curr_tid_run == tid) + char packet[32]; + int packet_len; + if (tid == UINT64_MAX) + packet_len = ::snprintf(packet, sizeof(packet), "Hc-1"); + else + packet_len = ::snprintf(packet, sizeof(packet), "Hc%" PRIx64, tid); + + assert(packet_len + 1 < (int)sizeof(packet)); + UNUSED_IF_ASSERT_DISABLED(packet_len); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, response, false) == + PacketResult::Success) { + if (response.IsOKResponse()) { + m_curr_tid_run = tid; + return true; + } + + /* + * Connected bare-iron target (like YAMON gdb-stub) may not have support for + * Hc packet. + * The reply from '?' packet could be as simple as 'S05'. There is no packet + * which can + * give us pid and/or tid. Assume pid=tid=1 in such cases. + */ + if (response.IsUnsupportedResponse() && IsConnected()) { + m_curr_tid_run = 1; + return true; + } + } + return false; +} + +bool GDBRemoteCommunicationClient::GetStopReply( + StringExtractorGDBRemote &response) { + if (SendPacketAndWaitForResponse("?", response, false) == + PacketResult::Success) + return response.IsNormalResponse(); + return false; +} + +bool GDBRemoteCommunicationClient::GetThreadStopInfo( + lldb::tid_t tid, StringExtractorGDBRemote &response) { + if (m_supports_qThreadStopInfo) { + char packet[256]; + int packet_len = + ::snprintf(packet, sizeof(packet), "qThreadStopInfo%" PRIx64, tid); + assert(packet_len < (int)sizeof(packet)); + UNUSED_IF_ASSERT_DISABLED(packet_len); + if (SendPacketAndWaitForResponse(packet, response, false) == + PacketResult::Success) { + if (response.IsUnsupportedResponse()) + m_supports_qThreadStopInfo = false; + else if (response.IsNormalResponse()) return true; - - char packet[32]; - int packet_len; - if (tid == UINT64_MAX) - packet_len = ::snprintf (packet, sizeof(packet), "Hc-1"); - else - packet_len = ::snprintf (packet, sizeof(packet), "Hc%" PRIx64, tid); - - assert (packet_len + 1 < (int)sizeof(packet)); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - { - m_curr_tid_run = tid; - return true; - } - - /* - * Connected bare-iron target (like YAMON gdb-stub) may not have support for Hc packet. - * The reply from '?' packet could be as simple as 'S05'. There is no packet which can - * give us pid and/or tid. Assume pid=tid=1 in such cases. - */ - if (response.IsUnsupportedResponse() && IsConnected()) - { - m_curr_tid_run = 1; - return true; - } + else + return false; + } else { + m_supports_qThreadStopInfo = false; } - return false; + } + return false; } -bool -GDBRemoteCommunicationClient::GetStopReply (StringExtractorGDBRemote &response) -{ - if (SendPacketAndWaitForResponse("?", 1, response, false) == PacketResult::Success) - return response.IsNormalResponse(); - return false; -} +uint8_t GDBRemoteCommunicationClient::SendGDBStoppointTypePacket( + GDBStoppointType type, bool insert, addr_t addr, uint32_t length) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + if (log) + log->Printf("GDBRemoteCommunicationClient::%s() %s at addr = 0x%" PRIx64, + __FUNCTION__, insert ? "add" : "remove", addr); -bool -GDBRemoteCommunicationClient::GetThreadStopInfo (lldb::tid_t tid, StringExtractorGDBRemote &response) -{ - if (m_supports_qThreadStopInfo) - { - char packet[256]; - int packet_len = ::snprintf(packet, sizeof(packet), "qThreadStopInfo%" PRIx64, tid); - assert (packet_len < (int)sizeof(packet)); - if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) - { - if (response.IsUnsupportedResponse()) - m_supports_qThreadStopInfo = false; - else if (response.IsNormalResponse()) - return true; - else - return false; - } - else - { - m_supports_qThreadStopInfo = false; - } + // Check if the stub is known not to support this breakpoint type + if (!SupportsGDBStoppointPacket(type)) + return UINT8_MAX; + // Construct the breakpoint packet + char packet[64]; + const int packet_len = + ::snprintf(packet, sizeof(packet), "%c%i,%" PRIx64 ",%x", + insert ? 'Z' : 'z', type, addr, length); + // Check we haven't overwritten the end of the packet buffer + assert(packet_len + 1 < (int)sizeof(packet)); + UNUSED_IF_ASSERT_DISABLED(packet_len); + StringExtractorGDBRemote response; + // Make sure the response is either "OK", "EXX" where XX are two hex digits, + // or "" (unsupported) + response.SetResponseValidatorToOKErrorNotSupported(); + // Try to send the breakpoint packet, and check that it was correctly sent + if (SendPacketAndWaitForResponse(packet, response, true) == + PacketResult::Success) { + // Receive and OK packet when the breakpoint successfully placed + if (response.IsOKResponse()) + return 0; + + // Error while setting breakpoint, send back specific error + if (response.IsErrorResponse()) + return response.GetError(); + + // Empty packet informs us that breakpoint is not supported + if (response.IsUnsupportedResponse()) { + // Disable this breakpoint type since it is unsupported + switch (type) { + case eBreakpointSoftware: + m_supports_z0 = false; + break; + case eBreakpointHardware: + m_supports_z1 = false; + break; + case eWatchpointWrite: + m_supports_z2 = false; + break; + case eWatchpointRead: + m_supports_z3 = false; + break; + case eWatchpointReadWrite: + m_supports_z4 = false; + break; + case eStoppointInvalid: + return UINT8_MAX; + } } - return false; + } + // Signal generic failure + return UINT8_MAX; } +size_t GDBRemoteCommunicationClient::GetCurrentThreadIDs( + std::vector<lldb::tid_t> &thread_ids, bool &sequence_mutex_unavailable) { + thread_ids.clear(); -uint8_t -GDBRemoteCommunicationClient::SendGDBStoppointTypePacket (GDBStoppointType type, bool insert, addr_t addr, uint32_t length) -{ - Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); - if (log) - log->Printf ("GDBRemoteCommunicationClient::%s() %s at addr = 0x%" PRIx64, - __FUNCTION__, insert ? "add" : "remove", addr); - - // Check if the stub is known not to support this breakpoint type - if (!SupportsGDBStoppointPacket(type)) - return UINT8_MAX; - // Construct the breakpoint packet - char packet[64]; - const int packet_len = ::snprintf (packet, - sizeof(packet), - "%c%i,%" PRIx64 ",%x", - insert ? 'Z' : 'z', - type, - addr, - length); - // Check we haven't overwritten the end of the packet buffer - assert (packet_len + 1 < (int)sizeof(packet)); + Lock lock(*this, false); + if (lock) { + sequence_mutex_unavailable = false; StringExtractorGDBRemote response; - // Make sure the response is either "OK", "EXX" where XX are two hex digits, or "" (unsupported) - response.SetResponseValidatorToOKErrorNotSupported(); - // Try to send the breakpoint packet, and check that it was correctly sent - if (SendPacketAndWaitForResponse(packet, packet_len, response, true) == PacketResult::Success) - { - // Receive and OK packet when the breakpoint successfully placed - if (response.IsOKResponse()) - return 0; - - // Error while setting breakpoint, send back specific error - if (response.IsErrorResponse()) - return response.GetError(); - - // Empty packet informs us that breakpoint is not supported - if (response.IsUnsupportedResponse()) - { - // Disable this breakpoint type since it is unsupported - switch (type) - { - case eBreakpointSoftware: m_supports_z0 = false; break; - case eBreakpointHardware: m_supports_z1 = false; break; - case eWatchpointWrite: m_supports_z2 = false; break; - case eWatchpointRead: m_supports_z3 = false; break; - case eWatchpointReadWrite: m_supports_z4 = false; break; - case eStoppointInvalid: return UINT8_MAX; - } - } - } - // Signal generic failure - return UINT8_MAX; -} - -size_t -GDBRemoteCommunicationClient::GetCurrentThreadIDs (std::vector<lldb::tid_t> &thread_ids, - bool &sequence_mutex_unavailable) -{ - Mutex::Locker locker; - thread_ids.clear(); - - if (GetSequenceMutex (locker, "ProcessGDBRemote::UpdateThreadList() failed due to not getting the sequence mutex")) - { - sequence_mutex_unavailable = false; - StringExtractorGDBRemote response; - - PacketResult packet_result; - for (packet_result = SendPacketAndWaitForResponseNoLock ("qfThreadInfo", strlen("qfThreadInfo"), response); - packet_result == PacketResult::Success && response.IsNormalResponse(); - packet_result = SendPacketAndWaitForResponseNoLock ("qsThreadInfo", strlen("qsThreadInfo"), response)) - { - char ch = response.GetChar(); - if (ch == 'l') - break; - if (ch == 'm') - { - do - { - tid_t tid = response.GetHexMaxU64(false, LLDB_INVALID_THREAD_ID); - - if (tid != LLDB_INVALID_THREAD_ID) - { - thread_ids.push_back (tid); - } - ch = response.GetChar(); // Skip the command separator - } while (ch == ','); // Make sure we got a comma separator - } - } - /* - * Connected bare-iron target (like YAMON gdb-stub) may not have support for - * qProcessInfo, qC and qfThreadInfo packets. The reply from '?' packet could - * be as simple as 'S05'. There is no packet which can give us pid and/or tid. - * Assume pid=tid=1 in such cases. - */ - if (response.IsUnsupportedResponse() && thread_ids.size() == 0 && IsConnected()) - { - thread_ids.push_back (1); - } - } - else - { -#if defined (LLDB_CONFIGURATION_DEBUG) - // assert(!"ProcessGDBRemote::UpdateThreadList() failed due to not getting the sequence mutex"); -#else - Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_PROCESS | GDBR_LOG_PACKETS)); - if (log) - log->Printf("error: failed to get packet sequence mutex, not sending packet 'qfThreadInfo'"); + PacketResult packet_result; + for (packet_result = + SendPacketAndWaitForResponseNoLock("qfThreadInfo", response); + packet_result == PacketResult::Success && response.IsNormalResponse(); + packet_result = + SendPacketAndWaitForResponseNoLock("qsThreadInfo", response)) { + char ch = response.GetChar(); + if (ch == 'l') + break; + if (ch == 'm') { + do { + tid_t tid = response.GetHexMaxU64(false, LLDB_INVALID_THREAD_ID); + + if (tid != LLDB_INVALID_THREAD_ID) { + thread_ids.push_back(tid); + } + ch = response.GetChar(); // Skip the command separator + } while (ch == ','); // Make sure we got a comma separator + } + } + + /* + * Connected bare-iron target (like YAMON gdb-stub) may not have support for + * qProcessInfo, qC and qfThreadInfo packets. The reply from '?' packet + * could + * be as simple as 'S05'. There is no packet which can give us pid and/or + * tid. + * Assume pid=tid=1 in such cases. + */ + if (response.IsUnsupportedResponse() && thread_ids.size() == 0 && + IsConnected()) { + thread_ids.push_back(1); + } + } else { +#if !defined(LLDB_CONFIGURATION_DEBUG) + Log *log(ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(GDBR_LOG_PROCESS | + GDBR_LOG_PACKETS)); + if (log) + log->Printf("error: failed to get packet sequence mutex, not sending " + "packet 'qfThreadInfo'"); #endif - sequence_mutex_unavailable = true; - } - return thread_ids.size(); + sequence_mutex_unavailable = true; + } + return thread_ids.size(); } -lldb::addr_t -GDBRemoteCommunicationClient::GetShlibInfoAddr() -{ - if (!IsRunning()) - { - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("qShlibInfoAddr", ::strlen ("qShlibInfoAddr"), response, false) == PacketResult::Success) - { - if (response.IsNormalResponse()) - return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS); - } - } +lldb::addr_t GDBRemoteCommunicationClient::GetShlibInfoAddr() { + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse("qShlibInfoAddr", response, false) != + PacketResult::Success || + !response.IsNormalResponse()) return LLDB_INVALID_ADDRESS; -} - -lldb_private::Error -GDBRemoteCommunicationClient::RunShellCommand(const char *command, // Shouldn't be NULL - const FileSpec &working_dir, // Pass empty FileSpec to use the current working directory - int *status_ptr, // Pass NULL if you don't want the process exit status - int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit - std::string *command_output, // Pass NULL if you don't want the command output - uint32_t timeout_sec) // Timeout in seconds to wait for shell program to finish -{ - lldb_private::StreamString stream; - stream.PutCString("qPlatform_shell:"); - stream.PutBytesAsRawHex8(command, strlen(command)); - stream.PutChar(','); - stream.PutHex32(timeout_sec); - if (working_dir) - { - std::string path{working_dir.GetPath(false)}; - stream.PutChar(','); - stream.PutCStringAsRawHex8(path.c_str()); - } - const char *packet = stream.GetData(); - int packet_len = stream.GetSize(); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) - { - if (response.GetChar() != 'F') - return Error("malformed reply"); - if (response.GetChar() != ',') - return Error("malformed reply"); - uint32_t exitcode = response.GetHexMaxU32(false, UINT32_MAX); - if (exitcode == UINT32_MAX) - return Error("unable to run remote process"); - else if (status_ptr) - *status_ptr = exitcode; - if (response.GetChar() != ',') - return Error("malformed reply"); - uint32_t signo = response.GetHexMaxU32(false, UINT32_MAX); - if (signo_ptr) - *signo_ptr = signo; - if (response.GetChar() != ',') - return Error("malformed reply"); - std::string output; - response.GetEscapedBinaryData(output); - if (command_output) - command_output->assign(output); - return Error(); - } - return Error("unable to send packet"); -} - -Error -GDBRemoteCommunicationClient::MakeDirectory(const FileSpec &file_spec, - uint32_t file_permissions) -{ - std::string path{file_spec.GetPath(false)}; - lldb_private::StreamString stream; - stream.PutCString("qPlatform_mkdir:"); - stream.PutHex32(file_permissions); + return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS); +} + +lldb_private::Error GDBRemoteCommunicationClient::RunShellCommand( + const char *command, // Shouldn't be NULL + const FileSpec & + working_dir, // Pass empty FileSpec to use the current working directory + int *status_ptr, // Pass NULL if you don't want the process exit status + int *signo_ptr, // Pass NULL if you don't want the signal that caused the + // process to exit + std::string + *command_output, // Pass NULL if you don't want the command output + uint32_t + timeout_sec) // Timeout in seconds to wait for shell program to finish +{ + lldb_private::StreamString stream; + stream.PutCString("qPlatform_shell:"); + stream.PutBytesAsRawHex8(command, strlen(command)); + stream.PutChar(','); + stream.PutHex32(timeout_sec); + if (working_dir) { + std::string path{working_dir.GetPath(false)}; stream.PutChar(','); stream.PutCStringAsRawHex8(path.c_str()); - const char *packet = stream.GetData(); - int packet_len = stream.GetSize(); - StringExtractorGDBRemote response; - - if (SendPacketAndWaitForResponse(packet, packet_len, response, false) != PacketResult::Success) - return Error("failed to send '%s' packet", packet); - + } + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == + PacketResult::Success) { if (response.GetChar() != 'F') - return Error("invalid response to '%s' packet", packet); - - return Error(response.GetU32(UINT32_MAX), eErrorTypePOSIX); -} - -Error -GDBRemoteCommunicationClient::SetFilePermissions(const FileSpec &file_spec, - uint32_t file_permissions) -{ - std::string path{file_spec.GetPath(false)}; - lldb_private::StreamString stream; - stream.PutCString("qPlatform_chmod:"); - stream.PutHex32(file_permissions); - stream.PutChar(','); - stream.PutCStringAsRawHex8(path.c_str()); - const char *packet = stream.GetData(); - int packet_len = stream.GetSize(); - StringExtractorGDBRemote response; - - if (SendPacketAndWaitForResponse(packet, packet_len, response, false) != PacketResult::Success) - return Error("failed to send '%s' packet", packet); - - if (response.GetChar() != 'F') - return Error("invalid response to '%s' packet", packet); - - return Error(response.GetU32(UINT32_MAX), eErrorTypePOSIX); -} - -static uint64_t -ParseHostIOPacketResponse (StringExtractorGDBRemote &response, - uint64_t fail_result, - Error &error) -{ - response.SetFilePos(0); - if (response.GetChar() != 'F') - return fail_result; - int32_t result = response.GetS32 (-2); - if (result == -2) - return fail_result; - if (response.GetChar() == ',') - { - int result_errno = response.GetS32 (-2); - if (result_errno != -2) - error.SetError(result_errno, eErrorTypePOSIX); - else - error.SetError(-1, eErrorTypeGeneric); - } + return Error("malformed reply"); + if (response.GetChar() != ',') + return Error("malformed reply"); + uint32_t exitcode = response.GetHexMaxU32(false, UINT32_MAX); + if (exitcode == UINT32_MAX) + return Error("unable to run remote process"); + else if (status_ptr) + *status_ptr = exitcode; + if (response.GetChar() != ',') + return Error("malformed reply"); + uint32_t signo = response.GetHexMaxU32(false, UINT32_MAX); + if (signo_ptr) + *signo_ptr = signo; + if (response.GetChar() != ',') + return Error("malformed reply"); + std::string output; + response.GetEscapedBinaryData(output); + if (command_output) + command_output->assign(output); + return Error(); + } + return Error("unable to send packet"); +} + +Error GDBRemoteCommunicationClient::MakeDirectory(const FileSpec &file_spec, + uint32_t file_permissions) { + std::string path{file_spec.GetPath(false)}; + lldb_private::StreamString stream; + stream.PutCString("qPlatform_mkdir:"); + stream.PutHex32(file_permissions); + stream.PutChar(','); + stream.PutCStringAsRawHex8(path.c_str()); + llvm::StringRef packet = stream.GetString(); + StringExtractorGDBRemote response; + + if (SendPacketAndWaitForResponse(packet, response, false) != + PacketResult::Success) + return Error("failed to send '%s' packet", packet.str().c_str()); + + if (response.GetChar() != 'F') + return Error("invalid response to '%s' packet", packet.str().c_str()); + + return Error(response.GetU32(UINT32_MAX), eErrorTypePOSIX); +} + +Error GDBRemoteCommunicationClient::SetFilePermissions( + const FileSpec &file_spec, uint32_t file_permissions) { + std::string path{file_spec.GetPath(false)}; + lldb_private::StreamString stream; + stream.PutCString("qPlatform_chmod:"); + stream.PutHex32(file_permissions); + stream.PutChar(','); + stream.PutCStringAsRawHex8(path.c_str()); + llvm::StringRef packet = stream.GetString(); + StringExtractorGDBRemote response; + + if (SendPacketAndWaitForResponse(packet, response, false) != + PacketResult::Success) + return Error("failed to send '%s' packet", stream.GetData()); + + if (response.GetChar() != 'F') + return Error("invalid response to '%s' packet", stream.GetData()); + + return Error(response.GetU32(UINT32_MAX), eErrorTypePOSIX); +} + +static uint64_t ParseHostIOPacketResponse(StringExtractorGDBRemote &response, + uint64_t fail_result, Error &error) { + response.SetFilePos(0); + if (response.GetChar() != 'F') + return fail_result; + int32_t result = response.GetS32(-2); + if (result == -2) + return fail_result; + if (response.GetChar() == ',') { + int result_errno = response.GetS32(-2); + if (result_errno != -2) + error.SetError(result_errno, eErrorTypePOSIX); else - error.Clear(); - return result; + error.SetError(-1, eErrorTypeGeneric); + } else + error.Clear(); + return result; } lldb::user_id_t -GDBRemoteCommunicationClient::OpenFile (const lldb_private::FileSpec& file_spec, - uint32_t flags, - mode_t mode, - Error &error) -{ - std::string path(file_spec.GetPath(false)); - lldb_private::StreamString stream; - stream.PutCString("vFile:open:"); - if (path.empty()) - return UINT64_MAX; - stream.PutCStringAsRawHex8(path.c_str()); - stream.PutChar(','); - stream.PutHex32(flags); - stream.PutChar(','); - stream.PutHex32(mode); - const char* packet = stream.GetData(); - int packet_len = stream.GetSize(); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) - { - return ParseHostIOPacketResponse (response, UINT64_MAX, error); - } +GDBRemoteCommunicationClient::OpenFile(const lldb_private::FileSpec &file_spec, + uint32_t flags, mode_t mode, + Error &error) { + std::string path(file_spec.GetPath(false)); + lldb_private::StreamString stream; + stream.PutCString("vFile:open:"); + if (path.empty()) return UINT64_MAX; -} - -bool -GDBRemoteCommunicationClient::CloseFile (lldb::user_id_t fd, - Error &error) -{ - lldb_private::StreamString stream; - stream.Printf("vFile:close:%i", (int)fd); - const char* packet = stream.GetData(); - int packet_len = stream.GetSize(); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) - { - return ParseHostIOPacketResponse (response, -1, error) == 0; - } - return false; + stream.PutCStringAsRawHex8(path.c_str()); + stream.PutChar(','); + stream.PutHex32(flags); + stream.PutChar(','); + stream.PutHex32(mode); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == + PacketResult::Success) { + return ParseHostIOPacketResponse(response, UINT64_MAX, error); + } + return UINT64_MAX; +} + +bool GDBRemoteCommunicationClient::CloseFile(lldb::user_id_t fd, Error &error) { + lldb_private::StreamString stream; + stream.Printf("vFile:close:%i", (int)fd); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == + PacketResult::Success) { + return ParseHostIOPacketResponse(response, -1, error) == 0; + } + return false; } // Extension of host I/O packets to get the file size. -lldb::user_id_t -GDBRemoteCommunicationClient::GetFileSize (const lldb_private::FileSpec& file_spec) -{ - std::string path(file_spec.GetPath(false)); - lldb_private::StreamString stream; - stream.PutCString("vFile:size:"); - stream.PutCStringAsRawHex8(path.c_str()); - const char* packet = stream.GetData(); - int packet_len = stream.GetSize(); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) - { - if (response.GetChar() != 'F') - return UINT64_MAX; - uint32_t retcode = response.GetHexMaxU64(false, UINT64_MAX); - return retcode; - } - return UINT64_MAX; +lldb::user_id_t GDBRemoteCommunicationClient::GetFileSize( + const lldb_private::FileSpec &file_spec) { + std::string path(file_spec.GetPath(false)); + lldb_private::StreamString stream; + stream.PutCString("vFile:size:"); + stream.PutCStringAsRawHex8(path.c_str()); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == + PacketResult::Success) { + if (response.GetChar() != 'F') + return UINT64_MAX; + uint32_t retcode = response.GetHexMaxU64(false, UINT64_MAX); + return retcode; + } + return UINT64_MAX; +} + +Error GDBRemoteCommunicationClient::GetFilePermissions( + const FileSpec &file_spec, uint32_t &file_permissions) { + std::string path{file_spec.GetPath(false)}; + Error error; + lldb_private::StreamString stream; + stream.PutCString("vFile:mode:"); + stream.PutCStringAsRawHex8(path.c_str()); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == + PacketResult::Success) { + if (response.GetChar() != 'F') { + error.SetErrorStringWithFormat("invalid response to '%s' packet", + stream.GetData()); + } else { + const uint32_t mode = response.GetS32(-1); + if (static_cast<int32_t>(mode) == -1) { + if (response.GetChar() == ',') { + int response_errno = response.GetS32(-1); + if (response_errno > 0) + error.SetError(response_errno, lldb::eErrorTypePOSIX); + else + error.SetErrorToGenericError(); + } else + error.SetErrorToGenericError(); + } else { + file_permissions = mode & (S_IRWXU | S_IRWXG | S_IRWXO); + } + } + } else { + error.SetErrorStringWithFormat("failed to send '%s' packet", + stream.GetData()); + } + return error; +} + +uint64_t GDBRemoteCommunicationClient::ReadFile(lldb::user_id_t fd, + uint64_t offset, void *dst, + uint64_t dst_len, + Error &error) { + lldb_private::StreamString stream; + stream.Printf("vFile:pread:%i,%" PRId64 ",%" PRId64, (int)fd, dst_len, + offset); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == + PacketResult::Success) { + if (response.GetChar() != 'F') + return 0; + uint32_t retcode = response.GetHexMaxU32(false, UINT32_MAX); + if (retcode == UINT32_MAX) + return retcode; + const char next = (response.Peek() ? *response.Peek() : 0); + if (next == ',') + return 0; + if (next == ';') { + response.GetChar(); // skip the semicolon + std::string buffer; + if (response.GetEscapedBinaryData(buffer)) { + const uint64_t data_to_write = + std::min<uint64_t>(dst_len, buffer.size()); + if (data_to_write > 0) + memcpy(dst, &buffer[0], data_to_write); + return data_to_write; + } + } + } + return 0; +} + +uint64_t GDBRemoteCommunicationClient::WriteFile(lldb::user_id_t fd, + uint64_t offset, + const void *src, + uint64_t src_len, + Error &error) { + lldb_private::StreamGDBRemote stream; + stream.Printf("vFile:pwrite:%i,%" PRId64 ",", (int)fd, offset); + stream.PutEscapedBytes(src, src_len); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == + PacketResult::Success) { + if (response.GetChar() != 'F') { + error.SetErrorStringWithFormat("write file failed"); + return 0; + } + uint64_t bytes_written = response.GetU64(UINT64_MAX); + if (bytes_written == UINT64_MAX) { + error.SetErrorToGenericError(); + if (response.GetChar() == ',') { + int response_errno = response.GetS32(-1); + if (response_errno > 0) + error.SetError(response_errno, lldb::eErrorTypePOSIX); + } + return 0; + } + return bytes_written; + } else { + error.SetErrorString("failed to send vFile:pwrite packet"); + } + return 0; +} + +Error GDBRemoteCommunicationClient::CreateSymlink(const FileSpec &src, + const FileSpec &dst) { + std::string src_path{src.GetPath(false)}, dst_path{dst.GetPath(false)}; + Error error; + lldb_private::StreamGDBRemote stream; + stream.PutCString("vFile:symlink:"); + // the unix symlink() command reverses its parameters where the dst if first, + // so we follow suit here + stream.PutCStringAsRawHex8(dst_path.c_str()); + stream.PutChar(','); + stream.PutCStringAsRawHex8(src_path.c_str()); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == + PacketResult::Success) { + if (response.GetChar() == 'F') { + uint32_t result = response.GetU32(UINT32_MAX); + if (result != 0) { + error.SetErrorToGenericError(); + if (response.GetChar() == ',') { + int response_errno = response.GetS32(-1); + if (response_errno > 0) + error.SetError(response_errno, lldb::eErrorTypePOSIX); + } + } + } else { + // Should have returned with 'F<result>[,<errno>]' + error.SetErrorStringWithFormat("symlink failed"); + } + } else { + error.SetErrorString("failed to send vFile:symlink packet"); + } + return error; +} + +Error GDBRemoteCommunicationClient::Unlink(const FileSpec &file_spec) { + std::string path{file_spec.GetPath(false)}; + Error error; + lldb_private::StreamGDBRemote stream; + stream.PutCString("vFile:unlink:"); + // the unix symlink() command reverses its parameters where the dst if first, + // so we follow suit here + stream.PutCStringAsRawHex8(path.c_str()); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == + PacketResult::Success) { + if (response.GetChar() == 'F') { + uint32_t result = response.GetU32(UINT32_MAX); + if (result != 0) { + error.SetErrorToGenericError(); + if (response.GetChar() == ',') { + int response_errno = response.GetS32(-1); + if (response_errno > 0) + error.SetError(response_errno, lldb::eErrorTypePOSIX); + } + } + } else { + // Should have returned with 'F<result>[,<errno>]' + error.SetErrorStringWithFormat("unlink failed"); + } + } else { + error.SetErrorString("failed to send vFile:unlink packet"); + } + return error; } -Error -GDBRemoteCommunicationClient::GetFilePermissions(const FileSpec &file_spec, - uint32_t &file_permissions) -{ - std::string path{file_spec.GetPath(false)}; - Error error; - lldb_private::StreamString stream; - stream.PutCString("vFile:mode:"); - stream.PutCStringAsRawHex8(path.c_str()); - const char* packet = stream.GetData(); - int packet_len = stream.GetSize(); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) - { - if (response.GetChar() != 'F') - { - error.SetErrorStringWithFormat ("invalid response to '%s' packet", packet); - } - else - { - const uint32_t mode = response.GetS32(-1); - if (static_cast<int32_t>(mode) == -1) - { - if (response.GetChar() == ',') - { - int response_errno = response.GetS32(-1); - if (response_errno > 0) - error.SetError(response_errno, lldb::eErrorTypePOSIX); - else - error.SetErrorToGenericError(); - } - else - error.SetErrorToGenericError(); - } - else - { - file_permissions = mode & (S_IRWXU|S_IRWXG|S_IRWXO); - } - } - } - else - { - error.SetErrorStringWithFormat ("failed to send '%s' packet", packet); - } - return error; -} +// Extension of host I/O packets to get whether a file exists. +bool GDBRemoteCommunicationClient::GetFileExists( + const lldb_private::FileSpec &file_spec) { + std::string path(file_spec.GetPath(false)); + lldb_private::StreamString stream; + stream.PutCString("vFile:exists:"); + stream.PutCStringAsRawHex8(path.c_str()); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == + PacketResult::Success) { + if (response.GetChar() != 'F') + return false; + if (response.GetChar() != ',') + return false; + bool retcode = (response.GetChar() != '0'); + return retcode; + } + return false; +} + +bool GDBRemoteCommunicationClient::CalculateMD5( + const lldb_private::FileSpec &file_spec, uint64_t &high, uint64_t &low) { + std::string path(file_spec.GetPath(false)); + lldb_private::StreamString stream; + stream.PutCString("vFile:MD5:"); + stream.PutCStringAsRawHex8(path.c_str()); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == + PacketResult::Success) { + if (response.GetChar() != 'F') + return false; + if (response.GetChar() != ',') + return false; + if (response.Peek() && *response.Peek() == 'x') + return false; + low = response.GetHexMaxU64(false, UINT64_MAX); + high = response.GetHexMaxU64(false, UINT64_MAX); + return true; + } + return false; +} + +bool GDBRemoteCommunicationClient::AvoidGPackets(ProcessGDBRemote *process) { + // Some targets have issues with g/G packets and we need to avoid using them + if (m_avoid_g_packets == eLazyBoolCalculate) { + if (process) { + m_avoid_g_packets = eLazyBoolNo; + const ArchSpec &arch = process->GetTarget().GetArchitecture(); + if (arch.IsValid() && + arch.GetTriple().getVendor() == llvm::Triple::Apple && + arch.GetTriple().getOS() == llvm::Triple::IOS && + arch.GetTriple().getArch() == llvm::Triple::aarch64) { + m_avoid_g_packets = eLazyBoolYes; + uint32_t gdb_server_version = GetGDBServerProgramVersion(); + if (gdb_server_version != 0) { + const char *gdb_server_name = GetGDBServerProgramName(); + if (gdb_server_name && strcmp(gdb_server_name, "debugserver") == 0) { + if (gdb_server_version >= 310) + m_avoid_g_packets = eLazyBoolNo; + } + } + } + } + } + return m_avoid_g_packets == eLazyBoolYes; +} + +DataBufferSP GDBRemoteCommunicationClient::ReadRegister(lldb::tid_t tid, + uint32_t reg) { + StreamString payload; + payload.Printf("p%x", reg); + StringExtractorGDBRemote response; + if (SendThreadSpecificPacketAndWaitForResponse( + tid, std::move(payload), response, false) != PacketResult::Success || + !response.IsNormalResponse()) + return nullptr; + + DataBufferSP buffer_sp( + new DataBufferHeap(response.GetStringRef().size() / 2, 0)); + response.GetHexBytes(buffer_sp->GetData(), '\xcc'); + return buffer_sp; +} + +DataBufferSP GDBRemoteCommunicationClient::ReadAllRegisters(lldb::tid_t tid) { + StreamString payload; + payload.PutChar('g'); + StringExtractorGDBRemote response; + if (SendThreadSpecificPacketAndWaitForResponse( + tid, std::move(payload), response, false) != PacketResult::Success || + !response.IsNormalResponse()) + return nullptr; + + DataBufferSP buffer_sp( + new DataBufferHeap(response.GetStringRef().size() / 2, 0)); + response.GetHexBytes(buffer_sp->GetData(), '\xcc'); + return buffer_sp; +} + +bool GDBRemoteCommunicationClient::WriteRegister(lldb::tid_t tid, + uint32_t reg_num, + llvm::ArrayRef<uint8_t> data) { + StreamString payload; + payload.Printf("P%x=", reg_num); + payload.PutBytesAsRawHex8(data.data(), data.size(), + endian::InlHostByteOrder(), + endian::InlHostByteOrder()); + StringExtractorGDBRemote response; + return SendThreadSpecificPacketAndWaitForResponse(tid, std::move(payload), + response, false) == + PacketResult::Success && + response.IsOKResponse(); +} + +bool GDBRemoteCommunicationClient::WriteAllRegisters( + lldb::tid_t tid, llvm::ArrayRef<uint8_t> data) { + StreamString payload; + payload.PutChar('G'); + payload.PutBytesAsRawHex8(data.data(), data.size(), + endian::InlHostByteOrder(), + endian::InlHostByteOrder()); + StringExtractorGDBRemote response; + return SendThreadSpecificPacketAndWaitForResponse(tid, std::move(payload), + response, false) == + PacketResult::Success && + response.IsOKResponse(); +} + +bool GDBRemoteCommunicationClient::SaveRegisterState(lldb::tid_t tid, + uint32_t &save_id) { + save_id = 0; // Set to invalid save ID + if (m_supports_QSaveRegisterState == eLazyBoolNo) + return false; -uint64_t -GDBRemoteCommunicationClient::ReadFile (lldb::user_id_t fd, - uint64_t offset, - void *dst, - uint64_t dst_len, - Error &error) -{ - lldb_private::StreamString stream; - stream.Printf("vFile:pread:%i,%" PRId64 ",%" PRId64, (int)fd, dst_len, offset); - const char* packet = stream.GetData(); - int packet_len = stream.GetSize(); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) - { - if (response.GetChar() != 'F') - return 0; - uint32_t retcode = response.GetHexMaxU32(false, UINT32_MAX); - if (retcode == UINT32_MAX) - return retcode; - const char next = (response.Peek() ? *response.Peek() : 0); - if (next == ',') - return 0; - if (next == ';') - { - response.GetChar(); // skip the semicolon - std::string buffer; - if (response.GetEscapedBinaryData(buffer)) - { - const uint64_t data_to_write = std::min<uint64_t>(dst_len, buffer.size()); - if (data_to_write > 0) - memcpy(dst, &buffer[0], data_to_write); - return data_to_write; - } - } - } - return 0; -} + m_supports_QSaveRegisterState = eLazyBoolYes; + StreamString payload; + payload.PutCString("QSaveRegisterState"); + StringExtractorGDBRemote response; + if (SendThreadSpecificPacketAndWaitForResponse( + tid, std::move(payload), response, false) != PacketResult::Success) + return false; -uint64_t -GDBRemoteCommunicationClient::WriteFile (lldb::user_id_t fd, - uint64_t offset, - const void* src, - uint64_t src_len, - Error &error) -{ - lldb_private::StreamGDBRemote stream; - stream.Printf("vFile:pwrite:%i,%" PRId64 ",", (int)fd, offset); - stream.PutEscapedBytes(src, src_len); - const char* packet = stream.GetData(); - int packet_len = stream.GetSize(); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) - { - if (response.GetChar() != 'F') - { - error.SetErrorStringWithFormat("write file failed"); - return 0; - } - uint64_t bytes_written = response.GetU64(UINT64_MAX); - if (bytes_written == UINT64_MAX) - { - error.SetErrorToGenericError(); - if (response.GetChar() == ',') - { - int response_errno = response.GetS32(-1); - if (response_errno > 0) - error.SetError(response_errno, lldb::eErrorTypePOSIX); - } - return 0; - } - return bytes_written; - } - else - { - error.SetErrorString ("failed to send vFile:pwrite packet"); - } - return 0; -} + if (response.IsUnsupportedResponse()) + m_supports_QSaveRegisterState = eLazyBoolNo; -Error -GDBRemoteCommunicationClient::CreateSymlink(const FileSpec &src, const FileSpec &dst) -{ - std::string src_path{src.GetPath(false)}, - dst_path{dst.GetPath(false)}; - Error error; - lldb_private::StreamGDBRemote stream; - stream.PutCString("vFile:symlink:"); - // the unix symlink() command reverses its parameters where the dst if first, - // so we follow suit here - stream.PutCStringAsRawHex8(dst_path.c_str()); - stream.PutChar(','); - stream.PutCStringAsRawHex8(src_path.c_str()); - const char* packet = stream.GetData(); - int packet_len = stream.GetSize(); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) - { - if (response.GetChar() == 'F') - { - uint32_t result = response.GetU32(UINT32_MAX); - if (result != 0) - { - error.SetErrorToGenericError(); - if (response.GetChar() == ',') - { - int response_errno = response.GetS32(-1); - if (response_errno > 0) - error.SetError(response_errno, lldb::eErrorTypePOSIX); - } - } - } - else - { - // Should have returned with 'F<result>[,<errno>]' - error.SetErrorStringWithFormat("symlink failed"); - } - } - else - { - error.SetErrorString ("failed to send vFile:symlink packet"); - } - return error; -} + const uint32_t response_save_id = response.GetU32(0); + if (response_save_id == 0) + return false; -Error -GDBRemoteCommunicationClient::Unlink(const FileSpec &file_spec) -{ - std::string path{file_spec.GetPath(false)}; - Error error; - lldb_private::StreamGDBRemote stream; - stream.PutCString("vFile:unlink:"); - // the unix symlink() command reverses its parameters where the dst if first, - // so we follow suit here - stream.PutCStringAsRawHex8(path.c_str()); - const char* packet = stream.GetData(); - int packet_len = stream.GetSize(); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) - { - if (response.GetChar() == 'F') - { - uint32_t result = response.GetU32(UINT32_MAX); - if (result != 0) - { - error.SetErrorToGenericError(); - if (response.GetChar() == ',') - { - int response_errno = response.GetS32(-1); - if (response_errno > 0) - error.SetError(response_errno, lldb::eErrorTypePOSIX); - } - } - } - else - { - // Should have returned with 'F<result>[,<errno>]' - error.SetErrorStringWithFormat("unlink failed"); - } - } - else - { - error.SetErrorString ("failed to send vFile:unlink packet"); - } - return error; + save_id = response_save_id; + return true; } -// Extension of host I/O packets to get whether a file exists. -bool -GDBRemoteCommunicationClient::GetFileExists (const lldb_private::FileSpec& file_spec) -{ - std::string path(file_spec.GetPath(false)); - lldb_private::StreamString stream; - stream.PutCString("vFile:exists:"); - stream.PutCStringAsRawHex8(path.c_str()); - const char* packet = stream.GetData(); - int packet_len = stream.GetSize(); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) - { - if (response.GetChar() != 'F') - return false; - if (response.GetChar() != ',') - return false; - bool retcode = (response.GetChar() != '0'); - return retcode; - } +bool GDBRemoteCommunicationClient::RestoreRegisterState(lldb::tid_t tid, + uint32_t save_id) { + // We use the "m_supports_QSaveRegisterState" variable here because the + // QSaveRegisterState and QRestoreRegisterState packets must both be supported + // in + // order to be useful + if (m_supports_QSaveRegisterState == eLazyBoolNo) return false; -} -bool -GDBRemoteCommunicationClient::CalculateMD5 (const lldb_private::FileSpec& file_spec, - uint64_t &high, - uint64_t &low) -{ - std::string path(file_spec.GetPath(false)); - lldb_private::StreamString stream; - stream.PutCString("vFile:MD5:"); - stream.PutCStringAsRawHex8(path.c_str()); - const char* packet = stream.GetData(); - int packet_len = stream.GetSize(); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) - { - if (response.GetChar() != 'F') - return false; - if (response.GetChar() != ',') - return false; - if (response.Peek() && *response.Peek() == 'x') - return false; - low = response.GetHexMaxU64(false, UINT64_MAX); - high = response.GetHexMaxU64(false, UINT64_MAX); - return true; - } + StreamString payload; + payload.Printf("QRestoreRegisterState:%u", save_id); + StringExtractorGDBRemote response; + if (SendThreadSpecificPacketAndWaitForResponse( + tid, std::move(payload), response, false) != PacketResult::Success) return false; -} -bool -GDBRemoteCommunicationClient::AvoidGPackets (ProcessGDBRemote *process) -{ - // Some targets have issues with g/G packets and we need to avoid using them - if (m_avoid_g_packets == eLazyBoolCalculate) - { - if (process) - { - m_avoid_g_packets = eLazyBoolNo; - const ArchSpec &arch = process->GetTarget().GetArchitecture(); - if (arch.IsValid() - && arch.GetTriple().getVendor() == llvm::Triple::Apple - && arch.GetTriple().getOS() == llvm::Triple::IOS - && arch.GetTriple().getArch() == llvm::Triple::aarch64) - { - m_avoid_g_packets = eLazyBoolYes; - uint32_t gdb_server_version = GetGDBServerProgramVersion(); - if (gdb_server_version != 0) - { - const char *gdb_server_name = GetGDBServerProgramName(); - if (gdb_server_name && strcmp(gdb_server_name, "debugserver") == 0) - { - if (gdb_server_version >= 310) - m_avoid_g_packets = eLazyBoolNo; - } - } - } - } - } - return m_avoid_g_packets == eLazyBoolYes; + if (response.IsOKResponse()) + return true; + + if (response.IsUnsupportedResponse()) + m_supports_QSaveRegisterState = eLazyBoolNo; + return false; } -bool -GDBRemoteCommunicationClient::ReadRegister(lldb::tid_t tid, uint32_t reg, StringExtractorGDBRemote &response) -{ - Mutex::Locker locker; - if (GetSequenceMutex (locker, "Didn't get sequence mutex for p packet.")) - { - const bool thread_suffix_supported = GetThreadSuffixSupported(); - - if (thread_suffix_supported || SetCurrentThread(tid)) - { - char packet[64]; - int packet_len = 0; - if (thread_suffix_supported) - packet_len = ::snprintf (packet, sizeof(packet), "p%x;thread:%4.4" PRIx64 ";", reg, tid); - else - packet_len = ::snprintf (packet, sizeof(packet), "p%x", reg); - assert (packet_len < ((int)sizeof(packet) - 1)); - return SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success; - } - } +bool GDBRemoteCommunicationClient::SyncThreadState(lldb::tid_t tid) { + if (!GetSyncThreadStateSupported()) return false; + StreamString packet; + StringExtractorGDBRemote response; + packet.Printf("QSyncThreadState:%4.4" PRIx64 ";", tid); + return SendPacketAndWaitForResponse(packet.GetString(), response, false) == + GDBRemoteCommunication::PacketResult::Success && + response.IsOKResponse(); } +bool GDBRemoteCommunicationClient::GetModuleInfo( + const FileSpec &module_file_spec, const lldb_private::ArchSpec &arch_spec, + ModuleSpec &module_spec) { + if (!m_supports_qModuleInfo) + return false; -bool -GDBRemoteCommunicationClient::ReadAllRegisters (lldb::tid_t tid, StringExtractorGDBRemote &response) -{ - Mutex::Locker locker; - if (GetSequenceMutex (locker, "Didn't get sequence mutex for g packet.")) - { - const bool thread_suffix_supported = GetThreadSuffixSupported(); - - if (thread_suffix_supported || SetCurrentThread(tid)) - { - char packet[64]; - int packet_len = 0; - // Get all registers in one packet - if (thread_suffix_supported) - packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4" PRIx64 ";", tid); - else - packet_len = ::snprintf (packet, sizeof(packet), "g"); - assert (packet_len < ((int)sizeof(packet) - 1)); - return SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success; - } - } + std::string module_path = module_file_spec.GetPath(false); + if (module_path.empty()) return false; -} -bool -GDBRemoteCommunicationClient::SaveRegisterState (lldb::tid_t tid, uint32_t &save_id) -{ - save_id = 0; // Set to invalid save ID - if (m_supports_QSaveRegisterState == eLazyBoolNo) - return false; - - m_supports_QSaveRegisterState = eLazyBoolYes; - Mutex::Locker locker; - if (GetSequenceMutex (locker, "Didn't get sequence mutex for QSaveRegisterState.")) - { - const bool thread_suffix_supported = GetThreadSuffixSupported(); - if (thread_suffix_supported || SetCurrentThread(tid)) - { - char packet[256]; - if (thread_suffix_supported) - ::snprintf (packet, sizeof(packet), "QSaveRegisterState;thread:%4.4" PRIx64 ";", tid); - else - ::snprintf(packet, sizeof(packet), "QSaveRegisterState"); - - StringExtractorGDBRemote response; - - if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success) - { - if (response.IsUnsupportedResponse()) - { - // This packet isn't supported, don't try calling it again - m_supports_QSaveRegisterState = eLazyBoolNo; - } - - const uint32_t response_save_id = response.GetU32(0); - if (response_save_id != 0) - { - save_id = response_save_id; - return true; - } - } - } - } + + StreamString packet; + packet.PutCString("qModuleInfo:"); + packet.PutCStringAsRawHex8(module_path.c_str()); + packet.PutCString(";"); + const auto &triple = arch_spec.GetTriple().getTriple(); + packet.PutCStringAsRawHex8(triple.c_str()); + + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet.GetString(), response, false) != + PacketResult::Success) return false; -} -bool -GDBRemoteCommunicationClient::RestoreRegisterState (lldb::tid_t tid, uint32_t save_id) -{ - // We use the "m_supports_QSaveRegisterState" variable here because the - // QSaveRegisterState and QRestoreRegisterState packets must both be supported in - // order to be useful - if (m_supports_QSaveRegisterState == eLazyBoolNo) - return false; - - Mutex::Locker locker; - if (GetSequenceMutex (locker, "Didn't get sequence mutex for QRestoreRegisterState.")) - { - const bool thread_suffix_supported = GetThreadSuffixSupported(); - if (thread_suffix_supported || SetCurrentThread(tid)) - { - char packet[256]; - if (thread_suffix_supported) - ::snprintf (packet, sizeof(packet), "QRestoreRegisterState:%u;thread:%4.4" PRIx64 ";", save_id, tid); - else - ::snprintf (packet, sizeof(packet), "QRestoreRegisterState:%u" PRIx64 ";", save_id); - - StringExtractorGDBRemote response; - - if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success) - { - if (response.IsOKResponse()) - { - return true; - } - else if (response.IsUnsupportedResponse()) - { - // This packet isn't supported, don't try calling this packet or - // QSaveRegisterState again... - m_supports_QSaveRegisterState = eLazyBoolNo; - } - } - } - } + if (response.IsErrorResponse()) return false; -} -bool -GDBRemoteCommunicationClient::GetModuleInfo (const FileSpec& module_file_spec, - const lldb_private::ArchSpec& arch_spec, - ModuleSpec &module_spec) -{ - if (!m_supports_qModuleInfo) - return false; + if (response.IsUnsupportedResponse()) { + m_supports_qModuleInfo = false; + return false; + } + + llvm::StringRef name; + llvm::StringRef value; + + module_spec.Clear(); + module_spec.GetFileSpec() = module_file_spec; + + while (response.GetNameColonValue(name, value)) { + if (name == "uuid" || name == "md5") { + StringExtractor extractor(value); + std::string uuid; + extractor.GetHexByteString(uuid); + module_spec.GetUUID().SetFromCString(uuid.c_str(), uuid.size() / 2); + } else if (name == "triple") { + StringExtractor extractor(value); + std::string triple; + extractor.GetHexByteString(triple); + module_spec.GetArchitecture().SetTriple(triple.c_str()); + } else if (name == "file_offset") { + uint64_t ival = 0; + if (!value.getAsInteger(16, ival)) + module_spec.SetObjectOffset(ival); + } else if (name == "file_size") { + uint64_t ival = 0; + if (!value.getAsInteger(16, ival)) + module_spec.SetObjectSize(ival); + } else if (name == "file_path") { + StringExtractor extractor(value); + std::string path; + extractor.GetHexByteString(path); + module_spec.GetFileSpec() = FileSpec(path, false, arch_spec); + } + } + + return true; +} + +static llvm::Optional<ModuleSpec> +ParseModuleSpec(StructuredData::Dictionary *dict) { + ModuleSpec result; + if (!dict) + return llvm::None; + + std::string string; + uint64_t integer; + + if (!dict->GetValueForKeyAsString("uuid", string)) + return llvm::None; + result.GetUUID().SetFromCString(string.c_str(), string.size()); + + if (!dict->GetValueForKeyAsInteger("file_offset", integer)) + return llvm::None; + result.SetObjectOffset(integer); + + if (!dict->GetValueForKeyAsInteger("file_size", integer)) + return llvm::None; + result.SetObjectSize(integer); + + if (!dict->GetValueForKeyAsString("triple", string)) + return llvm::None; + result.GetArchitecture().SetTriple(string.c_str()); + + if (!dict->GetValueForKeyAsString("file_path", string)) + return llvm::None; + result.GetFileSpec() = FileSpec(string, false, result.GetArchitecture()); + + return result; +} + +llvm::Optional<std::vector<ModuleSpec>> +GDBRemoteCommunicationClient::GetModulesInfo( + llvm::ArrayRef<FileSpec> module_file_specs, const llvm::Triple &triple) { + if (!m_supports_jModulesInfo) + return llvm::None; + + JSONArray::SP module_array_sp = std::make_shared<JSONArray>(); + for (const FileSpec &module_file_spec : module_file_specs) { + JSONObject::SP module_sp = std::make_shared<JSONObject>(); + module_array_sp->AppendObject(module_sp); + module_sp->SetObject( + "file", std::make_shared<JSONString>(module_file_spec.GetPath(false))); + module_sp->SetObject("triple", + std::make_shared<JSONString>(triple.getTriple())); + } + StreamString unescaped_payload; + unescaped_payload.PutCString("jModulesInfo:"); + module_array_sp->Write(unescaped_payload); + StreamGDBRemote payload; + payload.PutEscapedBytes(unescaped_payload.GetString().data(), + unescaped_payload.GetSize()); + + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(payload.GetString(), response, false) != + PacketResult::Success || + response.IsErrorResponse()) + return llvm::None; + + if (response.IsUnsupportedResponse()) { + m_supports_jModulesInfo = false; + return llvm::None; + } + + StructuredData::ObjectSP response_object_sp = + StructuredData::ParseJSON(response.GetStringRef()); + if (!response_object_sp) + return llvm::None; + + StructuredData::Array *response_array = response_object_sp->GetAsArray(); + if (!response_array) + return llvm::None; + + std::vector<ModuleSpec> result; + for (size_t i = 0; i < response_array->GetSize(); ++i) { + if (llvm::Optional<ModuleSpec> module_spec = ParseModuleSpec( + response_array->GetItemAtIndex(i)->GetAsDictionary())) + result.push_back(*module_spec); + } + + return result; +} - std::string module_path = module_file_spec.GetPath (false); - if (module_path.empty ()) - return false; +// query the target remote for extended information using the qXfer packet +// +// example: object='features', annex='target.xml', out=<xml output> +// return: 'true' on success +// 'false' on failure (err set) +bool GDBRemoteCommunicationClient::ReadExtFeature( + const lldb_private::ConstString object, + const lldb_private::ConstString annex, std::string &out, + lldb_private::Error &err) { - StreamString packet; - packet.PutCString("qModuleInfo:"); - packet.PutCStringAsRawHex8(module_path.c_str()); - packet.PutCString(";"); - const auto& triple = arch_spec.GetTriple().getTriple(); - packet.PutCStringAsRawHex8(triple.c_str()); + std::stringstream output; + StringExtractorGDBRemote chunk; - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) != PacketResult::Success) - return false; + uint64_t size = GetRemoteMaxPacketSize(); + if (size == 0) + size = 0x1000; + size = size - 1; // Leave space for the 'm' or 'l' character in the response + int offset = 0; + bool active = true; - if (response.IsErrorResponse ()) - return false; + // loop until all data has been read + while (active) { - if (response.IsUnsupportedResponse ()) - { - m_supports_qModuleInfo = false; - return false; - } + // send query extended feature packet + std::stringstream packet; + packet << "qXfer:" << object.AsCString("") + << ":read:" << annex.AsCString("") << ":" << std::hex << offset + << "," << std::hex << size; - std::string name; - std::string value; - bool success; - StringExtractor extractor; + GDBRemoteCommunication::PacketResult res = + SendPacketAndWaitForResponse(packet.str(), chunk, false); - module_spec.Clear (); - module_spec.GetFileSpec () = module_file_spec; - - while (response.GetNameColonValue (name, value)) - { - if (name == "uuid" || name == "md5") - { - extractor.GetStringRef ().swap (value); - extractor.SetFilePos (0); - extractor.GetHexByteString (value); - module_spec.GetUUID().SetFromCString (value.c_str(), value.size() / 2); - } - else if (name == "triple") - { - extractor.GetStringRef ().swap (value); - extractor.SetFilePos (0); - extractor.GetHexByteString (value); - module_spec.GetArchitecture().SetTriple (value.c_str ()); - } - else if (name == "file_offset") - { - const auto ival = StringConvert::ToUInt64 (value.c_str (), 0, 16, &success); - if (success) - module_spec.SetObjectOffset (ival); - } - else if (name == "file_size") - { - const auto ival = StringConvert::ToUInt64 (value.c_str (), 0, 16, &success); - if (success) - module_spec.SetObjectSize (ival); - } - else if (name == "file_path") - { - extractor.GetStringRef ().swap (value); - extractor.SetFilePos (0); - extractor.GetHexByteString (value); - module_spec.GetFileSpec() = FileSpec(value.c_str(), false, arch_spec); - } + if (res != GDBRemoteCommunication::PacketResult::Success) { + err.SetErrorString("Error sending $qXfer packet"); + return false; } - return true; -} + const std::string &str = chunk.GetStringRef(); + if (str.length() == 0) { + // should have some data in chunk + err.SetErrorString("Empty response from $qXfer packet"); + return false; + } -// query the target remote for extended information using the qXfer packet -// -// example: object='features', annex='target.xml', out=<xml output> -// return: 'true' on success -// 'false' on failure (err set) -bool -GDBRemoteCommunicationClient::ReadExtFeature (const lldb_private::ConstString object, - const lldb_private::ConstString annex, - std::string & out, - lldb_private::Error & err) { - - std::stringstream output; - StringExtractorGDBRemote chunk; - - uint64_t size = GetRemoteMaxPacketSize(); - if (size == 0) - size = 0x1000; - size = size - 1; // Leave space for the 'm' or 'l' character in the response - int offset = 0; - bool active = true; - - // loop until all data has been read - while ( active ) { - - // send query extended feature packet - std::stringstream packet; - packet << "qXfer:" - << object.AsCString("") << ":read:" - << annex.AsCString("") << ":" - << std::hex << offset << "," - << std::hex << size; - - GDBRemoteCommunication::PacketResult res = - SendPacketAndWaitForResponse( packet.str().c_str(), - chunk, - false ); - - if ( res != GDBRemoteCommunication::PacketResult::Success ) { - err.SetErrorString( "Error sending $qXfer packet" ); - return false; - } + // check packet code + switch (str[0]) { + // last chunk + case ('l'): + active = false; + LLVM_FALLTHROUGH; - const std::string & str = chunk.GetStringRef( ); - if ( str.length() == 0 ) { - // should have some data in chunk - err.SetErrorString( "Empty response from $qXfer packet" ); - return false; - } + // more chunks + case ('m'): + if (str.length() > 1) + output << &str[1]; + offset += size; + break; - // check packet code - switch ( str[0] ) { - // last chunk - case ( 'l' ): - active = false; - LLVM_FALLTHROUGH; - - // more chunks - case ( 'm' ) : - if ( str.length() > 1 ) - output << &str[1]; - offset += size; - break; - - // unknown chunk - default: - err.SetErrorString( "Invalid continuation code from $qXfer packet" ); - return false; - } + // unknown chunk + default: + err.SetErrorString("Invalid continuation code from $qXfer packet"); + return false; } + } - out = output.str( ); - err.Success( ); - return true; + out = output.str(); + err.Success(); + return true; } // Notify the target that gdb is prepared to serve symbol lookup requests. // packet: "qSymbol::" // reply: // OK The target does not need to look up any (more) symbols. -// qSymbol:<sym_name> The target requests the value of symbol sym_name (hex encoded). -// LLDB may provide the value by sending another qSymbol packet +// qSymbol:<sym_name> The target requests the value of symbol sym_name (hex +// encoded). +// LLDB may provide the value by sending another qSymbol +// packet // in the form of"qSymbol:<sym_value>:<sym_name>". // // Three examples: // // lldb sends: qSymbol:: // lldb receives: OK -// Remote gdb stub does not need to know the addresses of any symbols, lldb does not +// Remote gdb stub does not need to know the addresses of any symbols, lldb +// does not // need to ask again in this session. // // lldb sends: qSymbol:: // lldb receives: qSymbol:64697370617463685f71756575655f6f666673657473 // lldb sends: qSymbol::64697370617463685f71756575655f6f666673657473 // lldb receives: OK -// Remote gdb stub asks for address of 'dispatch_queue_offsets'. lldb does not know -// the address at this time. lldb needs to send qSymbol:: again when it has more +// Remote gdb stub asks for address of 'dispatch_queue_offsets'. lldb does +// not know +// the address at this time. lldb needs to send qSymbol:: again when it has +// more // solibs loaded. // // lldb sends: qSymbol:: // lldb receives: qSymbol:64697370617463685f71756575655f6f666673657473 // lldb sends: qSymbol:2bc97554:64697370617463685f71756575655f6f666673657473 // lldb receives: OK -// Remote gdb stub asks for address of 'dispatch_queue_offsets'. lldb says that it -// is at address 0x2bc97554. Remote gdb stub sends 'OK' indicating that it does not +// Remote gdb stub asks for address of 'dispatch_queue_offsets'. lldb says +// that it +// is at address 0x2bc97554. Remote gdb stub sends 'OK' indicating that it +// does not // need any more symbols. lldb does not need to ask again in this session. -void -GDBRemoteCommunicationClient::ServeSymbolLookups(lldb_private::Process *process) -{ - // Set to true once we've resolved a symbol to an address for the remote stub. - // If we get an 'OK' response after this, the remote stub doesn't need any more - // symbols and we can stop asking. - bool symbol_response_provided = false; - - // Is this the inital qSymbol:: packet? - bool first_qsymbol_query = true; - - if (m_supports_qSymbol && m_qSymbol_requests_done == false) - { - Mutex::Locker locker; - if (GetSequenceMutex(locker, "GDBRemoteCommunicationClient::ServeSymbolLookups() failed due to not getting the sequence mutex")) - { - StreamString packet; - packet.PutCString ("qSymbol::"); - StringExtractorGDBRemote response; - while (SendPacketAndWaitForResponseNoLock(packet.GetData(), packet.GetSize(), response) == PacketResult::Success) - { - if (response.IsOKResponse()) - { - if (symbol_response_provided || first_qsymbol_query) - { - m_qSymbol_requests_done = true; - } - - // We are done serving symbols requests - return; - } - first_qsymbol_query = false; +void GDBRemoteCommunicationClient::ServeSymbolLookups( + lldb_private::Process *process) { + // Set to true once we've resolved a symbol to an address for the remote stub. + // If we get an 'OK' response after this, the remote stub doesn't need any + // more + // symbols and we can stop asking. + bool symbol_response_provided = false; + + // Is this the initial qSymbol:: packet? + bool first_qsymbol_query = true; + + if (m_supports_qSymbol && m_qSymbol_requests_done == false) { + Lock lock(*this, false); + if (lock) { + StreamString packet; + packet.PutCString("qSymbol::"); + StringExtractorGDBRemote response; + while (SendPacketAndWaitForResponseNoLock(packet.GetString(), response) == + PacketResult::Success) { + if (response.IsOKResponse()) { + if (symbol_response_provided || first_qsymbol_query) { + m_qSymbol_requests_done = true; + } + + // We are done serving symbols requests + return; + } + first_qsymbol_query = false; + + if (response.IsUnsupportedResponse()) { + // qSymbol is not supported by the current GDB server we are connected + // to + m_supports_qSymbol = false; + return; + } else { + llvm::StringRef response_str(response.GetStringRef()); + if (response_str.startswith("qSymbol:")) { + response.SetFilePos(strlen("qSymbol:")); + std::string symbol_name; + if (response.GetHexByteString(symbol_name)) { + if (symbol_name.empty()) + return; + + addr_t symbol_load_addr = LLDB_INVALID_ADDRESS; + lldb_private::SymbolContextList sc_list; + if (process->GetTarget().GetImages().FindSymbolsWithNameAndType( + ConstString(symbol_name), eSymbolTypeAny, sc_list)) { + const size_t num_scs = sc_list.GetSize(); + for (size_t sc_idx = 0; + sc_idx < num_scs && + symbol_load_addr == LLDB_INVALID_ADDRESS; + ++sc_idx) { + SymbolContext sc; + if (sc_list.GetContextAtIndex(sc_idx, sc)) { + if (sc.symbol) { + switch (sc.symbol->GetType()) { + case eSymbolTypeInvalid: + case eSymbolTypeAbsolute: + case eSymbolTypeUndefined: + case eSymbolTypeSourceFile: + case eSymbolTypeHeaderFile: + case eSymbolTypeObjectFile: + case eSymbolTypeCommonBlock: + case eSymbolTypeBlock: + case eSymbolTypeLocal: + case eSymbolTypeParam: + case eSymbolTypeVariable: + case eSymbolTypeVariableType: + case eSymbolTypeLineEntry: + case eSymbolTypeLineHeader: + case eSymbolTypeScopeBegin: + case eSymbolTypeScopeEnd: + case eSymbolTypeAdditional: + case eSymbolTypeCompiler: + case eSymbolTypeInstrumentation: + case eSymbolTypeTrampoline: + break; - if (response.IsUnsupportedResponse()) - { - // qSymbol is not supported by the current GDB server we are connected to - m_supports_qSymbol = false; - return; - } - else - { - llvm::StringRef response_str(response.GetStringRef()); - if (response_str.startswith("qSymbol:")) - { - response.SetFilePos(strlen("qSymbol:")); - std::string symbol_name; - if (response.GetHexByteString(symbol_name)) - { - if (symbol_name.empty()) - return; - - addr_t symbol_load_addr = LLDB_INVALID_ADDRESS; - lldb_private::SymbolContextList sc_list; - if (process->GetTarget().GetImages().FindSymbolsWithNameAndType(ConstString(symbol_name), eSymbolTypeAny, sc_list)) - { - const size_t num_scs = sc_list.GetSize(); - for (size_t sc_idx=0; sc_idx<num_scs && symbol_load_addr == LLDB_INVALID_ADDRESS; ++sc_idx) - { - SymbolContext sc; - if (sc_list.GetContextAtIndex(sc_idx, sc)) - { - if (sc.symbol) - { - switch (sc.symbol->GetType()) - { - case eSymbolTypeInvalid: - case eSymbolTypeAbsolute: - case eSymbolTypeUndefined: - case eSymbolTypeSourceFile: - case eSymbolTypeHeaderFile: - case eSymbolTypeObjectFile: - case eSymbolTypeCommonBlock: - case eSymbolTypeBlock: - case eSymbolTypeLocal: - case eSymbolTypeParam: - case eSymbolTypeVariable: - case eSymbolTypeVariableType: - case eSymbolTypeLineEntry: - case eSymbolTypeLineHeader: - case eSymbolTypeScopeBegin: - case eSymbolTypeScopeEnd: - case eSymbolTypeAdditional: - case eSymbolTypeCompiler: - case eSymbolTypeInstrumentation: - case eSymbolTypeTrampoline: - break; - - case eSymbolTypeCode: - case eSymbolTypeResolver: - case eSymbolTypeData: - case eSymbolTypeRuntime: - case eSymbolTypeException: - case eSymbolTypeObjCClass: - case eSymbolTypeObjCMetaClass: - case eSymbolTypeObjCIVar: - case eSymbolTypeReExported: - symbol_load_addr = sc.symbol->GetLoadAddress(&process->GetTarget()); - break; - } - } - } - } - } - // This is the normal path where our symbol lookup was successful and we want - // to send a packet with the new symbol value and see if another lookup needs to be - // done. - - // Change "packet" to contain the requested symbol value and name - packet.Clear(); - packet.PutCString("qSymbol:"); - if (symbol_load_addr != LLDB_INVALID_ADDRESS) - { - packet.Printf("%" PRIx64, symbol_load_addr); - symbol_response_provided = true; - } - else - { - symbol_response_provided = false; - } - packet.PutCString(":"); - packet.PutBytesAsRawHex8(symbol_name.data(), symbol_name.size()); - continue; // go back to the while loop and send "packet" and wait for another response - } + case eSymbolTypeCode: + case eSymbolTypeResolver: + case eSymbolTypeData: + case eSymbolTypeRuntime: + case eSymbolTypeException: + case eSymbolTypeObjCClass: + case eSymbolTypeObjCMetaClass: + case eSymbolTypeObjCIVar: + case eSymbolTypeReExported: + symbol_load_addr = + sc.symbol->GetLoadAddress(&process->GetTarget()); + break; + } } + } } - } - // If we make it here, the symbol request packet response wasn't valid or - // our symbol lookup failed so we must abort - return; + } + // This is the normal path where our symbol lookup was successful + // and we want + // to send a packet with the new symbol value and see if another + // lookup needs to be + // done. + + // Change "packet" to contain the requested symbol value and name + packet.Clear(); + packet.PutCString("qSymbol:"); + if (symbol_load_addr != LLDB_INVALID_ADDRESS) { + packet.Printf("%" PRIx64, symbol_load_addr); + symbol_response_provided = true; + } else { + symbol_response_provided = false; + } + packet.PutCString(":"); + packet.PutBytesAsRawHex8(symbol_name.data(), symbol_name.size()); + continue; // go back to the while loop and send "packet" and wait + // for another response + } + } + } + } + // If we make it here, the symbol request packet response wasn't valid or + // our symbol lookup failed so we must abort + return; + + } else if (Log *log = ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet( + GDBR_LOG_PROCESS | GDBR_LOG_PACKETS)) { + log->Printf( + "GDBRemoteCommunicationClient::%s: Didn't get sequence mutex.", + __FUNCTION__); + } + } +} + +StructuredData::Array * +GDBRemoteCommunicationClient::GetSupportedStructuredDataPlugins() { + if (!m_supported_async_json_packets_is_valid) { + // Query the server for the array of supported asynchronous JSON + // packets. + m_supported_async_json_packets_is_valid = true; - } - } -} + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + // Poll it now. + StringExtractorGDBRemote response; + const bool send_async = false; + if (SendPacketAndWaitForResponse("qStructuredDataPlugins", response, + send_async) == PacketResult::Success) { + m_supported_async_json_packets_sp = + StructuredData::ParseJSON(response.GetStringRef()); + if (m_supported_async_json_packets_sp && + !m_supported_async_json_packets_sp->GetAsArray()) { + // We were returned something other than a JSON array. This + // is invalid. Clear it out. + if (log) + log->Printf("GDBRemoteCommunicationClient::%s(): " + "QSupportedAsyncJSONPackets returned invalid " + "result: %s", + __FUNCTION__, response.GetStringRef().c_str()); + m_supported_async_json_packets_sp.reset(); + } + } else { + if (log) + log->Printf("GDBRemoteCommunicationClient::%s(): " + "QSupportedAsyncJSONPackets unsupported", + __FUNCTION__); + } + + if (log && m_supported_async_json_packets_sp) { + StreamString stream; + m_supported_async_json_packets_sp->Dump(stream); + log->Printf("GDBRemoteCommunicationClient::%s(): supported async " + "JSON packets: %s", + __FUNCTION__, stream.GetData()); + } + } + + return m_supported_async_json_packets_sp + ? m_supported_async_json_packets_sp->GetAsArray() + : nullptr; +} + +Error GDBRemoteCommunicationClient::ConfigureRemoteStructuredData( + const ConstString &type_name, const StructuredData::ObjectSP &config_sp) { + Error error; + + if (type_name.GetLength() == 0) { + error.SetErrorString("invalid type_name argument"); + return error; + } + + // Build command: Configure{type_name}: serialized config + // data. + StreamGDBRemote stream; + stream.PutCString("QConfigure"); + stream.PutCString(type_name.AsCString()); + stream.PutChar(':'); + if (config_sp) { + // Gather the plain-text version of the configuration data. + StreamString unescaped_stream; + config_sp->Dump(unescaped_stream); + unescaped_stream.Flush(); + + // Add it to the stream in escaped fashion. + stream.PutEscapedBytes(unescaped_stream.GetString().data(), + unescaped_stream.GetSize()); + } + stream.Flush(); + + // Send the packet. + const bool send_async = false; + StringExtractorGDBRemote response; + auto result = + SendPacketAndWaitForResponse(stream.GetString(), response, send_async); + if (result == PacketResult::Success) { + // We failed if the config result comes back other than OK. + if (strcmp(response.GetStringRef().c_str(), "OK") == 0) { + // Okay! + error.Clear(); + } else { + error.SetErrorStringWithFormat("configuring StructuredData feature " + "%s failed with error %s", + type_name.AsCString(), + response.GetStringRef().c_str()); + } + } else { + // Can we get more data here on the failure? + error.SetErrorStringWithFormat("configuring StructuredData feature %s " + "failed when sending packet: " + "PacketResult=%d", + type_name.AsCString(), (int)result); + } + return error; +} + +void GDBRemoteCommunicationClient::OnRunPacketSent(bool first) { + GDBRemoteClientBase::OnRunPacketSent(first); + m_curr_tid = LLDB_INVALID_THREAD_ID; +} diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index 096c4cf..83162a6 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -10,8 +10,11 @@ #ifndef liblldb_GDBRemoteCommunicationClient_h_ #define liblldb_GDBRemoteCommunicationClient_h_ +#include "GDBRemoteClientBase.h" + // C Includes // C++ Includes +#include <chrono> #include <map> #include <mutex> #include <string> @@ -23,660 +26,563 @@ #include "lldb/Core/StructuredData.h" #include "lldb/Target/Process.h" -#include "GDBRemoteCommunication.h" +#include "llvm/ADT/Optional.h" namespace lldb_private { namespace process_gdb_remote { -class GDBRemoteCommunicationClient : public GDBRemoteCommunication -{ +class GDBRemoteCommunicationClient : public GDBRemoteClientBase { public: - GDBRemoteCommunicationClient(); - - ~GDBRemoteCommunicationClient() override; - - //------------------------------------------------------------------ - // After connecting, send the handshake to the server to make sure - // we are communicating with it. - //------------------------------------------------------------------ - bool - HandshakeWithServer (Error *error_ptr); - - PacketResult - SendPacketAndWaitForResponse (const char *send_payload, - StringExtractorGDBRemote &response, - bool send_async); - - PacketResult - SendPacketAndWaitForResponse (const char *send_payload, - size_t send_length, - StringExtractorGDBRemote &response, - bool send_async); - - // For packets which specify a range of output to be returned, - // return all of the output via a series of request packets of the form - // <prefix>0,<size> - // <prefix><size>,<size> - // <prefix><size>*2,<size> - // <prefix><size>*3,<size> - // ... - // until a "$l..." packet is received, indicating the end. - // (size is in hex; this format is used by a standard gdbserver to - // return the given portion of the output specified by <prefix>; - // for example, "qXfer:libraries-svr4:read::fff,1000" means - // "return a chunk of the xml description file for shared - // library load addresses, where the chunk starts at offset 0xfff - // and continues for 0x1000 bytes"). - // Concatenate the resulting server response packets together and - // return in response_string. If any packet fails, the return value - // indicates that failure and the returned string value is undefined. - PacketResult - SendPacketsAndConcatenateResponses (const char *send_payload_prefix, - std::string &response_string); - - lldb::StateType - SendContinuePacketAndWaitForResponse (ProcessGDBRemote *process, - const char *packet_payload, - size_t packet_length, - StringExtractorGDBRemote &response); - - bool - SendvContPacket (ProcessGDBRemote *process, - const char *payload, - size_t packet_length, - StringExtractorGDBRemote &response); - - bool - GetThreadSuffixSupported () override; - - // This packet is usually sent first and the boolean return value - // indicates if the packet was send and any response was received - // even in the response is UNIMPLEMENTED. If the packet failed to - // get a response, then false is returned. This quickly tells us - // if we were able to connect and communicate with the remote GDB - // server - bool - QueryNoAckModeSupported (); - - void - GetListThreadsInStopReplySupported (); - - bool - SendAsyncSignal (int signo); - - bool - SendInterrupt (Mutex::Locker &locker, - uint32_t seconds_to_wait_for_stop, - bool &timed_out); - - lldb::pid_t - GetCurrentProcessID (bool allow_lazy = true); - - bool - GetLaunchSuccess (std::string &error_str); - - bool - LaunchGDBServer (const char *remote_accept_hostname, - lldb::pid_t &pid, - uint16_t &port, - std::string &socket_name); - - size_t - QueryGDBServer (std::vector<std::pair<uint16_t, std::string>>& connection_urls); - - bool - KillSpawnedProcess (lldb::pid_t pid); - - //------------------------------------------------------------------ - /// Sends a GDB remote protocol 'A' packet that delivers program - /// arguments to the remote server. - /// - /// @param[in] argv - /// A NULL terminated array of const C strings to use as the - /// arguments. - /// - /// @return - /// Zero if the response was "OK", a positive value if the - /// the response was "Exx" where xx are two hex digits, or - /// -1 if the call is unsupported or any other unexpected - /// response was received. - //------------------------------------------------------------------ - int - SendArgumentsPacket (const ProcessLaunchInfo &launch_info); - - //------------------------------------------------------------------ - /// Sends a "QEnvironment:NAME=VALUE" packet that will build up the - /// environment that will get used when launching an application - /// in conjunction with the 'A' packet. This function can be called - /// multiple times in a row in order to pass on the desired - /// environment that the inferior should be launched with. - /// - /// @param[in] name_equal_value - /// A NULL terminated C string that contains a single environment - /// in the format "NAME=VALUE". - /// - /// @return - /// Zero if the response was "OK", a positive value if the - /// the response was "Exx" where xx are two hex digits, or - /// -1 if the call is unsupported or any other unexpected - /// response was received. - //------------------------------------------------------------------ - int - SendEnvironmentPacket (char const *name_equal_value); - - int - SendLaunchArchPacket (const char *arch); - - int - SendLaunchEventDataPacket(const char *data, bool *was_supported = nullptr); - - //------------------------------------------------------------------ - /// Sends a "vAttach:PID" where PID is in hex. - /// - /// @param[in] pid - /// A process ID for the remote gdb server to attach to. - /// - /// @param[out] response - /// The response received from the gdb server. If the return - /// value is zero, \a response will contain a stop reply - /// packet. - /// - /// @return - /// Zero if the attach was successful, or an error indicating - /// an error code. - //------------------------------------------------------------------ - int - SendAttach (lldb::pid_t pid, - StringExtractorGDBRemote& response); - - //------------------------------------------------------------------ - /// Sends a GDB remote protocol 'I' packet that delivers stdin - /// data to the remote process. - /// - /// @param[in] data - /// A pointer to stdin data. - /// - /// @param[in] data_len - /// The number of bytes available at \a data. - /// - /// @return - /// Zero if the attach was successful, or an error indicating - /// an error code. - //------------------------------------------------------------------ - int - SendStdinNotification(const char* data, size_t data_len); - - //------------------------------------------------------------------ - /// Sets the path to use for stdin/out/err for a process - /// that will be launched with the 'A' packet. - /// - /// @param[in] path - /// The path to use for stdin/out/err - /// - /// @return - /// Zero if the for success, or an error code for failure. - //------------------------------------------------------------------ - int - SetSTDIN(const FileSpec &file_spec); - int - SetSTDOUT(const FileSpec &file_spec); - int - SetSTDERR(const FileSpec &file_spec); - - //------------------------------------------------------------------ - /// Sets the disable ASLR flag to \a enable for a process that will - /// be launched with the 'A' packet. - /// - /// @param[in] enable - /// A boolean value indicating whether to disable ASLR or not. - /// - /// @return - /// Zero if the for success, or an error code for failure. - //------------------------------------------------------------------ - int - SetDisableASLR (bool enable); - - //------------------------------------------------------------------ - /// Sets the DetachOnError flag to \a enable for the process controlled by the stub. - /// - /// @param[in] enable - /// A boolean value indicating whether to detach on error or not. - /// - /// @return - /// Zero if the for success, or an error code for failure. - //------------------------------------------------------------------ - int - SetDetachOnError (bool enable); - - //------------------------------------------------------------------ - /// Sets the working directory to \a path for a process that will - /// be launched with the 'A' packet for non platform based - /// connections. If this packet is sent to a GDB server that - /// implements the platform, it will change the current working - /// directory for the platform process. - /// - /// @param[in] working_dir - /// The path to a directory to use when launching our process - /// - /// @return - /// Zero if the for success, or an error code for failure. - //------------------------------------------------------------------ - int - SetWorkingDir(const FileSpec &working_dir); - - //------------------------------------------------------------------ - /// Gets the current working directory of a remote platform GDB - /// server. - /// - /// @param[out] working_dir - /// The current working directory on the remote platform. - /// - /// @return - /// Boolean for success - //------------------------------------------------------------------ - bool - GetWorkingDir(FileSpec &working_dir); - - lldb::addr_t - AllocateMemory (size_t size, uint32_t permissions); - - bool - DeallocateMemory (lldb::addr_t addr); - - Error - Detach (bool keep_stopped); - - Error - GetMemoryRegionInfo (lldb::addr_t addr, MemoryRegionInfo &range_info); - - Error - GetWatchpointSupportInfo (uint32_t &num); - - Error - GetWatchpointSupportInfo (uint32_t &num, bool& after, const ArchSpec &arch); - - Error - GetWatchpointsTriggerAfterInstruction (bool &after, const ArchSpec &arch); - - const ArchSpec & - GetHostArchitecture (); - - uint32_t - GetHostDefaultPacketTimeout(); - - const ArchSpec & - GetProcessArchitecture (); - - void - GetRemoteQSupported(); - - bool - GetVContSupported (char flavor); - - bool - GetpPacketSupported (lldb::tid_t tid); - - bool - GetxPacketSupported (); - - bool - GetVAttachOrWaitSupported (); - - bool - GetSyncThreadStateSupported(); - - void - ResetDiscoverableSettings (bool did_exec); - - bool - GetHostInfo (bool force = false); - - bool - GetDefaultThreadId (lldb::tid_t &tid); - - bool - GetOSVersion (uint32_t &major, - uint32_t &minor, - uint32_t &update); - - bool - GetOSBuildString (std::string &s); - - bool - GetOSKernelDescription (std::string &s); - - ArchSpec - GetSystemArchitecture (); - - bool - GetHostname (std::string &s); - - lldb::addr_t - GetShlibInfoAddr(); - - bool - GetSupportsThreadSuffix (); - - bool - GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info); - - uint32_t - FindProcesses (const ProcessInstanceInfoMatch &process_match_info, - ProcessInstanceInfoList &process_infos); - - bool - GetUserName (uint32_t uid, std::string &name); - - bool - GetGroupName (uint32_t gid, std::string &name); - - bool - HasFullVContSupport () - { - return GetVContSupported ('A'); - } + GDBRemoteCommunicationClient(); + + ~GDBRemoteCommunicationClient() override; + + //------------------------------------------------------------------ + // After connecting, send the handshake to the server to make sure + // we are communicating with it. + //------------------------------------------------------------------ + bool HandshakeWithServer(Error *error_ptr); + + // For packets which specify a range of output to be returned, + // return all of the output via a series of request packets of the form + // <prefix>0,<size> + // <prefix><size>,<size> + // <prefix><size>*2,<size> + // <prefix><size>*3,<size> + // ... + // until a "$l..." packet is received, indicating the end. + // (size is in hex; this format is used by a standard gdbserver to + // return the given portion of the output specified by <prefix>; + // for example, "qXfer:libraries-svr4:read::fff,1000" means + // "return a chunk of the xml description file for shared + // library load addresses, where the chunk starts at offset 0xfff + // and continues for 0x1000 bytes"). + // Concatenate the resulting server response packets together and + // return in response_string. If any packet fails, the return value + // indicates that failure and the returned string value is undefined. + PacketResult + SendPacketsAndConcatenateResponses(const char *send_payload_prefix, + std::string &response_string); + + bool GetThreadSuffixSupported(); + + // This packet is usually sent first and the boolean return value + // indicates if the packet was send and any response was received + // even in the response is UNIMPLEMENTED. If the packet failed to + // get a response, then false is returned. This quickly tells us + // if we were able to connect and communicate with the remote GDB + // server + bool QueryNoAckModeSupported(); + + void GetListThreadsInStopReplySupported(); + + lldb::pid_t GetCurrentProcessID(bool allow_lazy = true); + + bool GetLaunchSuccess(std::string &error_str); + + bool LaunchGDBServer(const char *remote_accept_hostname, lldb::pid_t &pid, + uint16_t &port, std::string &socket_name); + + size_t QueryGDBServer( + std::vector<std::pair<uint16_t, std::string>> &connection_urls); + + bool KillSpawnedProcess(lldb::pid_t pid); + + //------------------------------------------------------------------ + /// Sends a GDB remote protocol 'A' packet that delivers program + /// arguments to the remote server. + /// + /// @param[in] argv + /// A NULL terminated array of const C strings to use as the + /// arguments. + /// + /// @return + /// Zero if the response was "OK", a positive value if the + /// the response was "Exx" where xx are two hex digits, or + /// -1 if the call is unsupported or any other unexpected + /// response was received. + //------------------------------------------------------------------ + int SendArgumentsPacket(const ProcessLaunchInfo &launch_info); + + //------------------------------------------------------------------ + /// Sends a "QEnvironment:NAME=VALUE" packet that will build up the + /// environment that will get used when launching an application + /// in conjunction with the 'A' packet. This function can be called + /// multiple times in a row in order to pass on the desired + /// environment that the inferior should be launched with. + /// + /// @param[in] name_equal_value + /// A NULL terminated C string that contains a single environment + /// in the format "NAME=VALUE". + /// + /// @return + /// Zero if the response was "OK", a positive value if the + /// the response was "Exx" where xx are two hex digits, or + /// -1 if the call is unsupported or any other unexpected + /// response was received. + //------------------------------------------------------------------ + int SendEnvironmentPacket(char const *name_equal_value); + + int SendLaunchArchPacket(const char *arch); + + int SendLaunchEventDataPacket(const char *data, + bool *was_supported = nullptr); + + //------------------------------------------------------------------ + /// Sends a "vAttach:PID" where PID is in hex. + /// + /// @param[in] pid + /// A process ID for the remote gdb server to attach to. + /// + /// @param[out] response + /// The response received from the gdb server. If the return + /// value is zero, \a response will contain a stop reply + /// packet. + /// + /// @return + /// Zero if the attach was successful, or an error indicating + /// an error code. + //------------------------------------------------------------------ + int SendAttach(lldb::pid_t pid, StringExtractorGDBRemote &response); + + //------------------------------------------------------------------ + /// Sends a GDB remote protocol 'I' packet that delivers stdin + /// data to the remote process. + /// + /// @param[in] data + /// A pointer to stdin data. + /// + /// @param[in] data_len + /// The number of bytes available at \a data. + /// + /// @return + /// Zero if the attach was successful, or an error indicating + /// an error code. + //------------------------------------------------------------------ + int SendStdinNotification(const char *data, size_t data_len); + + //------------------------------------------------------------------ + /// Sets the path to use for stdin/out/err for a process + /// that will be launched with the 'A' packet. + /// + /// @param[in] path + /// The path to use for stdin/out/err + /// + /// @return + /// Zero if the for success, or an error code for failure. + //------------------------------------------------------------------ + int SetSTDIN(const FileSpec &file_spec); + int SetSTDOUT(const FileSpec &file_spec); + int SetSTDERR(const FileSpec &file_spec); + + //------------------------------------------------------------------ + /// Sets the disable ASLR flag to \a enable for a process that will + /// be launched with the 'A' packet. + /// + /// @param[in] enable + /// A boolean value indicating whether to disable ASLR or not. + /// + /// @return + /// Zero if the for success, or an error code for failure. + //------------------------------------------------------------------ + int SetDisableASLR(bool enable); + + //------------------------------------------------------------------ + /// Sets the DetachOnError flag to \a enable for the process controlled by the + /// stub. + /// + /// @param[in] enable + /// A boolean value indicating whether to detach on error or not. + /// + /// @return + /// Zero if the for success, or an error code for failure. + //------------------------------------------------------------------ + int SetDetachOnError(bool enable); + + //------------------------------------------------------------------ + /// Sets the working directory to \a path for a process that will + /// be launched with the 'A' packet for non platform based + /// connections. If this packet is sent to a GDB server that + /// implements the platform, it will change the current working + /// directory for the platform process. + /// + /// @param[in] working_dir + /// The path to a directory to use when launching our process + /// + /// @return + /// Zero if the for success, or an error code for failure. + //------------------------------------------------------------------ + int SetWorkingDir(const FileSpec &working_dir); + + //------------------------------------------------------------------ + /// Gets the current working directory of a remote platform GDB + /// server. + /// + /// @param[out] working_dir + /// The current working directory on the remote platform. + /// + /// @return + /// Boolean for success + //------------------------------------------------------------------ + bool GetWorkingDir(FileSpec &working_dir); + + lldb::addr_t AllocateMemory(size_t size, uint32_t permissions); + + bool DeallocateMemory(lldb::addr_t addr); + + Error Detach(bool keep_stopped); + + Error GetMemoryRegionInfo(lldb::addr_t addr, MemoryRegionInfo &range_info); + + Error GetWatchpointSupportInfo(uint32_t &num); + + Error GetWatchpointSupportInfo(uint32_t &num, bool &after, + const ArchSpec &arch); + + Error GetWatchpointsTriggerAfterInstruction(bool &after, + const ArchSpec &arch); + + const ArchSpec &GetHostArchitecture(); + + std::chrono::seconds GetHostDefaultPacketTimeout(); + + const ArchSpec &GetProcessArchitecture(); + + void GetRemoteQSupported(); - bool - HasAnyVContSupport () - { - return GetVContSupported ('a'); - } - - bool - GetStopReply (StringExtractorGDBRemote &response); - - bool - GetThreadStopInfo (lldb::tid_t tid, - StringExtractorGDBRemote &response); - - bool - SupportsGDBStoppointPacket (GDBStoppointType type) - { - switch (type) - { - case eBreakpointSoftware: return m_supports_z0; - case eBreakpointHardware: return m_supports_z1; - case eWatchpointWrite: return m_supports_z2; - case eWatchpointRead: return m_supports_z3; - case eWatchpointReadWrite: return m_supports_z4; - default: return false; - } - } + bool GetVContSupported(char flavor); - uint8_t - SendGDBStoppointTypePacket (GDBStoppointType type, // Type of breakpoint or watchpoint - bool insert, // Insert or remove? - lldb::addr_t addr, // Address of breakpoint or watchpoint - uint32_t length); // Byte Size of breakpoint or watchpoint - - bool - SetNonStopMode (const bool enable); - - void - TestPacketSpeed (const uint32_t num_packets, uint32_t max_send, uint32_t max_recv, bool json, Stream &strm); - - // This packet is for testing the speed of the interface only. Both - // the client and server need to support it, but this allows us to - // measure the packet speed without any other work being done on the - // other end and avoids any of that work affecting the packet send - // and response times. - bool - SendSpeedTestPacket (uint32_t send_size, - uint32_t recv_size); - - bool - SetCurrentThread (uint64_t tid); - - bool - SetCurrentThreadForRun (uint64_t tid); - - bool - GetQXferAuxvReadSupported (); - - bool - GetQXferLibrariesReadSupported (); - - bool - GetQXferLibrariesSVR4ReadSupported (); - - uint64_t - GetRemoteMaxPacketSize(); - - bool - GetEchoSupported (); - - bool - GetAugmentedLibrariesSVR4ReadSupported (); - - bool - GetQXferFeaturesReadSupported (); - - LazyBool - SupportsAllocDeallocMemory () // const - { - // Uncomment this to have lldb pretend the debug server doesn't respond to alloc/dealloc memory packets. - // m_supports_alloc_dealloc_memory = lldb_private::eLazyBoolNo; - return m_supports_alloc_dealloc_memory; - } + bool GetpPacketSupported(lldb::tid_t tid); + + bool GetxPacketSupported(); + + bool GetVAttachOrWaitSupported(); + + bool GetSyncThreadStateSupported(); + + void ResetDiscoverableSettings(bool did_exec); + + bool GetHostInfo(bool force = false); + + bool GetDefaultThreadId(lldb::tid_t &tid); + + bool GetOSVersion(uint32_t &major, uint32_t &minor, uint32_t &update); + + bool GetOSBuildString(std::string &s); + + bool GetOSKernelDescription(std::string &s); + + ArchSpec GetSystemArchitecture(); + + bool GetHostname(std::string &s); + + lldb::addr_t GetShlibInfoAddr(); + + bool GetSupportsThreadSuffix(); + + bool GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info); - size_t - GetCurrentThreadIDs (std::vector<lldb::tid_t> &thread_ids, - bool &sequence_mutex_unavailable); - - bool - GetInterruptWasSent () const - { - return m_interrupt_sent; + uint32_t FindProcesses(const ProcessInstanceInfoMatch &process_match_info, + ProcessInstanceInfoList &process_infos); + + bool GetUserName(uint32_t uid, std::string &name); + + bool GetGroupName(uint32_t gid, std::string &name); + + bool HasFullVContSupport() { return GetVContSupported('A'); } + + bool HasAnyVContSupport() { return GetVContSupported('a'); } + + bool GetStopReply(StringExtractorGDBRemote &response); + + bool GetThreadStopInfo(lldb::tid_t tid, StringExtractorGDBRemote &response); + + bool SupportsGDBStoppointPacket(GDBStoppointType type) { + switch (type) { + case eBreakpointSoftware: + return m_supports_z0; + case eBreakpointHardware: + return m_supports_z1; + case eWatchpointWrite: + return m_supports_z2; + case eWatchpointRead: + return m_supports_z3; + case eWatchpointReadWrite: + return m_supports_z4; + default: + return false; } - - lldb::user_id_t - OpenFile (const FileSpec& file_spec, uint32_t flags, mode_t mode, Error &error); - - bool - CloseFile (lldb::user_id_t fd, Error &error); - - lldb::user_id_t - GetFileSize (const FileSpec& file_spec); - - Error - GetFilePermissions(const FileSpec &file_spec, uint32_t &file_permissions); - - Error - SetFilePermissions(const FileSpec &file_spec, uint32_t file_permissions); - - uint64_t - ReadFile (lldb::user_id_t fd, - uint64_t offset, - void *dst, - uint64_t dst_len, - Error &error); - - uint64_t - WriteFile (lldb::user_id_t fd, - uint64_t offset, - const void* src, - uint64_t src_len, - Error &error); - - Error - CreateSymlink(const FileSpec &src, - const FileSpec &dst); - - Error - Unlink(const FileSpec &file_spec); - - Error - MakeDirectory(const FileSpec &file_spec, uint32_t mode); - - bool - GetFileExists (const FileSpec& file_spec); - - Error - RunShellCommand(const char *command, // Shouldn't be nullptr - const FileSpec &working_dir, // Pass empty FileSpec to use the current working directory - int *status_ptr, // Pass nullptr if you don't want the process exit status - int *signo_ptr, // Pass nullptr if you don't want the signal that caused the process to exit - std::string *command_output, // Pass nullptr if you don't want the command output - uint32_t timeout_sec); // Timeout in seconds to wait for shell program to finish - - bool - CalculateMD5 (const FileSpec& file_spec, uint64_t &high, uint64_t &low); - - std::string - HarmonizeThreadIdsForProfileData (ProcessGDBRemote *process, - StringExtractorGDBRemote &inputStringExtractor); - - bool - ReadRegister(lldb::tid_t tid, - uint32_t reg_num, // Must be the eRegisterKindProcessPlugin register number, to be sent to the remote - StringExtractorGDBRemote &response); - - bool - ReadAllRegisters (lldb::tid_t tid, - StringExtractorGDBRemote &response); - - bool - SaveRegisterState (lldb::tid_t tid, uint32_t &save_id); - - bool - RestoreRegisterState (lldb::tid_t tid, uint32_t save_id); - - const char * - GetGDBServerProgramName(); - - uint32_t - GetGDBServerProgramVersion(); - - bool - AvoidGPackets(ProcessGDBRemote *process); - - StructuredData::ObjectSP - GetThreadsInfo(); - - bool - GetThreadExtendedInfoSupported(); - - bool - GetLoadedDynamicLibrariesInfosSupported(); - - bool - GetModuleInfo (const FileSpec& module_file_spec, - const ArchSpec& arch_spec, - ModuleSpec &module_spec); - - bool - ReadExtFeature (const lldb_private::ConstString object, - const lldb_private::ConstString annex, - std::string & out, - lldb_private::Error & err); - - void - ServeSymbolLookups(lldb_private::Process *process); + } + + uint8_t SendGDBStoppointTypePacket( + GDBStoppointType type, // Type of breakpoint or watchpoint + bool insert, // Insert or remove? + lldb::addr_t addr, // Address of breakpoint or watchpoint + uint32_t length); // Byte Size of breakpoint or watchpoint + + bool SetNonStopMode(const bool enable); + + void TestPacketSpeed(const uint32_t num_packets, uint32_t max_send, + uint32_t max_recv, uint64_t recv_amount, bool json, + Stream &strm); + + // This packet is for testing the speed of the interface only. Both + // the client and server need to support it, but this allows us to + // measure the packet speed without any other work being done on the + // other end and avoids any of that work affecting the packet send + // and response times. + bool SendSpeedTestPacket(uint32_t send_size, uint32_t recv_size); + + bool SetCurrentThread(uint64_t tid); + + bool SetCurrentThreadForRun(uint64_t tid); + + bool GetQXferAuxvReadSupported(); + + bool GetQXferLibrariesReadSupported(); + + bool GetQXferLibrariesSVR4ReadSupported(); + + uint64_t GetRemoteMaxPacketSize(); + + bool GetEchoSupported(); + + bool GetAugmentedLibrariesSVR4ReadSupported(); + + bool GetQXferFeaturesReadSupported(); + + LazyBool SupportsAllocDeallocMemory() // const + { + // Uncomment this to have lldb pretend the debug server doesn't respond to + // alloc/dealloc memory packets. + // m_supports_alloc_dealloc_memory = lldb_private::eLazyBoolNo; + return m_supports_alloc_dealloc_memory; + } + + size_t GetCurrentThreadIDs(std::vector<lldb::tid_t> &thread_ids, + bool &sequence_mutex_unavailable); + + lldb::user_id_t OpenFile(const FileSpec &file_spec, uint32_t flags, + mode_t mode, Error &error); + + bool CloseFile(lldb::user_id_t fd, Error &error); + + lldb::user_id_t GetFileSize(const FileSpec &file_spec); + + Error GetFilePermissions(const FileSpec &file_spec, + uint32_t &file_permissions); + + Error SetFilePermissions(const FileSpec &file_spec, + uint32_t file_permissions); + + uint64_t ReadFile(lldb::user_id_t fd, uint64_t offset, void *dst, + uint64_t dst_len, Error &error); + + uint64_t WriteFile(lldb::user_id_t fd, uint64_t offset, const void *src, + uint64_t src_len, Error &error); + + Error CreateSymlink(const FileSpec &src, const FileSpec &dst); + + Error Unlink(const FileSpec &file_spec); + + Error MakeDirectory(const FileSpec &file_spec, uint32_t mode); + + bool GetFileExists(const FileSpec &file_spec); + + Error RunShellCommand( + const char *command, // Shouldn't be nullptr + const FileSpec &working_dir, // Pass empty FileSpec to use the current + // working directory + int *status_ptr, // Pass nullptr if you don't want the process exit status + int *signo_ptr, // Pass nullptr if you don't want the signal that caused + // the process to exit + std::string + *command_output, // Pass nullptr if you don't want the command output + uint32_t timeout_sec); // Timeout in seconds to wait for shell program to + // finish + + bool CalculateMD5(const FileSpec &file_spec, uint64_t &high, uint64_t &low); + + lldb::DataBufferSP ReadRegister( + lldb::tid_t tid, + uint32_t + reg_num); // Must be the eRegisterKindProcessPlugin register number + + lldb::DataBufferSP ReadAllRegisters(lldb::tid_t tid); + + bool + WriteRegister(lldb::tid_t tid, + uint32_t reg_num, // eRegisterKindProcessPlugin register number + llvm::ArrayRef<uint8_t> data); + + bool WriteAllRegisters(lldb::tid_t tid, llvm::ArrayRef<uint8_t> data); + + bool SaveRegisterState(lldb::tid_t tid, uint32_t &save_id); + + bool RestoreRegisterState(lldb::tid_t tid, uint32_t save_id); + + bool SyncThreadState(lldb::tid_t tid); + + const char *GetGDBServerProgramName(); + + uint32_t GetGDBServerProgramVersion(); + + bool AvoidGPackets(ProcessGDBRemote *process); + + StructuredData::ObjectSP GetThreadsInfo(); + + bool GetThreadExtendedInfoSupported(); + + bool GetLoadedDynamicLibrariesInfosSupported(); + + bool GetSharedCacheInfoSupported(); + + bool GetModuleInfo(const FileSpec &module_file_spec, + const ArchSpec &arch_spec, ModuleSpec &module_spec); + + llvm::Optional<std::vector<ModuleSpec>> + GetModulesInfo(llvm::ArrayRef<FileSpec> module_file_specs, + const llvm::Triple &triple); + + bool ReadExtFeature(const lldb_private::ConstString object, + const lldb_private::ConstString annex, std::string &out, + lldb_private::Error &err); + + void ServeSymbolLookups(lldb_private::Process *process); + + //------------------------------------------------------------------ + /// Return the feature set supported by the gdb-remote server. + /// + /// This method returns the remote side's response to the qSupported + /// packet. The response is the complete string payload returned + /// to the client. + /// + /// @return + /// The string returned by the server to the qSupported query. + //------------------------------------------------------------------ + const std::string &GetServerSupportedFeatures() const { + return m_qSupported_response; + } + + //------------------------------------------------------------------ + /// Return the array of async JSON packet types supported by the remote. + /// + /// This method returns the remote side's array of supported JSON + /// packet types as a list of type names. Each of the results are + /// expected to have an Enable{type_name} command to enable and configure + /// the related feature. Each type_name for an enabled feature will + /// possibly send async-style packets that contain a payload of a + /// binhex-encoded JSON dictionary. The dictionary will have a + /// string field named 'type', that contains the type_name of the + /// supported packet type. + /// + /// There is a Plugin category called structured-data plugins. + /// A plugin indicates whether it knows how to handle a type_name. + /// If so, it can be used to process the async JSON packet. + /// + /// @return + /// The string returned by the server to the qSupported query. + //------------------------------------------------------------------ + lldb_private::StructuredData::Array *GetSupportedStructuredDataPlugins(); + + //------------------------------------------------------------------ + /// Configure a StructuredData feature on the remote end. + /// + /// @see \b Process::ConfigureStructuredData(...) for details. + //------------------------------------------------------------------ + Error + ConfigureRemoteStructuredData(const ConstString &type_name, + const StructuredData::ObjectSP &config_sp); protected: - LazyBool m_supports_not_sending_acks; - LazyBool m_supports_thread_suffix; - LazyBool m_supports_threads_in_stop_reply; - LazyBool m_supports_vCont_all; - LazyBool m_supports_vCont_any; - LazyBool m_supports_vCont_c; - LazyBool m_supports_vCont_C; - LazyBool m_supports_vCont_s; - LazyBool m_supports_vCont_S; - LazyBool m_qHostInfo_is_valid; - LazyBool m_curr_pid_is_valid; - LazyBool m_qProcessInfo_is_valid; - LazyBool m_qGDBServerVersion_is_valid; - LazyBool m_supports_alloc_dealloc_memory; - LazyBool m_supports_memory_region_info; - LazyBool m_supports_watchpoint_support_info; - LazyBool m_supports_detach_stay_stopped; - LazyBool m_watchpoints_trigger_after_instruction; - LazyBool m_attach_or_wait_reply; - LazyBool m_prepare_for_reg_writing_reply; - LazyBool m_supports_p; - LazyBool m_supports_x; - LazyBool m_avoid_g_packets; - LazyBool m_supports_QSaveRegisterState; - LazyBool m_supports_qXfer_auxv_read; - LazyBool m_supports_qXfer_libraries_read; - LazyBool m_supports_qXfer_libraries_svr4_read; - LazyBool m_supports_qXfer_features_read; - LazyBool m_supports_augmented_libraries_svr4_read; - LazyBool m_supports_jThreadExtendedInfo; - LazyBool m_supports_jLoadedDynamicLibrariesInfos; - - bool - m_supports_qProcessInfoPID:1, - m_supports_qfProcessInfo:1, - m_supports_qUserName:1, - m_supports_qGroupName:1, - m_supports_qThreadStopInfo:1, - m_supports_z0:1, - m_supports_z1:1, - m_supports_z2:1, - m_supports_z3:1, - m_supports_z4:1, - m_supports_QEnvironment:1, - m_supports_QEnvironmentHexEncoded:1, - m_supports_qSymbol:1, - m_qSymbol_requests_done:1, - m_supports_qModuleInfo:1, - m_supports_jThreadsInfo:1; - - lldb::pid_t m_curr_pid; - lldb::tid_t m_curr_tid; // Current gdb remote protocol thread index for all other operations - lldb::tid_t m_curr_tid_run; // Current gdb remote protocol thread index for continue, step, etc - - uint32_t m_num_supported_hardware_watchpoints; - - // If we need to send a packet while the target is running, the m_async_XXX - // member variables take care of making this happen. - std::recursive_mutex m_async_mutex; - Predicate<bool> m_async_packet_predicate; - std::string m_async_packet; - PacketResult m_async_result; - StringExtractorGDBRemote m_async_response; - int m_async_signal; // We were asked to deliver a signal to the inferior process. - bool m_interrupt_sent; - std::string m_partial_profile_data; - std::map<uint64_t, uint32_t> m_thread_id_to_used_usec_map; - - ArchSpec m_host_arch; - ArchSpec m_process_arch; - uint32_t m_os_version_major; - uint32_t m_os_version_minor; - uint32_t m_os_version_update; - std::string m_os_build; - std::string m_os_kernel; - std::string m_hostname; - std::string m_gdb_server_name; // from reply to qGDBServerVersion, empty if qGDBServerVersion is not supported - uint32_t m_gdb_server_version; // from reply to qGDBServerVersion, zero if qGDBServerVersion is not supported - uint32_t m_default_packet_timeout; - uint64_t m_max_packet_size; // as returned by qSupported - - PacketResult - SendPacketAndWaitForResponseNoLock (const char *payload, - size_t payload_length, - StringExtractorGDBRemote &response); - - bool - GetCurrentProcessInfo (bool allow_lazy_pid = true); - - bool - GetGDBServerVersion(); - - // Given the list of compression types that the remote debug stub can support, - // possibly enable compression if we find an encoding we can handle. - void - MaybeEnableCompression (std::vector<std::string> supported_compressions); - - bool - DecodeProcessInfoResponse (StringExtractorGDBRemote &response, - ProcessInstanceInfo &process_info); + LazyBool m_supports_not_sending_acks; + LazyBool m_supports_thread_suffix; + LazyBool m_supports_threads_in_stop_reply; + LazyBool m_supports_vCont_all; + LazyBool m_supports_vCont_any; + LazyBool m_supports_vCont_c; + LazyBool m_supports_vCont_C; + LazyBool m_supports_vCont_s; + LazyBool m_supports_vCont_S; + LazyBool m_qHostInfo_is_valid; + LazyBool m_curr_pid_is_valid; + LazyBool m_qProcessInfo_is_valid; + LazyBool m_qGDBServerVersion_is_valid; + LazyBool m_supports_alloc_dealloc_memory; + LazyBool m_supports_memory_region_info; + LazyBool m_supports_watchpoint_support_info; + LazyBool m_supports_detach_stay_stopped; + LazyBool m_watchpoints_trigger_after_instruction; + LazyBool m_attach_or_wait_reply; + LazyBool m_prepare_for_reg_writing_reply; + LazyBool m_supports_p; + LazyBool m_supports_x; + LazyBool m_avoid_g_packets; + LazyBool m_supports_QSaveRegisterState; + LazyBool m_supports_qXfer_auxv_read; + LazyBool m_supports_qXfer_libraries_read; + LazyBool m_supports_qXfer_libraries_svr4_read; + LazyBool m_supports_qXfer_features_read; + LazyBool m_supports_augmented_libraries_svr4_read; + LazyBool m_supports_jThreadExtendedInfo; + LazyBool m_supports_jLoadedDynamicLibrariesInfos; + LazyBool m_supports_jGetSharedCacheInfo; + + bool m_supports_qProcessInfoPID : 1, m_supports_qfProcessInfo : 1, + m_supports_qUserName : 1, m_supports_qGroupName : 1, + m_supports_qThreadStopInfo : 1, m_supports_z0 : 1, m_supports_z1 : 1, + m_supports_z2 : 1, m_supports_z3 : 1, m_supports_z4 : 1, + m_supports_QEnvironment : 1, m_supports_QEnvironmentHexEncoded : 1, + m_supports_qSymbol : 1, m_qSymbol_requests_done : 1, + m_supports_qModuleInfo : 1, m_supports_jThreadsInfo : 1, + m_supports_jModulesInfo : 1; + + lldb::pid_t m_curr_pid; + lldb::tid_t m_curr_tid; // Current gdb remote protocol thread index for all + // other operations + lldb::tid_t m_curr_tid_run; // Current gdb remote protocol thread index for + // continue, step, etc + + uint32_t m_num_supported_hardware_watchpoints; + + ArchSpec m_host_arch; + ArchSpec m_process_arch; + uint32_t m_os_version_major; + uint32_t m_os_version_minor; + uint32_t m_os_version_update; + std::string m_os_build; + std::string m_os_kernel; + std::string m_hostname; + std::string m_gdb_server_name; // from reply to qGDBServerVersion, empty if + // qGDBServerVersion is not supported + uint32_t m_gdb_server_version; // from reply to qGDBServerVersion, zero if + // qGDBServerVersion is not supported + std::chrono::seconds m_default_packet_timeout; + uint64_t m_max_packet_size; // as returned by qSupported + std::string m_qSupported_response; // the complete response to qSupported + + bool m_supported_async_json_packets_is_valid; + lldb_private::StructuredData::ObjectSP m_supported_async_json_packets_sp; + + bool GetCurrentProcessInfo(bool allow_lazy_pid = true); + + bool GetGDBServerVersion(); + + // Given the list of compression types that the remote debug stub can support, + // possibly enable compression if we find an encoding we can handle. + void MaybeEnableCompression(std::vector<std::string> supported_compressions); + + bool DecodeProcessInfoResponse(StringExtractorGDBRemote &response, + ProcessInstanceInfo &process_info); + + void OnRunPacketSent(bool first) override; + + PacketResult SendThreadSpecificPacketAndWaitForResponse( + lldb::tid_t tid, StreamString &&payload, + StringExtractorGDBRemote &response, bool send_async); private: - DISALLOW_COPY_AND_ASSIGN (GDBRemoteCommunicationClient); + DISALLOW_COPY_AND_ASSIGN(GDBRemoteCommunicationClient); }; } // namespace process_gdb_remote diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp index 4ee66b8..934824e 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp @@ -25,114 +25,96 @@ using namespace lldb; using namespace lldb_private; using namespace lldb_private::process_gdb_remote; -GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(const char *comm_name, - const char *listener_name) : - GDBRemoteCommunication (comm_name, listener_name), - m_exit_now (false) -{ -} +GDBRemoteCommunicationServer::GDBRemoteCommunicationServer( + const char *comm_name, const char *listener_name) + : GDBRemoteCommunication(comm_name, listener_name), m_exit_now(false) {} -GDBRemoteCommunicationServer::~GDBRemoteCommunicationServer() -{ -} +GDBRemoteCommunicationServer::~GDBRemoteCommunicationServer() {} void GDBRemoteCommunicationServer::RegisterPacketHandler( - StringExtractorGDBRemote::ServerPacketType packet_type, - PacketHandler handler) -{ - m_packet_handlers[packet_type] = std::move(handler); + StringExtractorGDBRemote::ServerPacketType packet_type, + PacketHandler handler) { + m_packet_handlers[packet_type] = std::move(handler); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec, - Error &error, - bool &interrupt, - bool &quit) -{ - StringExtractorGDBRemote packet; - - PacketResult packet_result = WaitForPacketWithTimeoutMicroSecondsNoLock (packet, timeout_usec, false); - if (packet_result == PacketResult::Success) - { - const StringExtractorGDBRemote::ServerPacketType packet_type = packet.GetServerPacketType (); - switch (packet_type) - { - case StringExtractorGDBRemote::eServerPacketType_nack: - case StringExtractorGDBRemote::eServerPacketType_ack: - break; - - case StringExtractorGDBRemote::eServerPacketType_invalid: - error.SetErrorString("invalid packet"); - quit = true; - break; - - case StringExtractorGDBRemote::eServerPacketType_unimplemented: - packet_result = SendUnimplementedResponse (packet.GetStringRef().c_str()); - break; - - default: - auto handler_it = m_packet_handlers.find(packet_type); - if (handler_it == m_packet_handlers.end()) - packet_result = SendUnimplementedResponse (packet.GetStringRef().c_str()); - else - packet_result = handler_it->second (packet, error, interrupt, quit); - break; - } +GDBRemoteCommunicationServer::GetPacketAndSendResponse( + Timeout<std::micro> timeout, Error &error, bool &interrupt, bool &quit) { + StringExtractorGDBRemote packet; + + PacketResult packet_result = WaitForPacketNoLock(packet, timeout, false); + if (packet_result == PacketResult::Success) { + const StringExtractorGDBRemote::ServerPacketType packet_type = + packet.GetServerPacketType(); + switch (packet_type) { + case StringExtractorGDBRemote::eServerPacketType_nack: + case StringExtractorGDBRemote::eServerPacketType_ack: + break; + + case StringExtractorGDBRemote::eServerPacketType_invalid: + error.SetErrorString("invalid packet"); + quit = true; + break; + + case StringExtractorGDBRemote::eServerPacketType_unimplemented: + packet_result = SendUnimplementedResponse(packet.GetStringRef().c_str()); + break; + + default: + auto handler_it = m_packet_handlers.find(packet_type); + if (handler_it == m_packet_handlers.end()) + packet_result = + SendUnimplementedResponse(packet.GetStringRef().c_str()); + else + packet_result = handler_it->second(packet, error, interrupt, quit); + break; } - else - { - if (!IsConnected()) - { - error.SetErrorString("lost connection"); - quit = true; - } - else - { - error.SetErrorString("timeout"); - } + } else { + if (!IsConnected()) { + error.SetErrorString("lost connection"); + quit = true; + } else { + error.SetErrorString("timeout"); } + } - // Check if anything occurred that would force us to want to exit. - if (m_exit_now) - quit = true; + // Check if anything occurred that would force us to want to exit. + if (m_exit_now) + quit = true; - return packet_result; + return packet_result; } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::SendUnimplementedResponse (const char *) -{ - // TODO: Log the packet we aren't handling... - return SendPacketNoLock ("", 0); +GDBRemoteCommunicationServer::SendUnimplementedResponse(const char *) { + // TODO: Log the packet we aren't handling... + return SendPacketNoLock(""); } - GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::SendErrorResponse (uint8_t err) -{ - char packet[16]; - int packet_len = ::snprintf (packet, sizeof(packet), "E%2.2x", err); - assert (packet_len < (int)sizeof(packet)); - return SendPacketNoLock (packet, packet_len); +GDBRemoteCommunicationServer::SendErrorResponse(uint8_t err) { + char packet[16]; + int packet_len = ::snprintf(packet, sizeof(packet), "E%2.2x", err); + assert(packet_len < (int)sizeof(packet)); + return SendPacketNoLock(llvm::StringRef(packet, packet_len)); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::SendIllFormedResponse (const StringExtractorGDBRemote &failed_packet, const char *message) -{ - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS)); - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s: ILLFORMED: '%s' (%s)", __FUNCTION__, failed_packet.GetStringRef ().c_str (), message ? message : ""); - return SendErrorResponse (0x03); +GDBRemoteCommunicationServer::SendIllFormedResponse( + const StringExtractorGDBRemote &failed_packet, const char *message) { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS)); + if (log) + log->Printf("GDBRemoteCommunicationServer::%s: ILLFORMED: '%s' (%s)", + __FUNCTION__, failed_packet.GetStringRef().c_str(), + message ? message : ""); + return SendErrorResponse(0x03); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::SendOKResponse () -{ - return SendPacketNoLock ("OK", 2); +GDBRemoteCommunicationServer::SendOKResponse() { + return SendPacketNoLock("OK"); } -bool -GDBRemoteCommunicationServer::HandshakeWithClient() -{ - return GetAck() == PacketResult::Success; +bool GDBRemoteCommunicationServer::HandshakeWithClient() { + return GetAck() == PacketResult::Success; } diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h index 1d512bf..0c583e6 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h @@ -17,8 +17,8 @@ // Other libraries and framework includes // Project includes -#include "lldb/lldb-private-forward.h" #include "GDBRemoteCommunication.h" +#include "lldb/lldb-private-forward.h" class StringExtractorGDBRemote; @@ -27,52 +27,47 @@ namespace process_gdb_remote { class ProcessGDBRemote; -class GDBRemoteCommunicationServer : public GDBRemoteCommunication -{ +class GDBRemoteCommunicationServer : public GDBRemoteCommunication { public: - using PortMap = std::map<uint16_t, lldb::pid_t>; - using PacketHandler = std::function<PacketResult(StringExtractorGDBRemote &packet, - Error &error, - bool &interrupt, - bool &quit)>; + using PortMap = std::map<uint16_t, lldb::pid_t>; + using PacketHandler = + std::function<PacketResult(StringExtractorGDBRemote &packet, Error &error, + bool &interrupt, bool &quit)>; - GDBRemoteCommunicationServer(const char *comm_name, - const char *listener_name); + GDBRemoteCommunicationServer(const char *comm_name, + const char *listener_name); - ~GDBRemoteCommunicationServer() override; + ~GDBRemoteCommunicationServer() override; - void RegisterPacketHandler(StringExtractorGDBRemote::ServerPacketType packet_type, - PacketHandler handler); + void + RegisterPacketHandler(StringExtractorGDBRemote::ServerPacketType packet_type, + PacketHandler handler); - PacketResult - GetPacketAndSendResponse (uint32_t timeout_usec, - Error &error, - bool &interrupt, - bool &quit); + PacketResult GetPacketAndSendResponse(Timeout<std::micro> timeout, + Error &error, bool &interrupt, + bool &quit); - // After connecting, do a little handshake with the client to make sure - // we are at least communicating - bool - HandshakeWithClient (); + // After connecting, do a little handshake with the client to make sure + // we are at least communicating + bool HandshakeWithClient(); protected: - std::map<StringExtractorGDBRemote::ServerPacketType, PacketHandler> m_packet_handlers; - bool m_exit_now; // use in asynchronous handling to indicate process should exit. + std::map<StringExtractorGDBRemote::ServerPacketType, PacketHandler> + m_packet_handlers; + bool m_exit_now; // use in asynchronous handling to indicate process should + // exit. - PacketResult - SendUnimplementedResponse (const char *packet); + PacketResult SendUnimplementedResponse(const char *packet); - PacketResult - SendErrorResponse (uint8_t error); + PacketResult SendErrorResponse(uint8_t error); - PacketResult - SendIllFormedResponse (const StringExtractorGDBRemote &packet, const char *error_message); + PacketResult SendIllFormedResponse(const StringExtractorGDBRemote &packet, + const char *error_message); - PacketResult - SendOKResponse (); + PacketResult SendOKResponse(); private: - DISALLOW_COPY_AND_ASSIGN (GDBRemoteCommunicationServer); + DISALLOW_COPY_AND_ASSIGN(GDBRemoteCommunicationServer); }; } // namespace process_gdb_remote diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp index 26a2e69..e4e6810 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp @@ -12,12 +12,16 @@ #include <errno.h> // C Includes + +#ifdef __APPLE__ +#include <TargetConditionals.h> +#endif + // C++ Includes -#include <cstring> #include <chrono> +#include <cstring> // Other libraries and framework includes -#include "llvm/ADT/Triple.h" #include "lldb/Core/Log.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/StreamGDBRemote.h" @@ -34,6 +38,8 @@ #include "lldb/Target/FileAction.h" #include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" +#include "lldb/Utility/JSON.h" +#include "llvm/ADT/Triple.h" // Project includes #include "ProcessGDBRemoteLog.h" @@ -43,1214 +49,1252 @@ #include "lldb/Host/android/HostInfoAndroid.h" #endif +#include "llvm/ADT/StringSwitch.h" + using namespace lldb; using namespace lldb_private; using namespace lldb_private::process_gdb_remote; #ifdef __ANDROID__ - const static uint32_t g_default_packet_timeout_sec = 20; // seconds +const static uint32_t g_default_packet_timeout_sec = 20; // seconds #else - const static uint32_t g_default_packet_timeout_sec = 0; // not specified +const static uint32_t g_default_packet_timeout_sec = 0; // not specified #endif //---------------------------------------------------------------------- // GDBRemoteCommunicationServerCommon constructor //---------------------------------------------------------------------- -GDBRemoteCommunicationServerCommon::GDBRemoteCommunicationServerCommon(const char *comm_name, const char *listener_name) : - GDBRemoteCommunicationServer (comm_name, listener_name), - m_process_launch_info (), - m_process_launch_error (), - m_proc_infos (), - m_proc_infos_index (0), - m_thread_suffix_supported (false), - m_list_threads_in_stop_reply (false) -{ - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_A, - &GDBRemoteCommunicationServerCommon::Handle_A); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QEnvironment, - &GDBRemoteCommunicationServerCommon::Handle_QEnvironment); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QEnvironmentHexEncoded, - &GDBRemoteCommunicationServerCommon::Handle_QEnvironmentHexEncoded); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qfProcessInfo, - &GDBRemoteCommunicationServerCommon::Handle_qfProcessInfo); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qGroupName, - &GDBRemoteCommunicationServerCommon::Handle_qGroupName); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qHostInfo, - &GDBRemoteCommunicationServerCommon::Handle_qHostInfo); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QLaunchArch, - &GDBRemoteCommunicationServerCommon::Handle_QLaunchArch); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qLaunchSuccess, - &GDBRemoteCommunicationServerCommon::Handle_qLaunchSuccess); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QListThreadsInStopReply, - &GDBRemoteCommunicationServerCommon::Handle_QListThreadsInStopReply); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qEcho, - &GDBRemoteCommunicationServerCommon::Handle_qEcho); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qModuleInfo, - &GDBRemoteCommunicationServerCommon::Handle_qModuleInfo); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qPlatform_chmod, - &GDBRemoteCommunicationServerCommon::Handle_qPlatform_chmod); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qPlatform_mkdir, - &GDBRemoteCommunicationServerCommon::Handle_qPlatform_mkdir); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qPlatform_shell, - &GDBRemoteCommunicationServerCommon::Handle_qPlatform_shell); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qProcessInfoPID, - &GDBRemoteCommunicationServerCommon::Handle_qProcessInfoPID); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetDetachOnError, - &GDBRemoteCommunicationServerCommon::Handle_QSetDetachOnError); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetSTDERR, - &GDBRemoteCommunicationServerCommon::Handle_QSetSTDERR); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetSTDIN, - &GDBRemoteCommunicationServerCommon::Handle_QSetSTDIN); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetSTDOUT, - &GDBRemoteCommunicationServerCommon::Handle_QSetSTDOUT); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qSpeedTest, - &GDBRemoteCommunicationServerCommon::Handle_qSpeedTest); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qsProcessInfo, - &GDBRemoteCommunicationServerCommon::Handle_qsProcessInfo); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QStartNoAckMode, - &GDBRemoteCommunicationServerCommon::Handle_QStartNoAckMode); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qSupported, - &GDBRemoteCommunicationServerCommon::Handle_qSupported); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QThreadSuffixSupported, - &GDBRemoteCommunicationServerCommon::Handle_QThreadSuffixSupported); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qUserName, - &GDBRemoteCommunicationServerCommon::Handle_qUserName); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_close, - &GDBRemoteCommunicationServerCommon::Handle_vFile_Close); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_exists, - &GDBRemoteCommunicationServerCommon::Handle_vFile_Exists); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_md5, - &GDBRemoteCommunicationServerCommon::Handle_vFile_MD5); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_mode, - &GDBRemoteCommunicationServerCommon::Handle_vFile_Mode); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_open, - &GDBRemoteCommunicationServerCommon::Handle_vFile_Open); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_pread, - &GDBRemoteCommunicationServerCommon::Handle_vFile_pRead); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_pwrite, - &GDBRemoteCommunicationServerCommon::Handle_vFile_pWrite); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_size, - &GDBRemoteCommunicationServerCommon::Handle_vFile_Size); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_stat, - &GDBRemoteCommunicationServerCommon::Handle_vFile_Stat); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_symlink, - &GDBRemoteCommunicationServerCommon::Handle_vFile_symlink); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_unlink, - &GDBRemoteCommunicationServerCommon::Handle_vFile_unlink); +GDBRemoteCommunicationServerCommon::GDBRemoteCommunicationServerCommon( + const char *comm_name, const char *listener_name) + : GDBRemoteCommunicationServer(comm_name, listener_name), + m_process_launch_info(), m_process_launch_error(), m_proc_infos(), + m_proc_infos_index(0), m_thread_suffix_supported(false), + m_list_threads_in_stop_reply(false) { + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_A, + &GDBRemoteCommunicationServerCommon::Handle_A); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_QEnvironment, + &GDBRemoteCommunicationServerCommon::Handle_QEnvironment); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_QEnvironmentHexEncoded, + &GDBRemoteCommunicationServerCommon::Handle_QEnvironmentHexEncoded); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qfProcessInfo, + &GDBRemoteCommunicationServerCommon::Handle_qfProcessInfo); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qGroupName, + &GDBRemoteCommunicationServerCommon::Handle_qGroupName); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qHostInfo, + &GDBRemoteCommunicationServerCommon::Handle_qHostInfo); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_QLaunchArch, + &GDBRemoteCommunicationServerCommon::Handle_QLaunchArch); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qLaunchSuccess, + &GDBRemoteCommunicationServerCommon::Handle_qLaunchSuccess); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_QListThreadsInStopReply, + &GDBRemoteCommunicationServerCommon::Handle_QListThreadsInStopReply); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qEcho, + &GDBRemoteCommunicationServerCommon::Handle_qEcho); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qModuleInfo, + &GDBRemoteCommunicationServerCommon::Handle_qModuleInfo); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_jModulesInfo, + &GDBRemoteCommunicationServerCommon::Handle_jModulesInfo); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qPlatform_chmod, + &GDBRemoteCommunicationServerCommon::Handle_qPlatform_chmod); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qPlatform_mkdir, + &GDBRemoteCommunicationServerCommon::Handle_qPlatform_mkdir); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qPlatform_shell, + &GDBRemoteCommunicationServerCommon::Handle_qPlatform_shell); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qProcessInfoPID, + &GDBRemoteCommunicationServerCommon::Handle_qProcessInfoPID); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_QSetDetachOnError, + &GDBRemoteCommunicationServerCommon::Handle_QSetDetachOnError); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_QSetSTDERR, + &GDBRemoteCommunicationServerCommon::Handle_QSetSTDERR); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_QSetSTDIN, + &GDBRemoteCommunicationServerCommon::Handle_QSetSTDIN); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_QSetSTDOUT, + &GDBRemoteCommunicationServerCommon::Handle_QSetSTDOUT); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qSpeedTest, + &GDBRemoteCommunicationServerCommon::Handle_qSpeedTest); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qsProcessInfo, + &GDBRemoteCommunicationServerCommon::Handle_qsProcessInfo); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_QStartNoAckMode, + &GDBRemoteCommunicationServerCommon::Handle_QStartNoAckMode); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qSupported, + &GDBRemoteCommunicationServerCommon::Handle_qSupported); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_QThreadSuffixSupported, + &GDBRemoteCommunicationServerCommon::Handle_QThreadSuffixSupported); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qUserName, + &GDBRemoteCommunicationServerCommon::Handle_qUserName); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_vFile_close, + &GDBRemoteCommunicationServerCommon::Handle_vFile_Close); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_vFile_exists, + &GDBRemoteCommunicationServerCommon::Handle_vFile_Exists); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_vFile_md5, + &GDBRemoteCommunicationServerCommon::Handle_vFile_MD5); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_vFile_mode, + &GDBRemoteCommunicationServerCommon::Handle_vFile_Mode); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_vFile_open, + &GDBRemoteCommunicationServerCommon::Handle_vFile_Open); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_vFile_pread, + &GDBRemoteCommunicationServerCommon::Handle_vFile_pRead); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_vFile_pwrite, + &GDBRemoteCommunicationServerCommon::Handle_vFile_pWrite); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_vFile_size, + &GDBRemoteCommunicationServerCommon::Handle_vFile_Size); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_vFile_stat, + &GDBRemoteCommunicationServerCommon::Handle_vFile_Stat); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_vFile_symlink, + &GDBRemoteCommunicationServerCommon::Handle_vFile_symlink); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_vFile_unlink, + &GDBRemoteCommunicationServerCommon::Handle_vFile_unlink); } //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- -GDBRemoteCommunicationServerCommon::~GDBRemoteCommunicationServerCommon() -{ -} +GDBRemoteCommunicationServerCommon::~GDBRemoteCommunicationServerCommon() {} GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_qHostInfo (StringExtractorGDBRemote &packet) -{ - StreamString response; +GDBRemoteCommunicationServerCommon::Handle_qHostInfo( + StringExtractorGDBRemote &packet) { + StreamString response; - // $cputype:16777223;cpusubtype:3;ostype:Darwin;vendor:apple;endian:little;ptrsize:8;#00 + // $cputype:16777223;cpusubtype:3;ostype:Darwin;vendor:apple;endian:little;ptrsize:8;#00 - ArchSpec host_arch(HostInfo::GetArchitecture()); - const llvm::Triple &host_triple = host_arch.GetTriple(); - response.PutCString("triple:"); - response.PutCStringAsRawHex8(host_triple.getTriple().c_str()); - response.Printf (";ptrsize:%u;",host_arch.GetAddressByteSize()); - - const char* distribution_id = host_arch.GetDistributionId ().AsCString (); - if (distribution_id) - { - response.PutCString("distribution_id:"); - response.PutCStringAsRawHex8(distribution_id); - response.PutCString(";"); - } + ArchSpec host_arch(HostInfo::GetArchitecture()); + const llvm::Triple &host_triple = host_arch.GetTriple(); + response.PutCString("triple:"); + response.PutCStringAsRawHex8(host_triple.getTriple().c_str()); + response.Printf(";ptrsize:%u;", host_arch.GetAddressByteSize()); + + const char *distribution_id = host_arch.GetDistributionId().AsCString(); + if (distribution_id) { + response.PutCString("distribution_id:"); + response.PutCStringAsRawHex8(distribution_id); + response.PutCString(";"); + } - // Only send out MachO info when lldb-platform/llgs is running on a MachO host. #if defined(__APPLE__) - uint32_t cpu = host_arch.GetMachOCPUType(); - uint32_t sub = host_arch.GetMachOCPUSubType(); - if (cpu != LLDB_INVALID_CPUTYPE) - response.Printf ("cputype:%u;", cpu); - if (sub != LLDB_INVALID_CPUTYPE) - response.Printf ("cpusubtype:%u;", sub); - - if (cpu == ArchSpec::kCore_arm_any) - response.Printf("watchpoint_exceptions_received:before;"); // On armv7 we use "synchronous" watchpoints which means the exception is delivered before the instruction executes. - else - response.Printf("watchpoint_exceptions_received:after;"); + // For parity with debugserver, we'll include the vendor key. + response.PutCString("vendor:apple;"); + + // Send out MachO info. + uint32_t cpu = host_arch.GetMachOCPUType(); + uint32_t sub = host_arch.GetMachOCPUSubType(); + if (cpu != LLDB_INVALID_CPUTYPE) + response.Printf("cputype:%u;", cpu); + if (sub != LLDB_INVALID_CPUTYPE) + response.Printf("cpusubtype:%u;", sub); + + if (cpu == ArchSpec::kCore_arm_any) { +// Indicate the OS type. +#if defined(TARGET_OS_TV) && TARGET_OS_TV == 1 + response.PutCString("ostype:tvos;"); +#elif defined(TARGET_OS_WATCH) && TARGET_OS_WATCH == 1 + response.PutCString("ostype:watchos;"); #else - if (host_arch.GetMachine() == llvm::Triple::aarch64 || - host_arch.GetMachine() == llvm::Triple::aarch64_be || - host_arch.GetMachine() == llvm::Triple::arm || - host_arch.GetMachine() == llvm::Triple::armeb || - host_arch.GetMachine() == llvm::Triple::mips64 || - host_arch.GetMachine() == llvm::Triple::mips64el || - host_arch.GetMachine() == llvm::Triple::mips || - host_arch.GetMachine() == llvm::Triple::mipsel) - response.Printf("watchpoint_exceptions_received:before;"); - else - response.Printf("watchpoint_exceptions_received:after;"); + response.PutCString("ostype:ios;"); #endif - switch (endian::InlHostByteOrder()) - { - case eByteOrderBig: response.PutCString ("endian:big;"); break; - case eByteOrderLittle: response.PutCString ("endian:little;"); break; - case eByteOrderPDP: response.PutCString ("endian:pdp;"); break; - default: response.PutCString ("endian:unknown;"); break; - } + // On arm, we use "synchronous" watchpoints which means the exception is + // delivered before the instruction executes. + response.PutCString("watchpoint_exceptions_received:before;"); + } else { + response.PutCString("ostype:macosx;"); + response.Printf("watchpoint_exceptions_received:after;"); + } - uint32_t major = UINT32_MAX; - uint32_t minor = UINT32_MAX; - uint32_t update = UINT32_MAX; - if (HostInfo::GetOSVersion(major, minor, update)) - { - if (major != UINT32_MAX) - { - response.Printf("os_version:%u", major); - if (minor != UINT32_MAX) - { - response.Printf(".%u", minor); - if (update != UINT32_MAX) - response.Printf(".%u", update); - } - response.PutChar(';'); - } - } +#else + if (host_arch.GetMachine() == llvm::Triple::aarch64 || + host_arch.GetMachine() == llvm::Triple::aarch64_be || + host_arch.GetMachine() == llvm::Triple::arm || + host_arch.GetMachine() == llvm::Triple::armeb || + host_arch.GetMachine() == llvm::Triple::mips64 || + host_arch.GetMachine() == llvm::Triple::mips64el || + host_arch.GetMachine() == llvm::Triple::mips || + host_arch.GetMachine() == llvm::Triple::mipsel) + response.Printf("watchpoint_exceptions_received:before;"); + else + response.Printf("watchpoint_exceptions_received:after;"); +#endif - std::string s; - if (HostInfo::GetOSBuildString(s)) - { - response.PutCString ("os_build:"); - response.PutCStringAsRawHex8(s.c_str()); - response.PutChar(';'); - } - if (HostInfo::GetOSKernelDescription(s)) - { - response.PutCString ("os_kernel:"); - response.PutCStringAsRawHex8(s.c_str()); - response.PutChar(';'); + switch (endian::InlHostByteOrder()) { + case eByteOrderBig: + response.PutCString("endian:big;"); + break; + case eByteOrderLittle: + response.PutCString("endian:little;"); + break; + case eByteOrderPDP: + response.PutCString("endian:pdp;"); + break; + default: + response.PutCString("endian:unknown;"); + break; + } + + uint32_t major = UINT32_MAX; + uint32_t minor = UINT32_MAX; + uint32_t update = UINT32_MAX; + if (HostInfo::GetOSVersion(major, minor, update)) { + if (major != UINT32_MAX) { + response.Printf("os_version:%u", major); + if (minor != UINT32_MAX) { + response.Printf(".%u", minor); + if (update != UINT32_MAX) + response.Printf(".%u", update); + } + response.PutChar(';'); } + } + + std::string s; + if (HostInfo::GetOSBuildString(s)) { + response.PutCString("os_build:"); + response.PutCStringAsRawHex8(s.c_str()); + response.PutChar(';'); + } + if (HostInfo::GetOSKernelDescription(s)) { + response.PutCString("os_kernel:"); + response.PutCStringAsRawHex8(s.c_str()); + response.PutChar(';'); + } #if defined(__APPLE__) #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) - // For iOS devices, we are connected through a USB Mux so we never pretend - // to actually have a hostname as far as the remote lldb that is connecting - // to this lldb-platform is concerned - response.PutCString ("hostname:"); - response.PutCStringAsRawHex8("127.0.0.1"); + // For iOS devices, we are connected through a USB Mux so we never pretend + // to actually have a hostname as far as the remote lldb that is connecting + // to this lldb-platform is concerned + response.PutCString("hostname:"); + response.PutCStringAsRawHex8("127.0.0.1"); + response.PutChar(';'); +#else // #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) + if (HostInfo::GetHostname(s)) { + response.PutCString("hostname:"); + response.PutCStringAsRawHex8(s.c_str()); response.PutChar(';'); -#else // #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) - if (HostInfo::GetHostname(s)) - { - response.PutCString ("hostname:"); - response.PutCStringAsRawHex8(s.c_str()); - response.PutChar(';'); - } -#endif // #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) + } +#endif // #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) -#else // #if defined(__APPLE__) - if (HostInfo::GetHostname(s)) - { - response.PutCString ("hostname:"); - response.PutCStringAsRawHex8(s.c_str()); - response.PutChar(';'); - } -#endif // #if defined(__APPLE__) +#else // #if defined(__APPLE__) + if (HostInfo::GetHostname(s)) { + response.PutCString("hostname:"); + response.PutCStringAsRawHex8(s.c_str()); + response.PutChar(';'); + } +#endif // #if defined(__APPLE__) - if (g_default_packet_timeout_sec > 0) - response.Printf ("default_packet_timeout:%u;", g_default_packet_timeout_sec); + if (g_default_packet_timeout_sec > 0) + response.Printf("default_packet_timeout:%u;", g_default_packet_timeout_sec); - return SendPacketNoLock (response.GetData(), response.GetSize()); + return SendPacketNoLock(response.GetString()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_qProcessInfoPID (StringExtractorGDBRemote &packet) -{ - // Packet format: "qProcessInfoPID:%i" where %i is the pid - packet.SetFilePos (::strlen ("qProcessInfoPID:")); - lldb::pid_t pid = packet.GetU32 (LLDB_INVALID_PROCESS_ID); - if (pid != LLDB_INVALID_PROCESS_ID) - { - ProcessInstanceInfo proc_info; - if (Host::GetProcessInfo (pid, proc_info)) - { - StreamString response; - CreateProcessInfoResponse (proc_info, response); - return SendPacketNoLock (response.GetData(), response.GetSize()); - } +GDBRemoteCommunicationServerCommon::Handle_qProcessInfoPID( + StringExtractorGDBRemote &packet) { + // Packet format: "qProcessInfoPID:%i" where %i is the pid + packet.SetFilePos(::strlen("qProcessInfoPID:")); + lldb::pid_t pid = packet.GetU32(LLDB_INVALID_PROCESS_ID); + if (pid != LLDB_INVALID_PROCESS_ID) { + ProcessInstanceInfo proc_info; + if (Host::GetProcessInfo(pid, proc_info)) { + StreamString response; + CreateProcessInfoResponse(proc_info, response); + return SendPacketNoLock(response.GetString()); } - return SendErrorResponse (1); + } + return SendErrorResponse(1); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_qfProcessInfo (StringExtractorGDBRemote &packet) -{ - m_proc_infos_index = 0; - m_proc_infos.Clear(); - - ProcessInstanceInfoMatch match_info; - packet.SetFilePos(::strlen ("qfProcessInfo")); - if (packet.GetChar() == ':') - { - - std::string key; - std::string value; - while (packet.GetNameColonValue(key, value)) - { - bool success = true; - if (key.compare("name") == 0) - { - StringExtractor extractor; - extractor.GetStringRef().swap(value); - extractor.GetHexByteString (value); - match_info.GetProcessInfo().GetExecutableFile().SetFile(value.c_str(), false); - } - else if (key.compare("name_match") == 0) - { - if (value.compare("equals") == 0) - { - match_info.SetNameMatchType (eNameMatchEquals); - } - else if (value.compare("starts_with") == 0) - { - match_info.SetNameMatchType (eNameMatchStartsWith); - } - else if (value.compare("ends_with") == 0) - { - match_info.SetNameMatchType (eNameMatchEndsWith); - } - else if (value.compare("contains") == 0) - { - match_info.SetNameMatchType (eNameMatchContains); - } - else if (value.compare("regex") == 0) - { - match_info.SetNameMatchType (eNameMatchRegularExpression); - } - else - { - success = false; - } - } - else if (key.compare("pid") == 0) - { - match_info.GetProcessInfo().SetProcessID (StringConvert::ToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0, &success)); - } - else if (key.compare("parent_pid") == 0) - { - match_info.GetProcessInfo().SetParentProcessID (StringConvert::ToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0, &success)); - } - else if (key.compare("uid") == 0) - { - match_info.GetProcessInfo().SetUserID (StringConvert::ToUInt32(value.c_str(), UINT32_MAX, 0, &success)); - } - else if (key.compare("gid") == 0) - { - match_info.GetProcessInfo().SetGroupID (StringConvert::ToUInt32(value.c_str(), UINT32_MAX, 0, &success)); - } - else if (key.compare("euid") == 0) - { - match_info.GetProcessInfo().SetEffectiveUserID (StringConvert::ToUInt32(value.c_str(), UINT32_MAX, 0, &success)); - } - else if (key.compare("egid") == 0) - { - match_info.GetProcessInfo().SetEffectiveGroupID (StringConvert::ToUInt32(value.c_str(), UINT32_MAX, 0, &success)); - } - else if (key.compare("all_users") == 0) - { - match_info.SetMatchAllUsers(Args::StringToBoolean(value.c_str(), false, &success)); - } - else if (key.compare("triple") == 0) - { - match_info.GetProcessInfo().GetArchitecture().SetTriple (value.c_str(), NULL); - } - else - { - success = false; - } - - if (!success) - return SendErrorResponse (2); - } - } - - if (Host::FindProcesses (match_info, m_proc_infos)) - { - // We found something, return the first item by calling the get - // subsequent process info packet handler... - return Handle_qsProcessInfo (packet); +GDBRemoteCommunicationServerCommon::Handle_qfProcessInfo( + StringExtractorGDBRemote &packet) { + m_proc_infos_index = 0; + m_proc_infos.Clear(); + + ProcessInstanceInfoMatch match_info; + packet.SetFilePos(::strlen("qfProcessInfo")); + if (packet.GetChar() == ':') { + llvm::StringRef key; + llvm::StringRef value; + while (packet.GetNameColonValue(key, value)) { + bool success = true; + if (key.equals("name")) { + StringExtractor extractor(value); + std::string file; + extractor.GetHexByteString(file); + match_info.GetProcessInfo().GetExecutableFile().SetFile(file, false); + } else if (key.equals("name_match")) { + NameMatchType name_match = + llvm::StringSwitch<NameMatchType>(value) + .Case("equals", eNameMatchEquals) + .Case("starts_with", eNameMatchStartsWith) + .Case("ends_with", eNameMatchEndsWith) + .Case("contains", eNameMatchContains) + .Case("regex", eNameMatchRegularExpression) + .Default(eNameMatchIgnore); + match_info.SetNameMatchType(name_match); + if (name_match == eNameMatchIgnore) + return SendErrorResponse(2); + } else if (key.equals("pid")) { + lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; + if (value.getAsInteger(0, pid)) + return SendErrorResponse(2); + match_info.GetProcessInfo().SetProcessID(pid); + } else if (key.equals("parent_pid")) { + lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; + if (value.getAsInteger(0, pid)) + return SendErrorResponse(2); + match_info.GetProcessInfo().SetParentProcessID(pid); + } else if (key.equals("uid")) { + uint32_t uid = UINT32_MAX; + if (value.getAsInteger(0, uid)) + return SendErrorResponse(2); + match_info.GetProcessInfo().SetUserID(uid); + } else if (key.equals("gid")) { + uint32_t gid = UINT32_MAX; + if (value.getAsInteger(0, gid)) + return SendErrorResponse(2); + match_info.GetProcessInfo().SetGroupID(gid); + } else if (key.equals("euid")) { + uint32_t uid = UINT32_MAX; + if (value.getAsInteger(0, uid)) + return SendErrorResponse(2); + match_info.GetProcessInfo().SetEffectiveUserID(uid); + } else if (key.equals("egid")) { + uint32_t gid = UINT32_MAX; + if (value.getAsInteger(0, gid)) + return SendErrorResponse(2); + match_info.GetProcessInfo().SetEffectiveGroupID(gid); + } else if (key.equals("all_users")) { + match_info.SetMatchAllUsers( + Args::StringToBoolean(value, false, &success)); + } else if (key.equals("triple")) { + match_info.GetProcessInfo().GetArchitecture().SetTriple( + value.str().c_str(), NULL); + } else { + success = false; + } + + if (!success) + return SendErrorResponse(2); } - return SendErrorResponse (3); + } + + if (Host::FindProcesses(match_info, m_proc_infos)) { + // We found something, return the first item by calling the get + // subsequent process info packet handler... + return Handle_qsProcessInfo(packet); + } + return SendErrorResponse(3); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_qsProcessInfo (StringExtractorGDBRemote &packet) -{ - if (m_proc_infos_index < m_proc_infos.GetSize()) - { - StreamString response; - CreateProcessInfoResponse (m_proc_infos.GetProcessInfoAtIndex(m_proc_infos_index), response); - ++m_proc_infos_index; - return SendPacketNoLock (response.GetData(), response.GetSize()); - } - return SendErrorResponse (4); +GDBRemoteCommunicationServerCommon::Handle_qsProcessInfo( + StringExtractorGDBRemote &packet) { + if (m_proc_infos_index < m_proc_infos.GetSize()) { + StreamString response; + CreateProcessInfoResponse( + m_proc_infos.GetProcessInfoAtIndex(m_proc_infos_index), response); + ++m_proc_infos_index; + return SendPacketNoLock(response.GetString()); + } + return SendErrorResponse(4); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_qUserName (StringExtractorGDBRemote &packet) -{ +GDBRemoteCommunicationServerCommon::Handle_qUserName( + StringExtractorGDBRemote &packet) { #if !defined(LLDB_DISABLE_POSIX) - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf("GDBRemoteCommunicationServerCommon::%s begin", __FUNCTION__); - - // Packet format: "qUserName:%i" where %i is the uid - packet.SetFilePos(::strlen ("qUserName:")); - uint32_t uid = packet.GetU32 (UINT32_MAX); - if (uid != UINT32_MAX) - { - std::string name; - if (HostInfo::LookupUserName(uid, name)) - { - StreamString response; - response.PutCStringAsRawHex8 (name.c_str()); - return SendPacketNoLock (response.GetData(), response.GetSize()); - } + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf("GDBRemoteCommunicationServerCommon::%s begin", __FUNCTION__); + + // Packet format: "qUserName:%i" where %i is the uid + packet.SetFilePos(::strlen("qUserName:")); + uint32_t uid = packet.GetU32(UINT32_MAX); + if (uid != UINT32_MAX) { + std::string name; + if (HostInfo::LookupUserName(uid, name)) { + StreamString response; + response.PutCStringAsRawHex8(name.c_str()); + return SendPacketNoLock(response.GetString()); } - if (log) - log->Printf("GDBRemoteCommunicationServerCommon::%s end", __FUNCTION__); + } + if (log) + log->Printf("GDBRemoteCommunicationServerCommon::%s end", __FUNCTION__); #endif - return SendErrorResponse (5); - + return SendErrorResponse(5); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_qGroupName (StringExtractorGDBRemote &packet) -{ +GDBRemoteCommunicationServerCommon::Handle_qGroupName( + StringExtractorGDBRemote &packet) { #if !defined(LLDB_DISABLE_POSIX) - // Packet format: "qGroupName:%i" where %i is the gid - packet.SetFilePos(::strlen ("qGroupName:")); - uint32_t gid = packet.GetU32 (UINT32_MAX); - if (gid != UINT32_MAX) - { - std::string name; - if (HostInfo::LookupGroupName(gid, name)) - { - StreamString response; - response.PutCStringAsRawHex8 (name.c_str()); - return SendPacketNoLock (response.GetData(), response.GetSize()); - } + // Packet format: "qGroupName:%i" where %i is the gid + packet.SetFilePos(::strlen("qGroupName:")); + uint32_t gid = packet.GetU32(UINT32_MAX); + if (gid != UINT32_MAX) { + std::string name; + if (HostInfo::LookupGroupName(gid, name)) { + StreamString response; + response.PutCStringAsRawHex8(name.c_str()); + return SendPacketNoLock(response.GetString()); } + } #endif - return SendErrorResponse (6); + return SendErrorResponse(6); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_qSpeedTest (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen ("qSpeedTest:")); - - std::string key; - std::string value; - bool success = packet.GetNameColonValue(key, value); - if (success && key.compare("response_size") == 0) - { - uint32_t response_size = StringConvert::ToUInt32(value.c_str(), 0, 0, &success); - if (success) - { - if (response_size == 0) - return SendOKResponse(); - StreamString response; - uint32_t bytes_left = response_size; - response.PutCString("data:"); - while (bytes_left > 0) - { - if (bytes_left >= 26) - { - response.PutCString("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); - bytes_left -= 26; - } - else - { - response.Printf ("%*.*s;", bytes_left, bytes_left, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); - bytes_left = 0; - } - } - return SendPacketNoLock (response.GetData(), response.GetSize()); +GDBRemoteCommunicationServerCommon::Handle_qSpeedTest( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("qSpeedTest:")); + + llvm::StringRef key; + llvm::StringRef value; + bool success = packet.GetNameColonValue(key, value); + if (success && key.equals("response_size")) { + uint32_t response_size = 0; + if (!value.getAsInteger(0, response_size)) { + if (response_size == 0) + return SendOKResponse(); + StreamString response; + uint32_t bytes_left = response_size; + response.PutCString("data:"); + while (bytes_left > 0) { + if (bytes_left >= 26) { + response.PutCString("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); + bytes_left -= 26; + } else { + response.Printf("%*.*s;", bytes_left, bytes_left, + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); + bytes_left = 0; } + } + return SendPacketNoLock(response.GetString()); } - return SendErrorResponse (7); + } + return SendErrorResponse(7); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_vFile_Open (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen("vFile:open:")); - std::string path; - packet.GetHexByteStringTerminatedBy(path,','); - if (!path.empty()) - { - if (packet.GetChar() == ',') - { - uint32_t flags = File::ConvertOpenOptionsForPOSIXOpen( - packet.GetHexMaxU32(false, 0)); - if (packet.GetChar() == ',') - { - mode_t mode = packet.GetHexMaxU32(false, 0600); - Error error; - const FileSpec path_spec{path, true}; - int fd = ::open(path_spec.GetCString(), flags, mode); - const int save_errno = fd == -1 ? errno : 0; - StreamString response; - response.PutChar('F'); - response.Printf("%i", fd); - if (save_errno) - response.Printf(",%i", save_errno); - return SendPacketNoLock(response.GetData(), response.GetSize()); - } - } +GDBRemoteCommunicationServerCommon::Handle_vFile_Open( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("vFile:open:")); + std::string path; + packet.GetHexByteStringTerminatedBy(path, ','); + if (!path.empty()) { + if (packet.GetChar() == ',') { + uint32_t flags = + File::ConvertOpenOptionsForPOSIXOpen(packet.GetHexMaxU32(false, 0)); + if (packet.GetChar() == ',') { + mode_t mode = packet.GetHexMaxU32(false, 0600); + Error error; + const FileSpec path_spec{path, true}; + int fd = ::open(path_spec.GetCString(), flags, mode); + const int save_errno = fd == -1 ? errno : 0; + StreamString response; + response.PutChar('F'); + response.Printf("%i", fd); + if (save_errno) + response.Printf(",%i", save_errno); + return SendPacketNoLock(response.GetString()); + } } - return SendErrorResponse(18); + } + return SendErrorResponse(18); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_vFile_Close (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen("vFile:close:")); - int fd = packet.GetS32(-1); - Error error; - int err = -1; - int save_errno = 0; - if (fd >= 0) - { - err = close(fd); - save_errno = err == -1 ? errno : 0; - } - else - { - save_errno = EINVAL; - } - StreamString response; - response.PutChar('F'); - response.Printf("%i", err); - if (save_errno) - response.Printf(",%i", save_errno); - return SendPacketNoLock(response.GetData(), response.GetSize()); +GDBRemoteCommunicationServerCommon::Handle_vFile_Close( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("vFile:close:")); + int fd = packet.GetS32(-1); + Error error; + int err = -1; + int save_errno = 0; + if (fd >= 0) { + err = close(fd); + save_errno = err == -1 ? errno : 0; + } else { + save_errno = EINVAL; + } + StreamString response; + response.PutChar('F'); + response.Printf("%i", err); + if (save_errno) + response.Printf(",%i", save_errno); + return SendPacketNoLock(response.GetString()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_vFile_pRead (StringExtractorGDBRemote &packet) -{ +GDBRemoteCommunicationServerCommon::Handle_vFile_pRead( + StringExtractorGDBRemote &packet) { #ifdef _WIN32 - // Not implemented on Windows - return SendUnimplementedResponse("GDBRemoteCommunicationServerCommon::Handle_vFile_pRead() unimplemented"); + // Not implemented on Windows + return SendUnimplementedResponse( + "GDBRemoteCommunicationServerCommon::Handle_vFile_pRead() unimplemented"); #else - StreamGDBRemote response; - packet.SetFilePos(::strlen("vFile:pread:")); - int fd = packet.GetS32(-1); - if (packet.GetChar() == ',') - { - uint64_t count = packet.GetU64(UINT64_MAX); - if (packet.GetChar() == ',') - { - uint64_t offset = packet.GetU64(UINT32_MAX); - if (count == UINT64_MAX) - { - response.Printf("F-1:%i", EINVAL); - return SendPacketNoLock(response.GetData(), response.GetSize()); - } - - std::string buffer(count, 0); - const ssize_t bytes_read = ::pread (fd, &buffer[0], buffer.size(), offset); - const int save_errno = bytes_read == -1 ? errno : 0; - response.PutChar('F'); - response.Printf("%zi", bytes_read); - if (save_errno) - response.Printf(",%i", save_errno); - else - { - response.PutChar(';'); - response.PutEscapedBytes(&buffer[0], bytes_read); - } - return SendPacketNoLock(response.GetData(), response.GetSize()); - } + StreamGDBRemote response; + packet.SetFilePos(::strlen("vFile:pread:")); + int fd = packet.GetS32(-1); + if (packet.GetChar() == ',') { + uint64_t count = packet.GetU64(UINT64_MAX); + if (packet.GetChar() == ',') { + uint64_t offset = packet.GetU64(UINT32_MAX); + if (count == UINT64_MAX) { + response.Printf("F-1:%i", EINVAL); + return SendPacketNoLock(response.GetString()); + } + + std::string buffer(count, 0); + const ssize_t bytes_read = ::pread(fd, &buffer[0], buffer.size(), offset); + const int save_errno = bytes_read == -1 ? errno : 0; + response.PutChar('F'); + response.Printf("%zi", bytes_read); + if (save_errno) + response.Printf(",%i", save_errno); + else { + response.PutChar(';'); + response.PutEscapedBytes(&buffer[0], bytes_read); + } + return SendPacketNoLock(response.GetString()); } - return SendErrorResponse(21); + } + return SendErrorResponse(21); #endif } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_vFile_pWrite (StringExtractorGDBRemote &packet) -{ +GDBRemoteCommunicationServerCommon::Handle_vFile_pWrite( + StringExtractorGDBRemote &packet) { #ifdef _WIN32 - return SendUnimplementedResponse("GDBRemoteCommunicationServerCommon::Handle_vFile_pWrite() unimplemented"); + return SendUnimplementedResponse("GDBRemoteCommunicationServerCommon::Handle_" + "vFile_pWrite() unimplemented"); #else - packet.SetFilePos(::strlen("vFile:pwrite:")); - - StreamGDBRemote response; - response.PutChar('F'); - - int fd = packet.GetU32(UINT32_MAX); - if (packet.GetChar() == ',') - { - off_t offset = packet.GetU64(UINT32_MAX); - if (packet.GetChar() == ',') - { - std::string buffer; - if (packet.GetEscapedBinaryData(buffer)) - { - const ssize_t bytes_written = ::pwrite (fd, buffer.data(), buffer.size(), offset); - const int save_errno = bytes_written == -1 ? errno : 0; - response.Printf("%zi", bytes_written); - if (save_errno) - response.Printf(",%i", save_errno); - } - else - { - response.Printf ("-1,%i", EINVAL); - } - return SendPacketNoLock(response.GetData(), response.GetSize()); - } + packet.SetFilePos(::strlen("vFile:pwrite:")); + + StreamGDBRemote response; + response.PutChar('F'); + + int fd = packet.GetU32(UINT32_MAX); + if (packet.GetChar() == ',') { + off_t offset = packet.GetU64(UINT32_MAX); + if (packet.GetChar() == ',') { + std::string buffer; + if (packet.GetEscapedBinaryData(buffer)) { + const ssize_t bytes_written = + ::pwrite(fd, buffer.data(), buffer.size(), offset); + const int save_errno = bytes_written == -1 ? errno : 0; + response.Printf("%zi", bytes_written); + if (save_errno) + response.Printf(",%i", save_errno); + } else { + response.Printf("-1,%i", EINVAL); + } + return SendPacketNoLock(response.GetString()); } - return SendErrorResponse(27); + } + return SendErrorResponse(27); #endif } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_vFile_Size (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen("vFile:size:")); - std::string path; - packet.GetHexByteString(path); - if (!path.empty()) - { - lldb::user_id_t retcode = FileSystem::GetFileSize(FileSpec(path.c_str(), false)); - StreamString response; - response.PutChar('F'); - response.PutHex64(retcode); - if (retcode == UINT64_MAX) - { - response.PutChar(','); - response.PutHex64(retcode); // TODO: replace with Host::GetSyswideErrorCode() - } - return SendPacketNoLock(response.GetData(), response.GetSize()); +GDBRemoteCommunicationServerCommon::Handle_vFile_Size( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("vFile:size:")); + std::string path; + packet.GetHexByteString(path); + if (!path.empty()) { + lldb::user_id_t retcode = FileSystem::GetFileSize(FileSpec(path, false)); + StreamString response; + response.PutChar('F'); + response.PutHex64(retcode); + if (retcode == UINT64_MAX) { + response.PutChar(','); + response.PutHex64( + retcode); // TODO: replace with Host::GetSyswideErrorCode() } - return SendErrorResponse(22); + return SendPacketNoLock(response.GetString()); + } + return SendErrorResponse(22); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_vFile_Mode (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen("vFile:mode:")); - std::string path; - packet.GetHexByteString(path); - if (!path.empty()) - { - Error error; - const uint32_t mode = File::GetPermissions(FileSpec{path, true}, error); - StreamString response; - response.Printf("F%u", mode); - if (mode == 0 || error.Fail()) - response.Printf(",%i", (int)error.GetError()); - return SendPacketNoLock(response.GetData(), response.GetSize()); - } - return SendErrorResponse(23); +GDBRemoteCommunicationServerCommon::Handle_vFile_Mode( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("vFile:mode:")); + std::string path; + packet.GetHexByteString(path); + if (!path.empty()) { + Error error; + const uint32_t mode = File::GetPermissions(FileSpec{path, true}, error); + StreamString response; + response.Printf("F%u", mode); + if (mode == 0 || error.Fail()) + response.Printf(",%i", (int)error.GetError()); + return SendPacketNoLock(response.GetString()); + } + return SendErrorResponse(23); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_vFile_Exists (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen("vFile:exists:")); - std::string path; - packet.GetHexByteString(path); - if (!path.empty()) - { - bool retcode = FileSystem::GetFileExists(FileSpec(path.c_str(), false)); - StreamString response; - response.PutChar('F'); - response.PutChar(','); - if (retcode) - response.PutChar('1'); - else - response.PutChar('0'); - return SendPacketNoLock(response.GetData(), response.GetSize()); - } - return SendErrorResponse(24); +GDBRemoteCommunicationServerCommon::Handle_vFile_Exists( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("vFile:exists:")); + std::string path; + packet.GetHexByteString(path); + if (!path.empty()) { + bool retcode = FileSystem::GetFileExists(FileSpec(path, false)); + StreamString response; + response.PutChar('F'); + response.PutChar(','); + if (retcode) + response.PutChar('1'); + else + response.PutChar('0'); + return SendPacketNoLock(response.GetString()); + } + return SendErrorResponse(24); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_vFile_symlink (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen("vFile:symlink:")); - std::string dst, src; - packet.GetHexByteStringTerminatedBy(dst, ','); - packet.GetChar(); // Skip ',' char - packet.GetHexByteString(src); - Error error = FileSystem::Symlink(FileSpec{src, true}, FileSpec{dst, false}); - StreamString response; - response.Printf("F%u,%u", error.GetError(), error.GetError()); - return SendPacketNoLock(response.GetData(), response.GetSize()); +GDBRemoteCommunicationServerCommon::Handle_vFile_symlink( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("vFile:symlink:")); + std::string dst, src; + packet.GetHexByteStringTerminatedBy(dst, ','); + packet.GetChar(); // Skip ',' char + packet.GetHexByteString(src); + Error error = FileSystem::Symlink(FileSpec{src, true}, FileSpec{dst, false}); + StreamString response; + response.Printf("F%u,%u", error.GetError(), error.GetError()); + return SendPacketNoLock(response.GetString()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_vFile_unlink (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen("vFile:unlink:")); - std::string path; - packet.GetHexByteString(path); - Error error = FileSystem::Unlink(FileSpec{path, true}); - StreamString response; - response.Printf("F%u,%u", error.GetError(), error.GetError()); - return SendPacketNoLock(response.GetData(), response.GetSize()); +GDBRemoteCommunicationServerCommon::Handle_vFile_unlink( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("vFile:unlink:")); + std::string path; + packet.GetHexByteString(path); + Error error = FileSystem::Unlink(FileSpec{path, true}); + StreamString response; + response.Printf("F%u,%u", error.GetError(), error.GetError()); + return SendPacketNoLock(response.GetString()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_qPlatform_shell (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen("qPlatform_shell:")); - std::string path; - std::string working_dir; - packet.GetHexByteStringTerminatedBy(path,','); - if (!path.empty()) - { - if (packet.GetChar() == ',') - { - // FIXME: add timeout to qPlatform_shell packet - // uint32_t timeout = packet.GetHexMaxU32(false, 32); - uint32_t timeout = 10; - if (packet.GetChar() == ',') - packet.GetHexByteString(working_dir); - int status, signo; - std::string output; - Error err = Host::RunShellCommand(path.c_str(), - FileSpec{working_dir, true}, - &status, &signo, &output, timeout); - StreamGDBRemote response; - if (err.Fail()) - { - response.PutCString("F,"); - response.PutHex32(UINT32_MAX); - } - else - { - response.PutCString("F,"); - response.PutHex32(status); - response.PutChar(','); - response.PutHex32(signo); - response.PutChar(','); - response.PutEscapedBytes(output.c_str(), output.size()); - } - return SendPacketNoLock(response.GetData(), response.GetSize()); - } +GDBRemoteCommunicationServerCommon::Handle_qPlatform_shell( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("qPlatform_shell:")); + std::string path; + std::string working_dir; + packet.GetHexByteStringTerminatedBy(path, ','); + if (!path.empty()) { + if (packet.GetChar() == ',') { + // FIXME: add timeout to qPlatform_shell packet + // uint32_t timeout = packet.GetHexMaxU32(false, 32); + uint32_t timeout = 10; + if (packet.GetChar() == ',') + packet.GetHexByteString(working_dir); + int status, signo; + std::string output; + Error err = + Host::RunShellCommand(path.c_str(), FileSpec{working_dir, true}, + &status, &signo, &output, timeout); + StreamGDBRemote response; + if (err.Fail()) { + response.PutCString("F,"); + response.PutHex32(UINT32_MAX); + } else { + response.PutCString("F,"); + response.PutHex32(status); + response.PutChar(','); + response.PutHex32(signo); + response.PutChar(','); + response.PutEscapedBytes(output.c_str(), output.size()); + } + return SendPacketNoLock(response.GetString()); } - return SendErrorResponse(24); + } + return SendErrorResponse(24); } - GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_vFile_Stat (StringExtractorGDBRemote &packet) -{ - return SendUnimplementedResponse("GDBRemoteCommunicationServerCommon::Handle_vFile_Stat() unimplemented"); +GDBRemoteCommunicationServerCommon::Handle_vFile_Stat( + StringExtractorGDBRemote &packet) { + return SendUnimplementedResponse( + "GDBRemoteCommunicationServerCommon::Handle_vFile_Stat() unimplemented"); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_vFile_MD5 (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen("vFile:MD5:")); - std::string path; - packet.GetHexByteString(path); - if (!path.empty()) - { - uint64_t a,b; - StreamGDBRemote response; - if (!FileSystem::CalculateMD5(FileSpec(path.c_str(), false), a, b)) - { - response.PutCString("F,"); - response.PutCString("x"); - } - else - { - response.PutCString("F,"); - response.PutHex64(a); - response.PutHex64(b); - } - return SendPacketNoLock(response.GetData(), response.GetSize()); +GDBRemoteCommunicationServerCommon::Handle_vFile_MD5( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("vFile:MD5:")); + std::string path; + packet.GetHexByteString(path); + if (!path.empty()) { + uint64_t a, b; + StreamGDBRemote response; + if (!FileSystem::CalculateMD5(FileSpec(path, false), a, b)) { + response.PutCString("F,"); + response.PutCString("x"); + } else { + response.PutCString("F,"); + response.PutHex64(a); + response.PutHex64(b); } - return SendErrorResponse(25); + return SendPacketNoLock(response.GetString()); + } + return SendErrorResponse(25); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_qPlatform_mkdir (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen("qPlatform_mkdir:")); - mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX); - if (packet.GetChar() == ',') - { - std::string path; - packet.GetHexByteString(path); - Error error = FileSystem::MakeDirectory(FileSpec{path, false}, mode); - - StreamGDBRemote response; - response.Printf("F%u", error.GetError()); - - return SendPacketNoLock(response.GetData(), response.GetSize()); - } - return SendErrorResponse(20); +GDBRemoteCommunicationServerCommon::Handle_qPlatform_mkdir( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("qPlatform_mkdir:")); + mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX); + if (packet.GetChar() == ',') { + std::string path; + packet.GetHexByteString(path); + Error error = FileSystem::MakeDirectory(FileSpec{path, false}, mode); + + StreamGDBRemote response; + response.Printf("F%u", error.GetError()); + + return SendPacketNoLock(response.GetString()); + } + return SendErrorResponse(20); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_qPlatform_chmod (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen("qPlatform_chmod:")); +GDBRemoteCommunicationServerCommon::Handle_qPlatform_chmod( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("qPlatform_chmod:")); - mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX); - if (packet.GetChar() == ',') - { - std::string path; - packet.GetHexByteString(path); - Error error = FileSystem::SetFilePermissions(FileSpec{path, true}, mode); + mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX); + if (packet.GetChar() == ',') { + std::string path; + packet.GetHexByteString(path); + Error error = FileSystem::SetFilePermissions(FileSpec{path, true}, mode); - StreamGDBRemote response; - response.Printf("F%u", error.GetError()); + StreamGDBRemote response; + response.Printf("F%u", error.GetError()); - return SendPacketNoLock(response.GetData(), response.GetSize()); - } - return SendErrorResponse(19); + return SendPacketNoLock(response.GetString()); + } + return SendErrorResponse(19); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_qSupported (StringExtractorGDBRemote &packet) -{ - StreamGDBRemote response; - - // Features common to lldb-platform and llgs. - uint32_t max_packet_size = 128 * 1024; // 128KBytes is a reasonable max packet size--debugger can always use less - response.Printf ("PacketSize=%x", max_packet_size); - - response.PutCString (";QStartNoAckMode+"); - response.PutCString (";QThreadSuffixSupported+"); - response.PutCString (";QListThreadsInStopReply+"); - response.PutCString (";qEcho+"); +GDBRemoteCommunicationServerCommon::Handle_qSupported( + StringExtractorGDBRemote &packet) { + StreamGDBRemote response; + + // Features common to lldb-platform and llgs. + uint32_t max_packet_size = 128 * 1024; // 128KBytes is a reasonable max packet + // size--debugger can always use less + response.Printf("PacketSize=%x", max_packet_size); + + response.PutCString(";QStartNoAckMode+"); + response.PutCString(";QThreadSuffixSupported+"); + response.PutCString(";QListThreadsInStopReply+"); + response.PutCString(";qEcho+"); #if defined(__linux__) - response.PutCString (";qXfer:auxv:read+"); + response.PutCString(";qXfer:auxv:read+"); #endif - return SendPacketNoLock(response.GetData(), response.GetSize()); + return SendPacketNoLock(response.GetString()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_QThreadSuffixSupported (StringExtractorGDBRemote &packet) -{ - m_thread_suffix_supported = true; - return SendOKResponse(); +GDBRemoteCommunicationServerCommon::Handle_QThreadSuffixSupported( + StringExtractorGDBRemote &packet) { + m_thread_suffix_supported = true; + return SendOKResponse(); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_QListThreadsInStopReply (StringExtractorGDBRemote &packet) -{ - m_list_threads_in_stop_reply = true; - return SendOKResponse(); +GDBRemoteCommunicationServerCommon::Handle_QListThreadsInStopReply( + StringExtractorGDBRemote &packet) { + m_list_threads_in_stop_reply = true; + return SendOKResponse(); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_QSetDetachOnError (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen ("QSetDetachOnError:")); - if (packet.GetU32(0)) - m_process_launch_info.GetFlags().Set (eLaunchFlagDetachOnError); - else - m_process_launch_info.GetFlags().Clear (eLaunchFlagDetachOnError); - return SendOKResponse (); +GDBRemoteCommunicationServerCommon::Handle_QSetDetachOnError( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("QSetDetachOnError:")); + if (packet.GetU32(0)) + m_process_launch_info.GetFlags().Set(eLaunchFlagDetachOnError); + else + m_process_launch_info.GetFlags().Clear(eLaunchFlagDetachOnError); + return SendOKResponse(); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_QStartNoAckMode (StringExtractorGDBRemote &packet) -{ - // Send response first before changing m_send_acks to we ack this packet - PacketResult packet_result = SendOKResponse (); - m_send_acks = false; - return packet_result; +GDBRemoteCommunicationServerCommon::Handle_QStartNoAckMode( + StringExtractorGDBRemote &packet) { + // Send response first before changing m_send_acks to we ack this packet + PacketResult packet_result = SendOKResponse(); + m_send_acks = false; + return packet_result; } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_QSetSTDIN (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen ("QSetSTDIN:")); - FileAction file_action; - std::string path; - packet.GetHexByteString(path); - const bool read = false; - const bool write = true; - if (file_action.Open(STDIN_FILENO, FileSpec{path, false}, read, write)) - { - m_process_launch_info.AppendFileAction(file_action); - return SendOKResponse (); - } - return SendErrorResponse (15); +GDBRemoteCommunicationServerCommon::Handle_QSetSTDIN( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("QSetSTDIN:")); + FileAction file_action; + std::string path; + packet.GetHexByteString(path); + const bool read = true; + const bool write = false; + if (file_action.Open(STDIN_FILENO, FileSpec{path, false}, read, write)) { + m_process_launch_info.AppendFileAction(file_action); + return SendOKResponse(); + } + return SendErrorResponse(15); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_QSetSTDOUT (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen ("QSetSTDOUT:")); - FileAction file_action; - std::string path; - packet.GetHexByteString(path); - const bool read = true; - const bool write = false; - if (file_action.Open(STDOUT_FILENO, FileSpec{path, false}, read, write)) - { - m_process_launch_info.AppendFileAction(file_action); - return SendOKResponse (); - } - return SendErrorResponse (16); +GDBRemoteCommunicationServerCommon::Handle_QSetSTDOUT( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("QSetSTDOUT:")); + FileAction file_action; + std::string path; + packet.GetHexByteString(path); + const bool read = false; + const bool write = true; + if (file_action.Open(STDOUT_FILENO, FileSpec{path, false}, read, write)) { + m_process_launch_info.AppendFileAction(file_action); + return SendOKResponse(); + } + return SendErrorResponse(16); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_QSetSTDERR (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen ("QSetSTDERR:")); - FileAction file_action; - std::string path; - packet.GetHexByteString(path); - const bool read = true; - const bool write = false; - if (file_action.Open(STDERR_FILENO, FileSpec{path, false}, read, write)) - { - m_process_launch_info.AppendFileAction(file_action); - return SendOKResponse (); - } - return SendErrorResponse (17); +GDBRemoteCommunicationServerCommon::Handle_QSetSTDERR( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("QSetSTDERR:")); + FileAction file_action; + std::string path; + packet.GetHexByteString(path); + const bool read = false; + const bool write = true; + if (file_action.Open(STDERR_FILENO, FileSpec{path, false}, read, write)) { + m_process_launch_info.AppendFileAction(file_action); + return SendOKResponse(); + } + return SendErrorResponse(17); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_qLaunchSuccess (StringExtractorGDBRemote &packet) -{ - if (m_process_launch_error.Success()) - return SendOKResponse(); - StreamString response; - response.PutChar('E'); - response.PutCString(m_process_launch_error.AsCString("<unknown error>")); - return SendPacketNoLock (response.GetData(), response.GetSize()); +GDBRemoteCommunicationServerCommon::Handle_qLaunchSuccess( + StringExtractorGDBRemote &packet) { + if (m_process_launch_error.Success()) + return SendOKResponse(); + StreamString response; + response.PutChar('E'); + response.PutCString(m_process_launch_error.AsCString("<unknown error>")); + return SendPacketNoLock(response.GetString()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_QEnvironment (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen ("QEnvironment:")); - const uint32_t bytes_left = packet.GetBytesLeft(); - if (bytes_left > 0) - { - m_process_launch_info.GetEnvironmentEntries ().AppendArgument (packet.Peek()); - return SendOKResponse (); - } - return SendErrorResponse (12); +GDBRemoteCommunicationServerCommon::Handle_QEnvironment( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("QEnvironment:")); + const uint32_t bytes_left = packet.GetBytesLeft(); + if (bytes_left > 0) { + m_process_launch_info.GetEnvironmentEntries().AppendArgument( + llvm::StringRef::withNullAsEmpty(packet.Peek())); + return SendOKResponse(); + } + return SendErrorResponse(12); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_QEnvironmentHexEncoded (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen("QEnvironmentHexEncoded:")); - const uint32_t bytes_left = packet.GetBytesLeft(); - if (bytes_left > 0) - { - std::string str; - packet.GetHexByteString(str); - m_process_launch_info.GetEnvironmentEntries().AppendArgument(str.c_str()); - return SendOKResponse(); - } - return SendErrorResponse(12); +GDBRemoteCommunicationServerCommon::Handle_QEnvironmentHexEncoded( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("QEnvironmentHexEncoded:")); + const uint32_t bytes_left = packet.GetBytesLeft(); + if (bytes_left > 0) { + std::string str; + packet.GetHexByteString(str); + m_process_launch_info.GetEnvironmentEntries().AppendArgument(str); + return SendOKResponse(); + } + return SendErrorResponse(12); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_QLaunchArch (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen ("QLaunchArch:")); - const uint32_t bytes_left = packet.GetBytesLeft(); - if (bytes_left > 0) - { - const char* arch_triple = packet.Peek(); - ArchSpec arch_spec(arch_triple,NULL); - m_process_launch_info.SetArchitecture(arch_spec); - return SendOKResponse(); - } - return SendErrorResponse(13); +GDBRemoteCommunicationServerCommon::Handle_QLaunchArch( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("QLaunchArch:")); + const uint32_t bytes_left = packet.GetBytesLeft(); + if (bytes_left > 0) { + const char *arch_triple = packet.Peek(); + ArchSpec arch_spec(arch_triple, NULL); + m_process_launch_info.SetArchitecture(arch_spec); + return SendOKResponse(); + } + return SendErrorResponse(13); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_A (StringExtractorGDBRemote &packet) -{ - // The 'A' packet is the most over designed packet ever here with - // redundant argument indexes, redundant argument lengths and needed hex - // encoded argument string values. Really all that is needed is a comma - // separated hex encoded argument value list, but we will stay true to the - // documented version of the 'A' packet here... - - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - int actual_arg_index = 0; - - packet.SetFilePos(1); // Skip the 'A' - bool success = true; - while (success && packet.GetBytesLeft() > 0) - { - // Decode the decimal argument string length. This length is the - // number of hex nibbles in the argument string value. - const uint32_t arg_len = packet.GetU32(UINT32_MAX); - if (arg_len == UINT32_MAX) +GDBRemoteCommunicationServerCommon::Handle_A(StringExtractorGDBRemote &packet) { + // The 'A' packet is the most over designed packet ever here with + // redundant argument indexes, redundant argument lengths and needed hex + // encoded argument string values. Really all that is needed is a comma + // separated hex encoded argument value list, but we will stay true to the + // documented version of the 'A' packet here... + + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + int actual_arg_index = 0; + + packet.SetFilePos(1); // Skip the 'A' + bool success = true; + while (success && packet.GetBytesLeft() > 0) { + // Decode the decimal argument string length. This length is the + // number of hex nibbles in the argument string value. + const uint32_t arg_len = packet.GetU32(UINT32_MAX); + if (arg_len == UINT32_MAX) + success = false; + else { + // Make sure the argument hex string length is followed by a comma + if (packet.GetChar() != ',') + success = false; + else { + // Decode the argument index. We ignore this really because + // who would really send down the arguments in a random order??? + const uint32_t arg_idx = packet.GetU32(UINT32_MAX); + if (arg_idx == UINT32_MAX) + success = false; + else { + // Make sure the argument index is followed by a comma + if (packet.GetChar() != ',') success = false; - else - { - // Make sure the argument hex string length is followed by a comma - if (packet.GetChar() != ',') - success = false; - else - { - // Decode the argument index. We ignore this really because - // who would really send down the arguments in a random order??? - const uint32_t arg_idx = packet.GetU32(UINT32_MAX); - if (arg_idx == UINT32_MAX) - success = false; - else - { - // Make sure the argument index is followed by a comma - if (packet.GetChar() != ',') - success = false; - else - { - // Decode the argument string value from hex bytes - // back into a UTF8 string and make sure the length - // matches the one supplied in the packet - std::string arg; - if (packet.GetHexByteStringFixedLength(arg, arg_len) != (arg_len / 2)) - success = false; - else - { - // If there are any bytes left - if (packet.GetBytesLeft()) - { - if (packet.GetChar() != ',') - success = false; - } - - if (success) - { - if (arg_idx == 0) - m_process_launch_info.GetExecutableFile().SetFile(arg.c_str(), false); - m_process_launch_info.GetArguments().AppendArgument(arg.c_str()); - if (log) - log->Printf ("LLGSPacketHandler::%s added arg %d: \"%s\"", __FUNCTION__, actual_arg_index, arg.c_str ()); - ++actual_arg_index; - } - } - } - } + else { + // Decode the argument string value from hex bytes + // back into a UTF8 string and make sure the length + // matches the one supplied in the packet + std::string arg; + if (packet.GetHexByteStringFixedLength(arg, arg_len) != + (arg_len / 2)) + success = false; + else { + // If there are any bytes left + if (packet.GetBytesLeft()) { + if (packet.GetChar() != ',') + success = false; + } + + if (success) { + if (arg_idx == 0) + m_process_launch_info.GetExecutableFile().SetFile(arg, false); + m_process_launch_info.GetArguments().AppendArgument(arg); + if (log) + log->Printf("LLGSPacketHandler::%s added arg %d: \"%s\"", + __FUNCTION__, actual_arg_index, arg.c_str()); + ++actual_arg_index; + } } + } } + } } - - if (success) - { - m_process_launch_error = LaunchProcess (); - if (m_process_launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) - { - return SendOKResponse (); - } - else - { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf("LLGSPacketHandler::%s failed to launch exe: %s", - __FUNCTION__, - m_process_launch_error.AsCString()); - - } + } + + if (success) { + m_process_launch_error = LaunchProcess(); + if (m_process_launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) { + return SendOKResponse(); + } else { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf("LLGSPacketHandler::%s failed to launch exe: %s", + __FUNCTION__, m_process_launch_error.AsCString()); } - return SendErrorResponse (8); + } + return SendErrorResponse(8); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_qEcho (StringExtractorGDBRemote &packet) -{ - // Just echo back the exact same packet for qEcho... - return SendPacketNoLock(packet.GetStringRef().c_str(), packet.GetStringRef().size()); +GDBRemoteCommunicationServerCommon::Handle_qEcho( + StringExtractorGDBRemote &packet) { + // Just echo back the exact same packet for qEcho... + return SendPacketNoLock(packet.GetStringRef()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_qModuleInfo (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen ("qModuleInfo:")); - - std::string module_path; - packet.GetHexByteStringTerminatedBy(module_path, ';'); - if (module_path.empty()) - return SendErrorResponse (1); - - if (packet.GetChar() != ';') - return SendErrorResponse (2); - - std::string triple; - packet.GetHexByteString(triple); - ArchSpec arch(triple.c_str()); - - const FileSpec req_module_path_spec(module_path.c_str(), true); - const FileSpec module_path_spec = FindModuleFile(req_module_path_spec.GetPath(), arch); - const ModuleSpec module_spec(module_path_spec, arch); - - ModuleSpecList module_specs; - if (!ObjectFile::GetModuleSpecifications(module_path_spec, 0, 0, module_specs)) - return SendErrorResponse (3); +GDBRemoteCommunicationServerCommon::Handle_qModuleInfo( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("qModuleInfo:")); + + std::string module_path; + packet.GetHexByteStringTerminatedBy(module_path, ';'); + if (module_path.empty()) + return SendErrorResponse(1); + + if (packet.GetChar() != ';') + return SendErrorResponse(2); + + std::string triple; + packet.GetHexByteString(triple); + + ModuleSpec matched_module_spec = GetModuleInfo(module_path, triple); + if (!matched_module_spec.GetFileSpec()) + return SendErrorResponse(3); + + const auto file_offset = matched_module_spec.GetObjectOffset(); + const auto file_size = matched_module_spec.GetObjectSize(); + const auto uuid_str = matched_module_spec.GetUUID().GetAsString(""); + + StreamGDBRemote response; + + if (uuid_str.empty()) { + std::string md5_hash; + if (!FileSystem::CalculateMD5AsString(matched_module_spec.GetFileSpec(), + file_offset, file_size, md5_hash)) + return SendErrorResponse(5); + response.PutCString("md5:"); + response.PutCStringAsRawHex8(md5_hash.c_str()); + } else { + response.PutCString("uuid:"); + response.PutCStringAsRawHex8(uuid_str.c_str()); + } + response.PutChar(';'); + + const auto &module_arch = matched_module_spec.GetArchitecture(); + response.PutCString("triple:"); + response.PutCStringAsRawHex8(module_arch.GetTriple().getTriple().c_str()); + response.PutChar(';'); + + response.PutCString("file_path:"); + response.PutCStringAsRawHex8(matched_module_spec.GetFileSpec().GetCString()); + response.PutChar(';'); + response.PutCString("file_offset:"); + response.PutHex64(file_offset); + response.PutChar(';'); + response.PutCString("file_size:"); + response.PutHex64(file_size); + response.PutChar(';'); + + return SendPacketNoLock(response.GetString()); +} - ModuleSpec matched_module_spec; - if (!module_specs.FindMatchingModuleSpec(module_spec, matched_module_spec)) - return SendErrorResponse (4); +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerCommon::Handle_jModulesInfo( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("jModulesInfo:")); + + StructuredData::ObjectSP object_sp = StructuredData::ParseJSON(packet.Peek()); + if (!object_sp) + return SendErrorResponse(1); + + StructuredData::Array *packet_array = object_sp->GetAsArray(); + if (!packet_array) + return SendErrorResponse(2); + + JSONArray::SP response_array_sp = std::make_shared<JSONArray>(); + for (size_t i = 0; i < packet_array->GetSize(); ++i) { + StructuredData::Dictionary *query = + packet_array->GetItemAtIndex(i)->GetAsDictionary(); + if (!query) + continue; + std::string file, triple; + if (!query->GetValueForKeyAsString("file", file) || + !query->GetValueForKeyAsString("triple", triple)) + continue; + + ModuleSpec matched_module_spec = GetModuleInfo(file, triple); + if (!matched_module_spec.GetFileSpec()) + continue; const auto file_offset = matched_module_spec.GetObjectOffset(); const auto file_size = matched_module_spec.GetObjectSize(); const auto uuid_str = matched_module_spec.GetUUID().GetAsString(""); - StreamGDBRemote response; - if (uuid_str.empty()) - { - std::string md5_hash; - if (!FileSystem::CalculateMD5AsString(matched_module_spec.GetFileSpec(), file_offset, file_size, md5_hash)) - return SendErrorResponse (5); - response.PutCString ("md5:"); - response.PutCStringAsRawHex8(md5_hash.c_str()); - } - else{ - response.PutCString ("uuid:"); - response.PutCStringAsRawHex8(uuid_str.c_str()); - } - response.PutChar(';'); + continue; + + JSONObject::SP response = std::make_shared<JSONObject>(); + response_array_sp->AppendObject(response); + response->SetObject("uuid", std::make_shared<JSONString>(uuid_str)); + response->SetObject( + "triple", + std::make_shared<JSONString>( + matched_module_spec.GetArchitecture().GetTriple().getTriple())); + response->SetObject("file_path", + std::make_shared<JSONString>( + matched_module_spec.GetFileSpec().GetPath())); + response->SetObject("file_offset", + std::make_shared<JSONNumber>(file_offset)); + response->SetObject("file_size", std::make_shared<JSONNumber>(file_size)); + } + + StreamString response; + response_array_sp->Write(response); + StreamGDBRemote escaped_response; + escaped_response.PutEscapedBytes(response.GetString().data(), + response.GetSize()); + return SendPacketNoLock(escaped_response.GetString()); +} - const auto &module_arch = matched_module_spec.GetArchitecture(); +void GDBRemoteCommunicationServerCommon::CreateProcessInfoResponse( + const ProcessInstanceInfo &proc_info, StreamString &response) { + response.Printf( + "pid:%" PRIu64 ";ppid:%" PRIu64 ";uid:%i;gid:%i;euid:%i;egid:%i;", + proc_info.GetProcessID(), proc_info.GetParentProcessID(), + proc_info.GetUserID(), proc_info.GetGroupID(), + proc_info.GetEffectiveUserID(), proc_info.GetEffectiveGroupID()); + response.PutCString("name:"); + response.PutCStringAsRawHex8(proc_info.GetExecutableFile().GetCString()); + response.PutChar(';'); + const ArchSpec &proc_arch = proc_info.GetArchitecture(); + if (proc_arch.IsValid()) { + const llvm::Triple &proc_triple = proc_arch.GetTriple(); response.PutCString("triple:"); - response.PutCStringAsRawHex8( module_arch.GetTriple().getTriple().c_str()); - response.PutChar(';'); - - response.PutCString("file_path:"); - response.PutCStringAsRawHex8(module_path_spec.GetCString()); - response.PutChar(';'); - response.PutCString("file_offset:"); - response.PutHex64(file_offset); + response.PutCStringAsRawHex8(proc_triple.getTriple().c_str()); response.PutChar(';'); - response.PutCString("file_size:"); - response.PutHex64(file_size); - response.PutChar(';'); - - return SendPacketNoLock(response.GetData(), response.GetSize()); + } } -void -GDBRemoteCommunicationServerCommon::CreateProcessInfoResponse (const ProcessInstanceInfo &proc_info, - StreamString &response) -{ - response.Printf ("pid:%" PRIu64 ";ppid:%" PRIu64 ";uid:%i;gid:%i;euid:%i;egid:%i;", - proc_info.GetProcessID(), - proc_info.GetParentProcessID(), - proc_info.GetUserID(), - proc_info.GetGroupID(), - proc_info.GetEffectiveUserID(), - proc_info.GetEffectiveGroupID()); - response.PutCString ("name:"); - response.PutCStringAsRawHex8(proc_info.GetExecutableFile().GetCString()); +void GDBRemoteCommunicationServerCommon:: + CreateProcessInfoResponse_DebugServerStyle( + const ProcessInstanceInfo &proc_info, StreamString &response) { + response.Printf("pid:%" PRIx64 ";parent-pid:%" PRIx64 + ";real-uid:%x;real-gid:%x;effective-uid:%x;effective-gid:%x;", + proc_info.GetProcessID(), proc_info.GetParentProcessID(), + proc_info.GetUserID(), proc_info.GetGroupID(), + proc_info.GetEffectiveUserID(), + proc_info.GetEffectiveGroupID()); + + const ArchSpec &proc_arch = proc_info.GetArchitecture(); + if (proc_arch.IsValid()) { + const llvm::Triple &proc_triple = proc_arch.GetTriple(); +#if defined(__APPLE__) + // We'll send cputype/cpusubtype. + const uint32_t cpu_type = proc_arch.GetMachOCPUType(); + if (cpu_type != 0) + response.Printf("cputype:%" PRIx32 ";", cpu_type); + + const uint32_t cpu_subtype = proc_arch.GetMachOCPUSubType(); + if (cpu_subtype != 0) + response.Printf("cpusubtype:%" PRIx32 ";", cpu_subtype); + + const std::string vendor = proc_triple.getVendorName(); + if (!vendor.empty()) + response.Printf("vendor:%s;", vendor.c_str()); +#else + // We'll send the triple. + response.PutCString("triple:"); + response.PutCStringAsRawHex8(proc_triple.getTriple().c_str()); response.PutChar(';'); - const ArchSpec &proc_arch = proc_info.GetArchitecture(); - if (proc_arch.IsValid()) - { - const llvm::Triple &proc_triple = proc_arch.GetTriple(); - response.PutCString("triple:"); - response.PutCStringAsRawHex8(proc_triple.getTriple().c_str()); - response.PutChar(';'); +#endif + std::string ostype = proc_triple.getOSName(); + // Adjust so ostype reports ios for Apple/ARM and Apple/ARM64. + if (proc_triple.getVendor() == llvm::Triple::Apple) { + switch (proc_triple.getArch()) { + case llvm::Triple::arm: + case llvm::Triple::thumb: + case llvm::Triple::aarch64: + ostype = "ios"; + break; + default: + // No change. + break; + } + } + response.Printf("ostype:%s;", ostype.c_str()); + + switch (proc_arch.GetByteOrder()) { + case lldb::eByteOrderLittle: + response.PutCString("endian:little;"); + break; + case lldb::eByteOrderBig: + response.PutCString("endian:big;"); + break; + case lldb::eByteOrderPDP: + response.PutCString("endian:pdp;"); + break; + default: + // Nothing. + break; } + // In case of MIPS64, pointer size is depend on ELF ABI + // For N32 the pointer size is 4 and for N64 it is 8 + std::string abi = proc_arch.GetTargetABI(); + if (!abi.empty()) + response.Printf("elf_abi:%s;", abi.c_str()); + response.Printf("ptrsize:%d;", proc_arch.GetAddressByteSize()); + } } -void -GDBRemoteCommunicationServerCommon::CreateProcessInfoResponse_DebugServerStyle ( - const ProcessInstanceInfo &proc_info, StreamString &response) -{ - response.Printf ("pid:%" PRIx64 ";parent-pid:%" PRIx64 ";real-uid:%x;real-gid:%x;effective-uid:%x;effective-gid:%x;", - proc_info.GetProcessID(), - proc_info.GetParentProcessID(), - proc_info.GetUserID(), - proc_info.GetGroupID(), - proc_info.GetEffectiveUserID(), - proc_info.GetEffectiveGroupID()); - - const ArchSpec &proc_arch = proc_info.GetArchitecture(); - if (proc_arch.IsValid()) - { - const llvm::Triple &proc_triple = proc_arch.GetTriple(); -#if defined(__APPLE__) - // We'll send cputype/cpusubtype. - const uint32_t cpu_type = proc_arch.GetMachOCPUType(); - if (cpu_type != 0) - response.Printf ("cputype:%" PRIx32 ";", cpu_type); - - const uint32_t cpu_subtype = proc_arch.GetMachOCPUSubType(); - if (cpu_subtype != 0) - response.Printf ("cpusubtype:%" PRIx32 ";", cpu_subtype); - - const std::string vendor = proc_triple.getVendorName (); - if (!vendor.empty ()) - response.Printf ("vendor:%s;", vendor.c_str ()); +FileSpec GDBRemoteCommunicationServerCommon::FindModuleFile( + const std::string &module_path, const ArchSpec &arch) { +#ifdef __ANDROID__ + return HostInfoAndroid::ResolveLibraryPath(module_path, arch); #else - // We'll send the triple. - response.PutCString("triple:"); - response.PutCStringAsRawHex8(proc_triple.getTriple().c_str()); - response.PutChar(';'); + return FileSpec(module_path, true); #endif - std::string ostype = proc_triple.getOSName (); - // Adjust so ostype reports ios for Apple/ARM and Apple/ARM64. - if (proc_triple.getVendor () == llvm::Triple::Apple) - { - switch (proc_triple.getArch ()) - { - case llvm::Triple::arm: - case llvm::Triple::thumb: - case llvm::Triple::aarch64: - ostype = "ios"; - break; - default: - // No change. - break; - } - } - response.Printf ("ostype:%s;", ostype.c_str ()); +} +ModuleSpec GDBRemoteCommunicationServerCommon::GetModuleInfo( + const std::string &module_path, const std::string &triple) { + ArchSpec arch(triple.c_str()); - switch (proc_arch.GetByteOrder ()) - { - case lldb::eByteOrderLittle: response.PutCString ("endian:little;"); break; - case lldb::eByteOrderBig: response.PutCString ("endian:big;"); break; - case lldb::eByteOrderPDP: response.PutCString ("endian:pdp;"); break; - default: - // Nothing. - break; - } + const FileSpec req_module_path_spec(module_path, true); + const FileSpec module_path_spec = + FindModuleFile(req_module_path_spec.GetPath(), arch); + const ModuleSpec module_spec(module_path_spec, arch); - // In case of MIPS64, pointer size is depend on ELF ABI - // For N32 the pointer size is 4 and for N64 it is 8 - std::string abi = proc_arch.GetTargetABI(); - if (!abi.empty()) - response.Printf("elf_abi:%s;", abi.c_str()); - response.Printf("ptrsize:%d;", proc_arch.GetAddressByteSize()); - } -} + ModuleSpecList module_specs; + if (!ObjectFile::GetModuleSpecifications(module_path_spec, 0, 0, + module_specs)) + return ModuleSpec(); -FileSpec -GDBRemoteCommunicationServerCommon::FindModuleFile(const std::string& module_path, - const ArchSpec& arch) -{ -#ifdef __ANDROID__ - return HostInfoAndroid::ResolveLibraryPath(module_path, arch); -#else - return FileSpec(module_path.c_str(), true); -#endif + ModuleSpec matched_module_spec; + if (!module_specs.FindMatchingModuleSpec(module_spec, matched_module_spec)) + return ModuleSpec(); + + return matched_module_spec; } diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h index d2fd700..321a922 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h @@ -16,8 +16,8 @@ // Other libraries and framework includes // Project includes -#include "lldb/lldb-private-forward.h" #include "lldb/Target/Process.h" +#include "lldb/lldb-private-forward.h" #include "GDBRemoteCommunicationServer.h" #include "GDBRemoteCommunicationServerCommon.h" @@ -29,175 +29,132 @@ namespace process_gdb_remote { class ProcessGDBRemote; -class GDBRemoteCommunicationServerCommon : - public GDBRemoteCommunicationServer -{ +class GDBRemoteCommunicationServerCommon : public GDBRemoteCommunicationServer { public: - GDBRemoteCommunicationServerCommon(const char *comm_name, const char *listener_name); + GDBRemoteCommunicationServerCommon(const char *comm_name, + const char *listener_name); - ~GDBRemoteCommunicationServerCommon() override; + ~GDBRemoteCommunicationServerCommon() override; protected: - ProcessLaunchInfo m_process_launch_info; - Error m_process_launch_error; - ProcessInstanceInfoList m_proc_infos; - uint32_t m_proc_infos_index; - bool m_thread_suffix_supported; - bool m_list_threads_in_stop_reply; + ProcessLaunchInfo m_process_launch_info; + Error m_process_launch_error; + ProcessInstanceInfoList m_proc_infos; + uint32_t m_proc_infos_index; + bool m_thread_suffix_supported; + bool m_list_threads_in_stop_reply; + + PacketResult Handle_A(StringExtractorGDBRemote &packet); - PacketResult - Handle_A (StringExtractorGDBRemote &packet); + PacketResult Handle_qHostInfo(StringExtractorGDBRemote &packet); - PacketResult - Handle_qHostInfo (StringExtractorGDBRemote &packet); + PacketResult Handle_qProcessInfoPID(StringExtractorGDBRemote &packet); - PacketResult - Handle_qProcessInfoPID (StringExtractorGDBRemote &packet); + PacketResult Handle_qfProcessInfo(StringExtractorGDBRemote &packet); - PacketResult - Handle_qfProcessInfo (StringExtractorGDBRemote &packet); + PacketResult Handle_qsProcessInfo(StringExtractorGDBRemote &packet); - PacketResult - Handle_qsProcessInfo (StringExtractorGDBRemote &packet); + PacketResult Handle_qUserName(StringExtractorGDBRemote &packet); - PacketResult - Handle_qUserName (StringExtractorGDBRemote &packet); + PacketResult Handle_qGroupName(StringExtractorGDBRemote &packet); - PacketResult - Handle_qGroupName (StringExtractorGDBRemote &packet); + PacketResult Handle_qSpeedTest(StringExtractorGDBRemote &packet); - PacketResult - Handle_qSpeedTest (StringExtractorGDBRemote &packet); + PacketResult Handle_vFile_Open(StringExtractorGDBRemote &packet); - PacketResult - Handle_vFile_Open (StringExtractorGDBRemote &packet); + PacketResult Handle_vFile_Close(StringExtractorGDBRemote &packet); - PacketResult - Handle_vFile_Close (StringExtractorGDBRemote &packet); + PacketResult Handle_vFile_pRead(StringExtractorGDBRemote &packet); - PacketResult - Handle_vFile_pRead (StringExtractorGDBRemote &packet); + PacketResult Handle_vFile_pWrite(StringExtractorGDBRemote &packet); - PacketResult - Handle_vFile_pWrite (StringExtractorGDBRemote &packet); + PacketResult Handle_vFile_Size(StringExtractorGDBRemote &packet); - PacketResult - Handle_vFile_Size (StringExtractorGDBRemote &packet); + PacketResult Handle_vFile_Mode(StringExtractorGDBRemote &packet); - PacketResult - Handle_vFile_Mode (StringExtractorGDBRemote &packet); + PacketResult Handle_vFile_Exists(StringExtractorGDBRemote &packet); - PacketResult - Handle_vFile_Exists (StringExtractorGDBRemote &packet); + PacketResult Handle_vFile_symlink(StringExtractorGDBRemote &packet); - PacketResult - Handle_vFile_symlink (StringExtractorGDBRemote &packet); + PacketResult Handle_vFile_unlink(StringExtractorGDBRemote &packet); - PacketResult - Handle_vFile_unlink (StringExtractorGDBRemote &packet); + PacketResult Handle_vFile_Stat(StringExtractorGDBRemote &packet); - PacketResult - Handle_vFile_Stat (StringExtractorGDBRemote &packet); + PacketResult Handle_vFile_MD5(StringExtractorGDBRemote &packet); - PacketResult - Handle_vFile_MD5 (StringExtractorGDBRemote &packet); + PacketResult Handle_qEcho(StringExtractorGDBRemote &packet); - PacketResult - Handle_qEcho (StringExtractorGDBRemote &packet); + PacketResult Handle_qModuleInfo(StringExtractorGDBRemote &packet); - PacketResult - Handle_qModuleInfo (StringExtractorGDBRemote &packet); + PacketResult Handle_jModulesInfo(StringExtractorGDBRemote &packet); - PacketResult - Handle_qPlatform_shell (StringExtractorGDBRemote &packet); + PacketResult Handle_qPlatform_shell(StringExtractorGDBRemote &packet); - PacketResult - Handle_qPlatform_mkdir (StringExtractorGDBRemote &packet); + PacketResult Handle_qPlatform_mkdir(StringExtractorGDBRemote &packet); - PacketResult - Handle_qPlatform_chmod (StringExtractorGDBRemote &packet); + PacketResult Handle_qPlatform_chmod(StringExtractorGDBRemote &packet); - PacketResult - Handle_qSupported (StringExtractorGDBRemote &packet); + PacketResult Handle_qSupported(StringExtractorGDBRemote &packet); - PacketResult - Handle_QThreadSuffixSupported (StringExtractorGDBRemote &packet); + PacketResult Handle_QThreadSuffixSupported(StringExtractorGDBRemote &packet); - PacketResult - Handle_QListThreadsInStopReply (StringExtractorGDBRemote &packet); + PacketResult Handle_QListThreadsInStopReply(StringExtractorGDBRemote &packet); - PacketResult - Handle_QSetDetachOnError (StringExtractorGDBRemote &packet); + PacketResult Handle_QSetDetachOnError(StringExtractorGDBRemote &packet); - PacketResult - Handle_QStartNoAckMode (StringExtractorGDBRemote &packet); + PacketResult Handle_QStartNoAckMode(StringExtractorGDBRemote &packet); - PacketResult - Handle_QSetSTDIN (StringExtractorGDBRemote &packet); + PacketResult Handle_QSetSTDIN(StringExtractorGDBRemote &packet); - PacketResult - Handle_QSetSTDOUT (StringExtractorGDBRemote &packet); + PacketResult Handle_QSetSTDOUT(StringExtractorGDBRemote &packet); - PacketResult - Handle_QSetSTDERR (StringExtractorGDBRemote &packet); + PacketResult Handle_QSetSTDERR(StringExtractorGDBRemote &packet); - PacketResult - Handle_qLaunchSuccess (StringExtractorGDBRemote &packet); + PacketResult Handle_qLaunchSuccess(StringExtractorGDBRemote &packet); - PacketResult - Handle_QEnvironment (StringExtractorGDBRemote &packet); + PacketResult Handle_QEnvironment(StringExtractorGDBRemote &packet); - PacketResult - Handle_QEnvironmentHexEncoded (StringExtractorGDBRemote &packet); + PacketResult Handle_QEnvironmentHexEncoded(StringExtractorGDBRemote &packet); - PacketResult - Handle_QLaunchArch (StringExtractorGDBRemote &packet); + PacketResult Handle_QLaunchArch(StringExtractorGDBRemote &packet); - static void - CreateProcessInfoResponse (const ProcessInstanceInfo &proc_info, - StreamString &response); + static void CreateProcessInfoResponse(const ProcessInstanceInfo &proc_info, + StreamString &response); - static void - CreateProcessInfoResponse_DebugServerStyle (const ProcessInstanceInfo &proc_info, - StreamString &response); + static void CreateProcessInfoResponse_DebugServerStyle( + const ProcessInstanceInfo &proc_info, StreamString &response); - template <typename T> - void - RegisterMemberFunctionHandler (StringExtractorGDBRemote::ServerPacketType packet_type, - PacketResult (T::*handler) (StringExtractorGDBRemote& packet)) - { - RegisterPacketHandler(packet_type, - [this, handler] (StringExtractorGDBRemote packet, - Error &error, - bool &interrupt, - bool &quit) - { - return (static_cast<T*>(this)->*handler) (packet); - }); - } + template <typename T> + void RegisterMemberFunctionHandler( + StringExtractorGDBRemote::ServerPacketType packet_type, + PacketResult (T::*handler)(StringExtractorGDBRemote &packet)) { + RegisterPacketHandler(packet_type, + [this, handler](StringExtractorGDBRemote packet, + Error &error, bool &interrupt, + bool &quit) { + return (static_cast<T *>(this)->*handler)(packet); + }); + } - bool - GetThreadSuffixSupported () override - { - return true; - } + //------------------------------------------------------------------ + /// Launch a process with the current launch settings. + /// + /// This method supports running an lldb-gdbserver or similar + /// server in a situation where the startup code has been provided + /// with all the information for a child process to be launched. + /// + /// @return + /// An Error object indicating the success or failure of the + /// launch. + //------------------------------------------------------------------ + virtual Error LaunchProcess() = 0; - //------------------------------------------------------------------ - /// Launch a process with the current launch settings. - /// - /// This method supports running an lldb-gdbserver or similar - /// server in a situation where the startup code has been provided - /// with all the information for a child process to be launched. - /// - /// @return - /// An Error object indicating the success or failure of the - /// launch. - //------------------------------------------------------------------ - virtual Error - LaunchProcess () = 0; + virtual FileSpec FindModuleFile(const std::string &module_path, + const ArchSpec &arch); - virtual FileSpec - FindModuleFile (const std::string& module_path, const ArchSpec& arch); +private: + ModuleSpec GetModuleInfo(const std::string &module_path, + const std::string &triple); }; } // namespace process_gdb_remote diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index c468ba3..bf72673 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -16,13 +16,11 @@ // C Includes // C++ Includes -#include <cstring> #include <chrono> +#include <cstring> #include <thread> // Other libraries and framework includes -#include "llvm/ADT/Triple.h" -#include "lldb/Interpreter/Args.h" #include "lldb/Core/DataBuffer.h" #include "lldb/Core/Log.h" #include "lldb/Core/RegisterValue.h" @@ -36,20 +34,22 @@ #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" #include "lldb/Host/StringConvert.h" -#include "lldb/Host/TimeValue.h" -#include "lldb/Target/FileAction.h" -#include "lldb/Target/MemoryRegionInfo.h" -#include "lldb/Host/common/NativeRegisterContext.h" #include "lldb/Host/common/NativeProcessProtocol.h" +#include "lldb/Host/common/NativeRegisterContext.h" #include "lldb/Host/common/NativeThreadProtocol.h" +#include "lldb/Interpreter/Args.h" +#include "lldb/Target/FileAction.h" +#include "lldb/Target/MemoryRegionInfo.h" #include "lldb/Utility/JSON.h" #include "lldb/Utility/LLDBAssert.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/ScopedPrinter.h" // Project includes -#include "Utility/StringExtractorGDBRemote.h" -#include "Utility/UriParser.h" #include "ProcessGDBRemote.h" #include "ProcessGDBRemoteLog.h" +#include "Utility/StringExtractorGDBRemote.h" +#include "Utility/UriParser.h" using namespace lldb; using namespace lldb_private; @@ -60,2934 +60,3110 @@ using namespace llvm; // GDBRemote Errors //---------------------------------------------------------------------- -namespace -{ - enum GDBRemoteServerError - { - // Set to the first unused error number in literal form below - eErrorFirst = 29, - eErrorNoProcess = eErrorFirst, - eErrorResume, - eErrorExitStatus - }; +namespace { +enum GDBRemoteServerError { + // Set to the first unused error number in literal form below + eErrorFirst = 29, + eErrorNoProcess = eErrorFirst, + eErrorResume, + eErrorExitStatus +}; } //---------------------------------------------------------------------- // GDBRemoteCommunicationServerLLGS constructor //---------------------------------------------------------------------- -GDBRemoteCommunicationServerLLGS::GDBRemoteCommunicationServerLLGS(MainLoop &mainloop) - : GDBRemoteCommunicationServerCommon("gdb-remote.server", "gdb-remote.server.rx_packet"), - m_mainloop(mainloop), - m_current_tid(LLDB_INVALID_THREAD_ID), - m_continue_tid(LLDB_INVALID_THREAD_ID), - m_debugged_process_mutex(), - m_debugged_process_sp(), - m_stdio_communication("process.stdio"), +GDBRemoteCommunicationServerLLGS::GDBRemoteCommunicationServerLLGS( + MainLoop &mainloop) + : GDBRemoteCommunicationServerCommon("gdb-remote.server", + "gdb-remote.server.rx_packet"), + m_mainloop(mainloop), m_current_tid(LLDB_INVALID_THREAD_ID), + m_continue_tid(LLDB_INVALID_THREAD_ID), m_debugged_process_mutex(), + m_debugged_process_sp(), m_stdio_communication("process.stdio"), m_inferior_prev_state(StateType::eStateInvalid), - m_active_auxv_buffer_sp(), - m_saved_registers_mutex(), - m_saved_registers_map(), - m_next_saved_registers_id(1), - m_handshake_completed(false) -{ - RegisterPacketHandlers(); -} - -void -GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() -{ - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_C, - &GDBRemoteCommunicationServerLLGS::Handle_C); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_c, - &GDBRemoteCommunicationServerLLGS::Handle_c); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_D, - &GDBRemoteCommunicationServerLLGS::Handle_D); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_H, - &GDBRemoteCommunicationServerLLGS::Handle_H); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_I, - &GDBRemoteCommunicationServerLLGS::Handle_I); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_interrupt, - &GDBRemoteCommunicationServerLLGS::Handle_interrupt); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_m, - &GDBRemoteCommunicationServerLLGS::Handle_memory_read); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_M, - &GDBRemoteCommunicationServerLLGS::Handle_M); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_p, - &GDBRemoteCommunicationServerLLGS::Handle_p); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_P, - &GDBRemoteCommunicationServerLLGS::Handle_P); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qC, - &GDBRemoteCommunicationServerLLGS::Handle_qC); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qfThreadInfo, - &GDBRemoteCommunicationServerLLGS::Handle_qfThreadInfo); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qFileLoadAddress, - &GDBRemoteCommunicationServerLLGS::Handle_qFileLoadAddress); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir, - &GDBRemoteCommunicationServerLLGS::Handle_qGetWorkingDir); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qMemoryRegionInfo, - &GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qMemoryRegionInfoSupported, - &GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfoSupported); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qProcessInfo, - &GDBRemoteCommunicationServerLLGS::Handle_qProcessInfo); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qRegisterInfo, - &GDBRemoteCommunicationServerLLGS::Handle_qRegisterInfo); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QRestoreRegisterState, - &GDBRemoteCommunicationServerLLGS::Handle_QRestoreRegisterState); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSaveRegisterState, - &GDBRemoteCommunicationServerLLGS::Handle_QSaveRegisterState); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetDisableASLR, - &GDBRemoteCommunicationServerLLGS::Handle_QSetDisableASLR); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir, - &GDBRemoteCommunicationServerLLGS::Handle_QSetWorkingDir); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qsThreadInfo, - &GDBRemoteCommunicationServerLLGS::Handle_qsThreadInfo); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qThreadStopInfo, - &GDBRemoteCommunicationServerLLGS::Handle_qThreadStopInfo); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_jThreadsInfo, - &GDBRemoteCommunicationServerLLGS::Handle_jThreadsInfo); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qWatchpointSupportInfo, - &GDBRemoteCommunicationServerLLGS::Handle_qWatchpointSupportInfo); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qXfer_auxv_read, - &GDBRemoteCommunicationServerLLGS::Handle_qXfer_auxv_read); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_s, - &GDBRemoteCommunicationServerLLGS::Handle_s); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_stop_reason, - &GDBRemoteCommunicationServerLLGS::Handle_stop_reason); // ? - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vAttach, - &GDBRemoteCommunicationServerLLGS::Handle_vAttach); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vCont, - &GDBRemoteCommunicationServerLLGS::Handle_vCont); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vCont_actions, - &GDBRemoteCommunicationServerLLGS::Handle_vCont_actions); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_x, - &GDBRemoteCommunicationServerLLGS::Handle_memory_read); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_Z, - &GDBRemoteCommunicationServerLLGS::Handle_Z); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_z, - &GDBRemoteCommunicationServerLLGS::Handle_z); - - RegisterPacketHandler(StringExtractorGDBRemote::eServerPacketType_k, - [this](StringExtractorGDBRemote packet, - Error &error, - bool &interrupt, - bool &quit) - { - quit = true; - return this->Handle_k (packet); - }); -} - -Error -GDBRemoteCommunicationServerLLGS::SetLaunchArguments (const char *const args[], int argc) -{ - if ((argc < 1) || !args || !args[0] || !args[0][0]) - return Error ("%s: no process command line specified to launch", __FUNCTION__); - - m_process_launch_info.SetArguments (const_cast<const char**> (args), true); - return Error (); -} - -Error -GDBRemoteCommunicationServerLLGS::SetLaunchFlags (unsigned int launch_flags) -{ - m_process_launch_info.GetFlags ().Set (launch_flags); - return Error (); -} - -Error -GDBRemoteCommunicationServerLLGS::LaunchProcess () -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - - if (!m_process_launch_info.GetArguments ().GetArgumentCount ()) - return Error ("%s: no process command line specified to launch", __FUNCTION__); - - Error error; - { - std::lock_guard<std::recursive_mutex> guard(m_debugged_process_mutex); - assert (!m_debugged_process_sp && "lldb-gdbserver creating debugged process but one already exists"); - error = NativeProcessProtocol::Launch( - m_process_launch_info, - *this, - m_mainloop, - m_debugged_process_sp); - } - - if (!error.Success ()) - { - fprintf (stderr, "%s: failed to launch executable %s", __FUNCTION__, m_process_launch_info.GetArguments ().GetArgumentAtIndex (0)); - return error; - } - - // Handle mirroring of inferior stdout/stderr over the gdb-remote protocol - // as needed. - // llgs local-process debugging may specify PTY paths, which will make these - // file actions non-null - // process launch -i/e/o will also make these file actions non-null - // nullptr means that the traffic is expected to flow over gdb-remote protocol - if ( - m_process_launch_info.GetFileActionForFD(STDIN_FILENO) == nullptr || - m_process_launch_info.GetFileActionForFD(STDOUT_FILENO) == nullptr || - m_process_launch_info.GetFileActionForFD(STDERR_FILENO) == nullptr - ) - { - // nullptr means it's not redirected to file or pty (in case of LLGS local) - // at least one of stdio will be transferred pty<->gdb-remote - // we need to give the pty master handle to this object to read and/or write - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " setting up stdout/stderr redirection via $O gdb-remote commands", __FUNCTION__, m_debugged_process_sp->GetID ()); - - // Setup stdout/stderr mapping from inferior to $O - auto terminal_fd = m_debugged_process_sp->GetTerminalFileDescriptor (); - if (terminal_fd >= 0) - { - if (log) - log->Printf ("ProcessGDBRemoteCommunicationServerLLGS::%s setting inferior STDIO fd to %d", __FUNCTION__, terminal_fd); - error = SetSTDIOFileDescriptor (terminal_fd); - if (error.Fail ()) - return error; - } - else - { - if (log) - log->Printf ("ProcessGDBRemoteCommunicationServerLLGS::%s ignoring inferior STDIO since terminal fd reported as %d", __FUNCTION__, terminal_fd); - } - } - else - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " skipping stdout/stderr redirection via $O: inferior will communicate over client-provided file descriptors", __FUNCTION__, m_debugged_process_sp->GetID ()); - } - - printf ("Launched '%s' as process %" PRIu64 "...\n", m_process_launch_info.GetArguments ().GetArgumentAtIndex (0), m_process_launch_info.GetProcessID ()); - + m_active_auxv_buffer_sp(), m_saved_registers_mutex(), + m_saved_registers_map(), m_next_saved_registers_id(1), + m_handshake_completed(false) { + RegisterPacketHandlers(); +} + +void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() { + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_C, + &GDBRemoteCommunicationServerLLGS::Handle_C); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_c, + &GDBRemoteCommunicationServerLLGS::Handle_c); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_D, + &GDBRemoteCommunicationServerLLGS::Handle_D); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_H, + &GDBRemoteCommunicationServerLLGS::Handle_H); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_I, + &GDBRemoteCommunicationServerLLGS::Handle_I); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_interrupt, + &GDBRemoteCommunicationServerLLGS::Handle_interrupt); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_m, + &GDBRemoteCommunicationServerLLGS::Handle_memory_read); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_M, + &GDBRemoteCommunicationServerLLGS::Handle_M); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_p, + &GDBRemoteCommunicationServerLLGS::Handle_p); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_P, + &GDBRemoteCommunicationServerLLGS::Handle_P); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qC, + &GDBRemoteCommunicationServerLLGS::Handle_qC); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qfThreadInfo, + &GDBRemoteCommunicationServerLLGS::Handle_qfThreadInfo); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qFileLoadAddress, + &GDBRemoteCommunicationServerLLGS::Handle_qFileLoadAddress); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir, + &GDBRemoteCommunicationServerLLGS::Handle_qGetWorkingDir); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qMemoryRegionInfo, + &GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qMemoryRegionInfoSupported, + &GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfoSupported); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qProcessInfo, + &GDBRemoteCommunicationServerLLGS::Handle_qProcessInfo); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qRegisterInfo, + &GDBRemoteCommunicationServerLLGS::Handle_qRegisterInfo); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_QRestoreRegisterState, + &GDBRemoteCommunicationServerLLGS::Handle_QRestoreRegisterState); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_QSaveRegisterState, + &GDBRemoteCommunicationServerLLGS::Handle_QSaveRegisterState); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_QSetDisableASLR, + &GDBRemoteCommunicationServerLLGS::Handle_QSetDisableASLR); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir, + &GDBRemoteCommunicationServerLLGS::Handle_QSetWorkingDir); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qsThreadInfo, + &GDBRemoteCommunicationServerLLGS::Handle_qsThreadInfo); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qThreadStopInfo, + &GDBRemoteCommunicationServerLLGS::Handle_qThreadStopInfo); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_jThreadsInfo, + &GDBRemoteCommunicationServerLLGS::Handle_jThreadsInfo); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qWatchpointSupportInfo, + &GDBRemoteCommunicationServerLLGS::Handle_qWatchpointSupportInfo); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qXfer_auxv_read, + &GDBRemoteCommunicationServerLLGS::Handle_qXfer_auxv_read); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_s, + &GDBRemoteCommunicationServerLLGS::Handle_s); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_stop_reason, + &GDBRemoteCommunicationServerLLGS::Handle_stop_reason); // ? + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_vAttach, + &GDBRemoteCommunicationServerLLGS::Handle_vAttach); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_vCont, + &GDBRemoteCommunicationServerLLGS::Handle_vCont); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_vCont_actions, + &GDBRemoteCommunicationServerLLGS::Handle_vCont_actions); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_x, + &GDBRemoteCommunicationServerLLGS::Handle_memory_read); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_Z, + &GDBRemoteCommunicationServerLLGS::Handle_Z); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_z, + &GDBRemoteCommunicationServerLLGS::Handle_z); + + RegisterPacketHandler(StringExtractorGDBRemote::eServerPacketType_k, + [this](StringExtractorGDBRemote packet, Error &error, + bool &interrupt, bool &quit) { + quit = true; + return this->Handle_k(packet); + }); +} + +Error GDBRemoteCommunicationServerLLGS::SetLaunchArguments( + const char *const args[], int argc) { + if ((argc < 1) || !args || !args[0] || !args[0][0]) + return Error("%s: no process command line specified to launch", + __FUNCTION__); + + m_process_launch_info.SetArguments(const_cast<const char **>(args), true); + return Error(); +} + +Error GDBRemoteCommunicationServerLLGS::SetLaunchFlags( + unsigned int launch_flags) { + m_process_launch_info.GetFlags().Set(launch_flags); + return Error(); +} + +Error GDBRemoteCommunicationServerLLGS::LaunchProcess() { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + if (!m_process_launch_info.GetArguments().GetArgumentCount()) + return Error("%s: no process command line specified to launch", + __FUNCTION__); + + const bool should_forward_stdio = + m_process_launch_info.GetFileActionForFD(STDIN_FILENO) == nullptr || + m_process_launch_info.GetFileActionForFD(STDOUT_FILENO) == nullptr || + m_process_launch_info.GetFileActionForFD(STDERR_FILENO) == nullptr; + m_process_launch_info.SetLaunchInSeparateProcessGroup(true); + m_process_launch_info.GetFlags().Set(eLaunchFlagDebug); + + const bool default_to_use_pty = true; + m_process_launch_info.FinalizeFileActions(nullptr, default_to_use_pty); + + Error error; + { + std::lock_guard<std::recursive_mutex> guard(m_debugged_process_mutex); + assert(!m_debugged_process_sp && "lldb-server creating debugged " + "process but one already exists"); + error = NativeProcessProtocol::Launch(m_process_launch_info, *this, + m_mainloop, m_debugged_process_sp); + } + + if (!error.Success()) { + fprintf(stderr, "%s: failed to launch executable %s", __FUNCTION__, + m_process_launch_info.GetArguments().GetArgumentAtIndex(0)); return error; -} - -Error -GDBRemoteCommunicationServerLLGS::AttachToProcess (lldb::pid_t pid) -{ - Error error; - - Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS)); + } + + // Handle mirroring of inferior stdout/stderr over the gdb-remote protocol + // as needed. + // llgs local-process debugging may specify PTY paths, which will make these + // file actions non-null + // process launch -i/e/o will also make these file actions non-null + // nullptr means that the traffic is expected to flow over gdb-remote protocol + if (should_forward_stdio) { + // nullptr means it's not redirected to file or pty (in case of LLGS local) + // at least one of stdio will be transferred pty<->gdb-remote + // we need to give the pty master handle to this object to read and/or write if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64, __FUNCTION__, pid); - - // Before we try to attach, make sure we aren't already monitoring something else. - if (m_debugged_process_sp && m_debugged_process_sp->GetID() != LLDB_INVALID_PROCESS_ID) - return Error("cannot attach to a process %" PRIu64 " when another process with pid %" PRIu64 " is being debugged.", pid, m_debugged_process_sp->GetID()); - - // Try to attach. - error = NativeProcessProtocol::Attach(pid, *this, m_mainloop, m_debugged_process_sp); - if (!error.Success ()) - { - fprintf (stderr, "%s: failed to attach to process %" PRIu64 ": %s", __FUNCTION__, pid, error.AsCString ()); + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 + " setting up stdout/stderr redirection via $O gdb-remote commands", + __FUNCTION__, m_debugged_process_sp->GetID()); + + // Setup stdout/stderr mapping from inferior to $O + auto terminal_fd = m_debugged_process_sp->GetTerminalFileDescriptor(); + if (terminal_fd >= 0) { + if (log) + log->Printf("ProcessGDBRemoteCommunicationServerLLGS::%s setting " + "inferior STDIO fd to %d", + __FUNCTION__, terminal_fd); + error = SetSTDIOFileDescriptor(terminal_fd); + if (error.Fail()) return error; + } else { + if (log) + log->Printf("ProcessGDBRemoteCommunicationServerLLGS::%s ignoring " + "inferior STDIO since terminal fd reported as %d", + __FUNCTION__, terminal_fd); } - - // Setup stdout/stderr mapping from inferior. - auto terminal_fd = m_debugged_process_sp->GetTerminalFileDescriptor (); - if (terminal_fd >= 0) - { - if (log) - log->Printf ("ProcessGDBRemoteCommunicationServerLLGS::%s setting inferior STDIO fd to %d", __FUNCTION__, terminal_fd); - error = SetSTDIOFileDescriptor (terminal_fd); - if (error.Fail ()) - return error; - } - else - { - if (log) - log->Printf ("ProcessGDBRemoteCommunicationServerLLGS::%s ignoring inferior STDIO since terminal fd reported as %d", __FUNCTION__, terminal_fd); - } - - printf ("Attached to process %" PRIu64 "...\n", pid); - + } else { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 + " skipping stdout/stderr redirection via $O: inferior will " + "communicate over client-provided file descriptors", + __FUNCTION__, m_debugged_process_sp->GetID()); + } + + printf("Launched '%s' as process %" PRIu64 "...\n", + m_process_launch_info.GetArguments().GetArgumentAtIndex(0), + m_process_launch_info.GetProcessID()); + + return error; +} + +Error GDBRemoteCommunicationServerLLGS::AttachToProcess(lldb::pid_t pid) { + Error error; + + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64, + __FUNCTION__, pid); + + // Before we try to attach, make sure we aren't already monitoring something + // else. + if (m_debugged_process_sp && + m_debugged_process_sp->GetID() != LLDB_INVALID_PROCESS_ID) + return Error("cannot attach to a process %" PRIu64 + " when another process with pid %" PRIu64 + " is being debugged.", + pid, m_debugged_process_sp->GetID()); + + // Try to attach. + error = NativeProcessProtocol::Attach(pid, *this, m_mainloop, + m_debugged_process_sp); + if (!error.Success()) { + fprintf(stderr, "%s: failed to attach to process %" PRIu64 ": %s", + __FUNCTION__, pid, error.AsCString()); return error; -} + } -void -GDBRemoteCommunicationServerLLGS::InitializeDelegate (NativeProcessProtocol *process) -{ - assert (process && "process cannot be NULL"); - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + // Setup stdout/stderr mapping from inferior. + auto terminal_fd = m_debugged_process_sp->GetTerminalFileDescriptor(); + if (terminal_fd >= 0) { if (log) - { - log->Printf ("GDBRemoteCommunicationServerLLGS::%s called with NativeProcessProtocol pid %" PRIu64 ", current state: %s", - __FUNCTION__, - process->GetID (), - StateAsCString (process->GetState ())); - } -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::SendWResponse (NativeProcessProtocol *process) -{ - assert (process && "process cannot be NULL"); - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - - // send W notification - ExitType exit_type = ExitType::eExitTypeInvalid; - int return_code = 0; - std::string exit_description; - - const bool got_exit_info = process->GetExitStatus (&exit_type, &return_code, exit_description); - if (!got_exit_info) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 ", failed to retrieve process exit status", __FUNCTION__, process->GetID ()); - - StreamGDBRemote response; - response.PutChar ('E'); - response.PutHex8 (GDBRemoteServerError::eErrorExitStatus); - return SendPacketNoLock(response.GetData(), response.GetSize()); - } - else - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 ", returning exit type %d, return code %d [%s]", __FUNCTION__, process->GetID (), exit_type, return_code, exit_description.c_str ()); - - StreamGDBRemote response; - - char return_type_code; - switch (exit_type) - { - case ExitType::eExitTypeExit: - return_type_code = 'W'; - break; - case ExitType::eExitTypeSignal: - return_type_code = 'X'; - break; - case ExitType::eExitTypeStop: - return_type_code = 'S'; - break; - case ExitType::eExitTypeInvalid: - return_type_code = 'E'; - break; - } - response.PutChar (return_type_code); + log->Printf("ProcessGDBRemoteCommunicationServerLLGS::%s setting " + "inferior STDIO fd to %d", + __FUNCTION__, terminal_fd); + error = SetSTDIOFileDescriptor(terminal_fd); + if (error.Fail()) + return error; + } else { + if (log) + log->Printf("ProcessGDBRemoteCommunicationServerLLGS::%s ignoring " + "inferior STDIO since terminal fd reported as %d", + __FUNCTION__, terminal_fd); + } - // POSIX exit status limited to unsigned 8 bits. - response.PutHex8 (return_code); + printf("Attached to process %" PRIu64 "...\n", pid); - return SendPacketNoLock(response.GetData(), response.GetSize()); - } + return error; } -static void -AppendHexValue (StreamString &response, const uint8_t* buf, uint32_t buf_size, bool swap) -{ - int64_t i; - if (swap) - { - for (i = buf_size-1; i >= 0; i--) - response.PutHex8 (buf[i]); - } - else - { - for (i = 0; i < buf_size; i++) - response.PutHex8 (buf[i]); - } +void GDBRemoteCommunicationServerLLGS::InitializeDelegate( + NativeProcessProtocol *process) { + assert(process && "process cannot be NULL"); + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) { + log->Printf("GDBRemoteCommunicationServerLLGS::%s called with " + "NativeProcessProtocol pid %" PRIu64 ", current state: %s", + __FUNCTION__, process->GetID(), + StateAsCString(process->GetState())); + } } -static void -WriteRegisterValueInHexFixedWidth (StreamString &response, - NativeRegisterContextSP ®_ctx_sp, - const RegisterInfo ®_info, - const RegisterValue *reg_value_p) -{ - RegisterValue reg_value; - if (!reg_value_p) - { - Error error = reg_ctx_sp->ReadRegister (®_info, reg_value); - if (error.Success ()) - reg_value_p = ®_value; - // else log. - } +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::SendWResponse( + NativeProcessProtocol *process) { + assert(process && "process cannot be NULL"); + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + // send W notification + ExitType exit_type = ExitType::eExitTypeInvalid; + int return_code = 0; + std::string exit_description; + + const bool got_exit_info = + process->GetExitStatus(&exit_type, &return_code, exit_description); + if (!got_exit_info) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 + ", failed to retrieve process exit status", + __FUNCTION__, process->GetID()); - if (reg_value_p) - { - AppendHexValue (response, (const uint8_t*) reg_value_p->GetBytes (), reg_value_p->GetByteSize (), false); - } - else - { - // Zero-out any unreadable values. - if (reg_info.byte_size > 0) - { - std::basic_string<uint8_t> zeros(reg_info.byte_size, '\0'); - AppendHexValue (response, zeros.data(), zeros.size(), false); - } - } -} + StreamGDBRemote response; + response.PutChar('E'); + response.PutHex8(GDBRemoteServerError::eErrorExitStatus); + return SendPacketNoLock(response.GetString()); + } else { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 + ", returning exit type %d, return code %d [%s]", + __FUNCTION__, process->GetID(), exit_type, return_code, + exit_description.c_str()); -static JSONObject::SP -GetRegistersAsJSON(NativeThreadProtocol &thread, bool abridged) -{ - Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_THREAD)); + StreamGDBRemote response; - NativeRegisterContextSP reg_ctx_sp = thread.GetRegisterContext (); - if (! reg_ctx_sp) - return nullptr; + char return_type_code; + switch (exit_type) { + case ExitType::eExitTypeExit: + return_type_code = 'W'; + break; + case ExitType::eExitTypeSignal: + return_type_code = 'X'; + break; + case ExitType::eExitTypeStop: + return_type_code = 'S'; + break; + case ExitType::eExitTypeInvalid: + return_type_code = 'E'; + break; + } + response.PutChar(return_type_code); + + // POSIX exit status limited to unsigned 8 bits. + response.PutHex8(return_code); + + return SendPacketNoLock(response.GetString()); + } +} + +static void AppendHexValue(StreamString &response, const uint8_t *buf, + uint32_t buf_size, bool swap) { + int64_t i; + if (swap) { + for (i = buf_size - 1; i >= 0; i--) + response.PutHex8(buf[i]); + } else { + for (i = 0; i < buf_size; i++) + response.PutHex8(buf[i]); + } +} + +static void WriteRegisterValueInHexFixedWidth( + StreamString &response, NativeRegisterContextSP ®_ctx_sp, + const RegisterInfo ®_info, const RegisterValue *reg_value_p) { + RegisterValue reg_value; + if (!reg_value_p) { + Error error = reg_ctx_sp->ReadRegister(®_info, reg_value); + if (error.Success()) + reg_value_p = ®_value; + // else log. + } + + if (reg_value_p) { + AppendHexValue(response, (const uint8_t *)reg_value_p->GetBytes(), + reg_value_p->GetByteSize(), false); + } else { + // Zero-out any unreadable values. + if (reg_info.byte_size > 0) { + std::basic_string<uint8_t> zeros(reg_info.byte_size, '\0'); + AppendHexValue(response, zeros.data(), zeros.size(), false); + } + } +} + +static JSONObject::SP GetRegistersAsJSON(NativeThreadProtocol &thread, + bool abridged) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + + NativeRegisterContextSP reg_ctx_sp = thread.GetRegisterContext(); + if (!reg_ctx_sp) + return nullptr; - JSONObject::SP register_object_sp = std::make_shared<JSONObject>(); + JSONObject::SP register_object_sp = std::make_shared<JSONObject>(); #ifdef LLDB_JTHREADSINFO_FULL_REGISTER_SET - // Expedite all registers in the first register set (i.e. should be GPRs) that are not contained in other registers. - const RegisterSet *reg_set_p = reg_ctx_sp->GetRegisterSet(0); - if (! reg_set_p) - return nullptr; - for (const uint32_t *reg_num_p = reg_set_p->registers; *reg_num_p != LLDB_INVALID_REGNUM; ++reg_num_p) - { - uint32_t reg_num = *reg_num_p; + // Expedite all registers in the first register set (i.e. should be GPRs) that + // are not contained in other registers. + const RegisterSet *reg_set_p = reg_ctx_sp->GetRegisterSet(0); + if (!reg_set_p) + return nullptr; + for (const uint32_t *reg_num_p = reg_set_p->registers; + *reg_num_p != LLDB_INVALID_REGNUM; ++reg_num_p) { + uint32_t reg_num = *reg_num_p; #else - // Expedite only a couple of registers until we figure out why sending registers is - // expensive. - static const uint32_t k_expedited_registers[] = { - LLDB_REGNUM_GENERIC_PC, LLDB_REGNUM_GENERIC_SP, LLDB_REGNUM_GENERIC_FP, LLDB_REGNUM_GENERIC_RA, LLDB_INVALID_REGNUM - }; - static const uint32_t k_abridged_expedited_registers[] = { - LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM - }; - - for (const uint32_t *generic_reg_p = abridged ? k_abridged_expedited_registers : k_expedited_registers; - *generic_reg_p != LLDB_INVALID_REGNUM; - ++generic_reg_p) - { - uint32_t reg_num = reg_ctx_sp->ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, *generic_reg_p); - if (reg_num == LLDB_INVALID_REGNUM) - continue; // Target does not support the given register. + // Expedite only a couple of registers until we figure out why sending + // registers is + // expensive. + static const uint32_t k_expedited_registers[] = { + LLDB_REGNUM_GENERIC_PC, LLDB_REGNUM_GENERIC_SP, LLDB_REGNUM_GENERIC_FP, + LLDB_REGNUM_GENERIC_RA, LLDB_INVALID_REGNUM}; + static const uint32_t k_abridged_expedited_registers[] = { + LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM}; + + for (const uint32_t *generic_reg_p = abridged ? k_abridged_expedited_registers + : k_expedited_registers; + *generic_reg_p != LLDB_INVALID_REGNUM; ++generic_reg_p) { + uint32_t reg_num = reg_ctx_sp->ConvertRegisterKindToRegisterNumber( + eRegisterKindGeneric, *generic_reg_p); + if (reg_num == LLDB_INVALID_REGNUM) + continue; // Target does not support the given register. #endif - const RegisterInfo *const reg_info_p = reg_ctx_sp->GetRegisterInfoAtIndex(reg_num); - if (reg_info_p == nullptr) - { - if (log) - log->Printf("%s failed to get register info for register index %" PRIu32, - __FUNCTION__, reg_num); - continue; - } - - if (reg_info_p->value_regs != nullptr) - continue; // Only expedite registers that are not contained in other registers. - - RegisterValue reg_value; - Error error = reg_ctx_sp->ReadRegister(reg_info_p, reg_value); - if (error.Fail()) - { - if (log) - log->Printf("%s failed to read register '%s' index %" PRIu32 ": %s", __FUNCTION__, - reg_info_p->name ? reg_info_p->name : "<unnamed-register>", reg_num, - error.AsCString ()); - continue; - } - - StreamString stream; - WriteRegisterValueInHexFixedWidth(stream, reg_ctx_sp, *reg_info_p, ®_value); - - register_object_sp->SetObject(std::to_string(reg_num), - std::make_shared<JSONString>(stream.GetString())); - } - - return register_object_sp; -} - -static const char * -GetStopReasonString(StopReason stop_reason) -{ - switch (stop_reason) - { - case eStopReasonTrace: - return "trace"; - case eStopReasonBreakpoint: - return "breakpoint"; - case eStopReasonWatchpoint: - return "watchpoint"; - case eStopReasonSignal: - return "signal"; - case eStopReasonException: - return "exception"; - case eStopReasonExec: - return "exec"; - case eStopReasonInstrumentation: - case eStopReasonInvalid: - case eStopReasonPlanComplete: - case eStopReasonThreadExiting: - case eStopReasonNone: - break; // ignored + const RegisterInfo *const reg_info_p = + reg_ctx_sp->GetRegisterInfoAtIndex(reg_num); + if (reg_info_p == nullptr) { + if (log) + log->Printf( + "%s failed to get register info for register index %" PRIu32, + __FUNCTION__, reg_num); + continue; } - return nullptr; -} -static JSONArray::SP -GetJSONThreadsInfo(NativeProcessProtocol &process, bool abridged) -{ - Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); + if (reg_info_p->value_regs != nullptr) + continue; // Only expedite registers that are not contained in other + // registers. - JSONArray::SP threads_array_sp = std::make_shared<JSONArray>(); - - // Ensure we can get info on the given thread. - uint32_t thread_idx = 0; - for ( NativeThreadProtocolSP thread_sp; - (thread_sp = process.GetThreadAtIndex(thread_idx)) != nullptr; - ++thread_idx) - { - - lldb::tid_t tid = thread_sp->GetID(); - - // Grab the reason this thread stopped. - struct ThreadStopInfo tid_stop_info; - std::string description; - if (!thread_sp->GetStopReason (tid_stop_info, description)) - return nullptr; - - const int signum = tid_stop_info.details.signal.signo; - if (log) - { - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 " got signal signo = %d, reason = %d, exc_type = %" PRIu64, + RegisterValue reg_value; + Error error = reg_ctx_sp->ReadRegister(reg_info_p, reg_value); + if (error.Fail()) { + if (log) + log->Printf("%s failed to read register '%s' index %" PRIu32 ": %s", __FUNCTION__, - process.GetID (), - tid, - signum, - tid_stop_info.reason, - tid_stop_info.details.exception.type); - } - - JSONObject::SP thread_obj_sp = std::make_shared<JSONObject>(); - threads_array_sp->AppendObject(thread_obj_sp); - - if (JSONObject::SP registers_sp = GetRegistersAsJSON(*thread_sp, abridged)) - thread_obj_sp->SetObject("registers", registers_sp); - - thread_obj_sp->SetObject("tid", std::make_shared<JSONNumber>(tid)); - if (signum != 0) - thread_obj_sp->SetObject("signal", std::make_shared<JSONNumber>(signum)); + reg_info_p->name ? reg_info_p->name : "<unnamed-register>", + reg_num, error.AsCString()); + continue; + } + + StreamString stream; + WriteRegisterValueInHexFixedWidth(stream, reg_ctx_sp, *reg_info_p, + ®_value); + + register_object_sp->SetObject( + llvm::to_string(reg_num), + std::make_shared<JSONString>(stream.GetString())); + } + + return register_object_sp; +} + +static const char *GetStopReasonString(StopReason stop_reason) { + switch (stop_reason) { + case eStopReasonTrace: + return "trace"; + case eStopReasonBreakpoint: + return "breakpoint"; + case eStopReasonWatchpoint: + return "watchpoint"; + case eStopReasonSignal: + return "signal"; + case eStopReasonException: + return "exception"; + case eStopReasonExec: + return "exec"; + case eStopReasonInstrumentation: + case eStopReasonInvalid: + case eStopReasonPlanComplete: + case eStopReasonThreadExiting: + case eStopReasonNone: + break; // ignored + } + return nullptr; +} + +static JSONArray::SP GetJSONThreadsInfo(NativeProcessProtocol &process, + bool abridged) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); + + JSONArray::SP threads_array_sp = std::make_shared<JSONArray>(); + + // Ensure we can get info on the given thread. + uint32_t thread_idx = 0; + for (NativeThreadProtocolSP thread_sp; + (thread_sp = process.GetThreadAtIndex(thread_idx)) != nullptr; + ++thread_idx) { + + lldb::tid_t tid = thread_sp->GetID(); - const std::string thread_name = thread_sp->GetName (); - if (! thread_name.empty()) - thread_obj_sp->SetObject("name", std::make_shared<JSONString>(thread_name)); - - if (const char *stop_reason_str = GetStopReasonString(tid_stop_info.reason)) - thread_obj_sp->SetObject("reason", std::make_shared<JSONString>(stop_reason_str)); - - if (! description.empty()) - thread_obj_sp->SetObject("description", std::make_shared<JSONString>(description)); - - if ((tid_stop_info.reason == eStopReasonException) && tid_stop_info.details.exception.type) - { - thread_obj_sp->SetObject("metype", - std::make_shared<JSONNumber>(tid_stop_info.details.exception.type)); - - JSONArray::SP medata_array_sp = std::make_shared<JSONArray>(); - for (uint32_t i = 0; i < tid_stop_info.details.exception.data_count; ++i) - { - medata_array_sp->AppendObject(std::make_shared<JSONNumber>( - tid_stop_info.details.exception.data[i])); - } - thread_obj_sp->SetObject("medata", medata_array_sp); - } + // Grab the reason this thread stopped. + struct ThreadStopInfo tid_stop_info; + std::string description; + if (!thread_sp->GetStopReason(tid_stop_info, description)) + return nullptr; - // TODO: Expedite interesting regions of inferior memory + const int signum = tid_stop_info.details.signal.signo; + if (log) { + log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 + " tid %" PRIu64 + " got signal signo = %d, reason = %d, exc_type = %" PRIu64, + __FUNCTION__, process.GetID(), tid, signum, + tid_stop_info.reason, tid_stop_info.details.exception.type); } - return threads_array_sp; -} + JSONObject::SP thread_obj_sp = std::make_shared<JSONObject>(); + threads_array_sp->AppendObject(thread_obj_sp); -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread (lldb::tid_t tid) -{ - Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); + if (JSONObject::SP registers_sp = GetRegistersAsJSON(*thread_sp, abridged)) + thread_obj_sp->SetObject("registers", registers_sp); - // Ensure we have a debugged process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - return SendErrorResponse (50); + thread_obj_sp->SetObject("tid", std::make_shared<JSONNumber>(tid)); + if (signum != 0) + thread_obj_sp->SetObject("signal", std::make_shared<JSONNumber>(signum)); - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s preparing packet for pid %" PRIu64 " tid %" PRIu64, - __FUNCTION__, m_debugged_process_sp->GetID (), tid); + const std::string thread_name = thread_sp->GetName(); + if (!thread_name.empty()) + thread_obj_sp->SetObject("name", + std::make_shared<JSONString>(thread_name)); - // Ensure we can get info on the given thread. - NativeThreadProtocolSP thread_sp (m_debugged_process_sp->GetThreadByID (tid)); - if (!thread_sp) - return SendErrorResponse (51); + if (const char *stop_reason_str = GetStopReasonString(tid_stop_info.reason)) + thread_obj_sp->SetObject("reason", + std::make_shared<JSONString>(stop_reason_str)); - // Grab the reason this thread stopped. - struct ThreadStopInfo tid_stop_info; - std::string description; - if (!thread_sp->GetStopReason (tid_stop_info, description)) - return SendErrorResponse (52); + if (!description.empty()) + thread_obj_sp->SetObject("description", + std::make_shared<JSONString>(description)); - // FIXME implement register handling for exec'd inferiors. - // if (tid_stop_info.reason == eStopReasonExec) - // { - // const bool force = true; - // InitializeRegisters(force); - // } + if ((tid_stop_info.reason == eStopReasonException) && + tid_stop_info.details.exception.type) { + thread_obj_sp->SetObject( + "metype", + std::make_shared<JSONNumber>(tid_stop_info.details.exception.type)); - StreamString response; - // Output the T packet with the thread - response.PutChar ('T'); - int signum = tid_stop_info.details.signal.signo; - if (log) - { - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 " got signal signo = %d, reason = %d, exc_type = %" PRIu64, - __FUNCTION__, - m_debugged_process_sp->GetID (), - tid, - signum, - tid_stop_info.reason, - tid_stop_info.details.exception.type); + JSONArray::SP medata_array_sp = std::make_shared<JSONArray>(); + for (uint32_t i = 0; i < tid_stop_info.details.exception.data_count; + ++i) { + medata_array_sp->AppendObject(std::make_shared<JSONNumber>( + tid_stop_info.details.exception.data[i])); + } + thread_obj_sp->SetObject("medata", medata_array_sp); } - // Print the signal number. - response.PutHex8 (signum & 0xff); - - // Include the tid. - response.Printf ("thread:%" PRIx64 ";", tid); - - // Include the thread name if there is one. - const std::string thread_name = thread_sp->GetName (); - if (!thread_name.empty ()) - { - size_t thread_name_len = thread_name.length (); + // TODO: Expedite interesting regions of inferior memory + } - if (::strcspn (thread_name.c_str (), "$#+-;:") == thread_name_len) - { - response.PutCString ("name:"); - response.PutCString (thread_name.c_str ()); - } - else - { - // The thread name contains special chars, send as hex bytes. - response.PutCString ("hexname:"); - response.PutCStringAsRawHex8 (thread_name.c_str ()); - } - response.PutChar (';'); - } - - // If a 'QListThreadsInStopReply' was sent to enable this feature, we - // will send all thread IDs back in the "threads" key whose value is - // a list of hex thread IDs separated by commas: - // "threads:10a,10b,10c;" - // This will save the debugger from having to send a pair of qfThreadInfo - // and qsThreadInfo packets, but it also might take a lot of room in the - // stop reply packet, so it must be enabled only on systems where there - // are no limits on packet lengths. - if (m_list_threads_in_stop_reply) - { - response.PutCString ("threads:"); - - uint32_t thread_index = 0; - NativeThreadProtocolSP listed_thread_sp; - for (listed_thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index); listed_thread_sp; ++thread_index, listed_thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index)) - { - if (thread_index > 0) - response.PutChar (','); - response.Printf ("%" PRIx64, listed_thread_sp->GetID ()); - } - response.PutChar (';'); - - // Include JSON info that describes the stop reason for any threads - // that actually have stop reasons. We use the new "jstopinfo" key - // whose values is hex ascii JSON that contains the thread IDs - // thread stop info only for threads that have stop reasons. Only send - // this if we have more than one thread otherwise this packet has all - // the info it needs. - if (thread_index > 0) - { - const bool threads_with_valid_stop_info_only = true; - JSONArray::SP threads_info_sp = GetJSONThreadsInfo(*m_debugged_process_sp, - threads_with_valid_stop_info_only); - if (threads_info_sp) - { - response.PutCString("jstopinfo:"); - StreamString unescaped_response; - threads_info_sp->Write(unescaped_response); - response.PutCStringAsRawHex8(unescaped_response.GetData()); - response.PutChar(';'); - } - else if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to prepare a jstopinfo field for pid %" PRIu64, - __FUNCTION__, m_debugged_process_sp->GetID()); + return threads_array_sp; +} - } +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread( + lldb::tid_t tid) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); + + // Ensure we have a debugged process. + if (!m_debugged_process_sp || + (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) + return SendErrorResponse(50); + + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s preparing packet for pid %" PRIu64 + " tid %" PRIu64, + __FUNCTION__, m_debugged_process_sp->GetID(), tid); + + // Ensure we can get info on the given thread. + NativeThreadProtocolSP thread_sp(m_debugged_process_sp->GetThreadByID(tid)); + if (!thread_sp) + return SendErrorResponse(51); + + // Grab the reason this thread stopped. + struct ThreadStopInfo tid_stop_info; + std::string description; + if (!thread_sp->GetStopReason(tid_stop_info, description)) + return SendErrorResponse(52); + + // FIXME implement register handling for exec'd inferiors. + // if (tid_stop_info.reason == eStopReasonExec) + // { + // const bool force = true; + // InitializeRegisters(force); + // } + + StreamString response; + // Output the T packet with the thread + response.PutChar('T'); + int signum = tid_stop_info.details.signal.signo; + if (log) { + log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 + " tid %" PRIu64 + " got signal signo = %d, reason = %d, exc_type = %" PRIu64, + __FUNCTION__, m_debugged_process_sp->GetID(), tid, signum, + tid_stop_info.reason, tid_stop_info.details.exception.type); + } + + // Print the signal number. + response.PutHex8(signum & 0xff); + + // Include the tid. + response.Printf("thread:%" PRIx64 ";", tid); + + // Include the thread name if there is one. + const std::string thread_name = thread_sp->GetName(); + if (!thread_name.empty()) { + size_t thread_name_len = thread_name.length(); + + if (::strcspn(thread_name.c_str(), "$#+-;:") == thread_name_len) { + response.PutCString("name:"); + response.PutCString(thread_name); + } else { + // The thread name contains special chars, send as hex bytes. + response.PutCString("hexname:"); + response.PutCStringAsRawHex8(thread_name.c_str()); + } + response.PutChar(';'); + } + + // If a 'QListThreadsInStopReply' was sent to enable this feature, we + // will send all thread IDs back in the "threads" key whose value is + // a list of hex thread IDs separated by commas: + // "threads:10a,10b,10c;" + // This will save the debugger from having to send a pair of qfThreadInfo + // and qsThreadInfo packets, but it also might take a lot of room in the + // stop reply packet, so it must be enabled only on systems where there + // are no limits on packet lengths. + if (m_list_threads_in_stop_reply) { + response.PutCString("threads:"); + + uint32_t thread_index = 0; + NativeThreadProtocolSP listed_thread_sp; + for (listed_thread_sp = + m_debugged_process_sp->GetThreadAtIndex(thread_index); + listed_thread_sp; ++thread_index, + listed_thread_sp = m_debugged_process_sp->GetThreadAtIndex( + thread_index)) { + if (thread_index > 0) + response.PutChar(','); + response.Printf("%" PRIx64, listed_thread_sp->GetID()); + } + response.PutChar(';'); + + // Include JSON info that describes the stop reason for any threads + // that actually have stop reasons. We use the new "jstopinfo" key + // whose values is hex ascii JSON that contains the thread IDs + // thread stop info only for threads that have stop reasons. Only send + // this if we have more than one thread otherwise this packet has all + // the info it needs. + if (thread_index > 0) { + const bool threads_with_valid_stop_info_only = true; + JSONArray::SP threads_info_sp = GetJSONThreadsInfo( + *m_debugged_process_sp, threads_with_valid_stop_info_only); + if (threads_info_sp) { + response.PutCString("jstopinfo:"); + StreamString unescaped_response; + threads_info_sp->Write(unescaped_response); + response.PutCStringAsRawHex8(unescaped_response.GetData()); + response.PutChar(';'); + } else if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed to prepare a " + "jstopinfo field for pid %" PRIu64, + __FUNCTION__, m_debugged_process_sp->GetID()); } - - // - // Expedite registers. - // - - // Grab the register context. - NativeRegisterContextSP reg_ctx_sp = thread_sp->GetRegisterContext (); - if (reg_ctx_sp) - { - // Expedite all registers in the first register set (i.e. should be GPRs) that are not contained in other registers. - const RegisterSet *reg_set_p; - if (reg_ctx_sp->GetRegisterSetCount () > 0 && ((reg_set_p = reg_ctx_sp->GetRegisterSet (0)) != nullptr)) - { + } + + // + // Expedite registers. + // + + // Grab the register context. + NativeRegisterContextSP reg_ctx_sp = thread_sp->GetRegisterContext(); + if (reg_ctx_sp) { + // Expedite all registers in the first register set (i.e. should be GPRs) + // that are not contained in other registers. + const RegisterSet *reg_set_p; + if (reg_ctx_sp->GetRegisterSetCount() > 0 && + ((reg_set_p = reg_ctx_sp->GetRegisterSet(0)) != nullptr)) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s expediting registers " + "from set '%s' (registers set count: %zu)", + __FUNCTION__, + reg_set_p->name ? reg_set_p->name : "<unnamed-set>", + reg_set_p->num_registers); + + for (const uint32_t *reg_num_p = reg_set_p->registers; + *reg_num_p != LLDB_INVALID_REGNUM; ++reg_num_p) { + const RegisterInfo *const reg_info_p = + reg_ctx_sp->GetRegisterInfoAtIndex(*reg_num_p); + if (reg_info_p == nullptr) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed to get " + "register info for register set '%s', register index " + "%" PRIu32, + __FUNCTION__, + reg_set_p->name ? reg_set_p->name : "<unnamed-set>", + *reg_num_p); + } else if (reg_info_p->value_regs == nullptr) { + // Only expediate registers that are not contained in other registers. + RegisterValue reg_value; + Error error = reg_ctx_sp->ReadRegister(reg_info_p, reg_value); + if (error.Success()) { + response.Printf("%.02x:", *reg_num_p); + WriteRegisterValueInHexFixedWidth(response, reg_ctx_sp, *reg_info_p, + ®_value); + response.PutChar(';'); + } else { if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s expediting registers from set '%s' (registers set count: %zu)", __FUNCTION__, reg_set_p->name ? reg_set_p->name : "<unnamed-set>", reg_set_p->num_registers); - - for (const uint32_t *reg_num_p = reg_set_p->registers; *reg_num_p != LLDB_INVALID_REGNUM; ++reg_num_p) - { - const RegisterInfo *const reg_info_p = reg_ctx_sp->GetRegisterInfoAtIndex (*reg_num_p); - if (reg_info_p == nullptr) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to get register info for register set '%s', register index %" PRIu32, __FUNCTION__, reg_set_p->name ? reg_set_p->name : "<unnamed-set>", *reg_num_p); - } - else if (reg_info_p->value_regs == nullptr) - { - // Only expediate registers that are not contained in other registers. - RegisterValue reg_value; - Error error = reg_ctx_sp->ReadRegister (reg_info_p, reg_value); - if (error.Success ()) - { - response.Printf ("%.02x:", *reg_num_p); - WriteRegisterValueInHexFixedWidth(response, reg_ctx_sp, *reg_info_p, ®_value); - response.PutChar (';'); - } - else - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to read register '%s' index %" PRIu32 ": %s", __FUNCTION__, reg_info_p->name ? reg_info_p->name : "<unnamed-register>", *reg_num_p, error.AsCString ()); - - } - } - } + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed to read " + "register '%s' index %" PRIu32 ": %s", + __FUNCTION__, reg_info_p->name ? reg_info_p->name + : "<unnamed-register>", + *reg_num_p, error.AsCString()); + } } + } } + } - const char* reason_str = GetStopReasonString(tid_stop_info.reason); - if (reason_str != nullptr) - { - response.Printf ("reason:%s;", reason_str); - } + const char *reason_str = GetStopReasonString(tid_stop_info.reason); + if (reason_str != nullptr) { + response.Printf("reason:%s;", reason_str); + } - if (!description.empty()) - { - // Description may contains special chars, send as hex bytes. - response.PutCString ("description:"); - response.PutCStringAsRawHex8 (description.c_str ()); - response.PutChar (';'); - } - else if ((tid_stop_info.reason == eStopReasonException) && tid_stop_info.details.exception.type) - { - response.PutCString ("metype:"); - response.PutHex64 (tid_stop_info.details.exception.type); - response.PutCString (";mecount:"); - response.PutHex32 (tid_stop_info.details.exception.data_count); - response.PutChar (';'); - - for (uint32_t i = 0; i < tid_stop_info.details.exception.data_count; ++i) - { - response.PutCString ("medata:"); - response.PutHex64 (tid_stop_info.details.exception.data[i]); - response.PutChar (';'); - } + if (!description.empty()) { + // Description may contains special chars, send as hex bytes. + response.PutCString("description:"); + response.PutCStringAsRawHex8(description.c_str()); + response.PutChar(';'); + } else if ((tid_stop_info.reason == eStopReasonException) && + tid_stop_info.details.exception.type) { + response.PutCString("metype:"); + response.PutHex64(tid_stop_info.details.exception.type); + response.PutCString(";mecount:"); + response.PutHex32(tid_stop_info.details.exception.data_count); + response.PutChar(';'); + + for (uint32_t i = 0; i < tid_stop_info.details.exception.data_count; ++i) { + response.PutCString("medata:"); + response.PutHex64(tid_stop_info.details.exception.data[i]); + response.PutChar(';'); } + } - return SendPacketNoLock (response.GetData(), response.GetSize()); + return SendPacketNoLock(response.GetString()); } -void -GDBRemoteCommunicationServerLLGS::HandleInferiorState_Exited (NativeProcessProtocol *process) -{ - assert (process && "process cannot be NULL"); - - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__); - - PacketResult result = SendStopReasonForState(StateType::eStateExited); - if (result != PacketResult::Success) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to send stop notification for PID %" PRIu64 ", state: eStateExited", __FUNCTION__, process->GetID ()); - } +void GDBRemoteCommunicationServerLLGS::HandleInferiorState_Exited( + NativeProcessProtocol *process) { + assert(process && "process cannot be NULL"); - // Close the pipe to the inferior terminal i/o if we launched it - // and set one up. - MaybeCloseInferiorTerminalConnection (); - - // We are ready to exit the debug monitor. - m_exit_now = true; -} - -void -GDBRemoteCommunicationServerLLGS::HandleInferiorState_Stopped (NativeProcessProtocol *process) -{ - assert (process && "process cannot be NULL"); - - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__); - - // Send the stop reason unless this is the stop after the - // launch or attach. - switch (m_inferior_prev_state) - { - case eStateLaunching: - case eStateAttaching: - // Don't send anything per debugserver behavior. - break; - default: - // In all other cases, send the stop reason. - PacketResult result = SendStopReasonForState(StateType::eStateStopped); - if (result != PacketResult::Success) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to send stop notification for PID %" PRIu64 ", state: eStateExited", __FUNCTION__, process->GetID ()); - } - break; - } -} + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__); -void -GDBRemoteCommunicationServerLLGS::ProcessStateChanged (NativeProcessProtocol *process, lldb::StateType state) -{ - assert (process && "process cannot be NULL"); - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + PacketResult result = SendStopReasonForState(StateType::eStateExited); + if (result != PacketResult::Success) { if (log) - { - log->Printf ("GDBRemoteCommunicationServerLLGS::%s called with NativeProcessProtocol pid %" PRIu64 ", state: %s", - __FUNCTION__, - process->GetID (), - StateAsCString (state)); - } + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed to send stop " + "notification for PID %" PRIu64 ", state: eStateExited", + __FUNCTION__, process->GetID()); + } + + // Close the pipe to the inferior terminal i/o if we launched it + // and set one up. + MaybeCloseInferiorTerminalConnection(); + + // We are ready to exit the debug monitor. + m_exit_now = true; +} + +void GDBRemoteCommunicationServerLLGS::HandleInferiorState_Stopped( + NativeProcessProtocol *process) { + assert(process && "process cannot be NULL"); + + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__); + + // Send the stop reason unless this is the stop after the + // launch or attach. + switch (m_inferior_prev_state) { + case eStateLaunching: + case eStateAttaching: + // Don't send anything per debugserver behavior. + break; + default: + // In all other cases, send the stop reason. + PacketResult result = SendStopReasonForState(StateType::eStateStopped); + if (result != PacketResult::Success) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed to send stop " + "notification for PID %" PRIu64 ", state: eStateExited", + __FUNCTION__, process->GetID()); + } + break; + } +} + +void GDBRemoteCommunicationServerLLGS::ProcessStateChanged( + NativeProcessProtocol *process, lldb::StateType state) { + assert(process && "process cannot be NULL"); + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) { + log->Printf("GDBRemoteCommunicationServerLLGS::%s called with " + "NativeProcessProtocol pid %" PRIu64 ", state: %s", + __FUNCTION__, process->GetID(), StateAsCString(state)); + } + + switch (state) { + case StateType::eStateRunning: + StartSTDIOForwarding(); + break; + + case StateType::eStateStopped: + // Make sure we get all of the pending stdout/stderr from the inferior + // and send it to the lldb host before we send the state change + // notification + SendProcessOutput(); + // Then stop the forwarding, so that any late output (see llvm.org/pr25652) + // does not + // interfere with our protocol. + StopSTDIOForwarding(); + HandleInferiorState_Stopped(process); + break; - switch (state) - { - case StateType::eStateRunning: - StartSTDIOForwarding(); - break; - - case StateType::eStateStopped: - // Make sure we get all of the pending stdout/stderr from the inferior - // and send it to the lldb host before we send the state change - // notification - SendProcessOutput(); - // Then stop the forwarding, so that any late output (see llvm.org/pr25652) does not - // interfere with our protocol. - StopSTDIOForwarding(); - HandleInferiorState_Stopped (process); - break; - - case StateType::eStateExited: - // Same as above - SendProcessOutput(); - StopSTDIOForwarding(); - HandleInferiorState_Exited (process); - break; + case StateType::eStateExited: + // Same as above + SendProcessOutput(); + StopSTDIOForwarding(); + HandleInferiorState_Exited(process); + break; - default: - if (log) - { - log->Printf ("GDBRemoteCommunicationServerLLGS::%s didn't handle state change for pid %" PRIu64 ", new state: %s", - __FUNCTION__, - process->GetID (), - StateAsCString (state)); - } - break; + default: + if (log) { + log->Printf("GDBRemoteCommunicationServerLLGS::%s didn't handle state " + "change for pid %" PRIu64 ", new state: %s", + __FUNCTION__, process->GetID(), StateAsCString(state)); } + break; + } - // Remember the previous state reported to us. - m_inferior_prev_state = state; + // Remember the previous state reported to us. + m_inferior_prev_state = state; } -void -GDBRemoteCommunicationServerLLGS::DidExec (NativeProcessProtocol *process) -{ - ClearProcessSpecificData (); +void GDBRemoteCommunicationServerLLGS::DidExec(NativeProcessProtocol *process) { + ClearProcessSpecificData(); } -void -GDBRemoteCommunicationServerLLGS::DataAvailableCallback () -{ - Log *log (GetLogIfAnyCategoriesSet(GDBR_LOG_COMM)); +void GDBRemoteCommunicationServerLLGS::DataAvailableCallback() { + Log *log(GetLogIfAnyCategoriesSet(GDBR_LOG_COMM)); - if (! m_handshake_completed) - { - if (! HandshakeWithClient()) - { - if(log) - log->Printf("GDBRemoteCommunicationServerLLGS::%s handshake with client failed, exiting", - __FUNCTION__); - m_mainloop.RequestTermination(); - return; - } - m_handshake_completed = true; + if (!m_handshake_completed) { + if (!HandshakeWithClient()) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s handshake with " + "client failed, exiting", + __FUNCTION__); + m_mainloop.RequestTermination(); + return; } + m_handshake_completed = true; + } - bool interrupt = false; - bool done = false; - Error error; - while (true) - { - const PacketResult result = GetPacketAndSendResponse (0, error, interrupt, done); - if (result == PacketResult::ErrorReplyTimeout) - break; // No more packets in the queue - - if ((result != PacketResult::Success)) - { - if(log) - log->Printf("GDBRemoteCommunicationServerLLGS::%s processing a packet failed: %s", - __FUNCTION__, error.AsCString()); - m_mainloop.RequestTermination(); - break; - } + bool interrupt = false; + bool done = false; + Error error; + while (true) { + const PacketResult result = GetPacketAndSendResponse( + std::chrono::microseconds(0), error, interrupt, done); + if (result == PacketResult::ErrorReplyTimeout) + break; // No more packets in the queue + + if ((result != PacketResult::Success)) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s processing a packet " + "failed: %s", + __FUNCTION__, error.AsCString()); + m_mainloop.RequestTermination(); + break; } + } } -Error -GDBRemoteCommunicationServerLLGS::InitializeConnection (std::unique_ptr<Connection> &&connection) -{ - IOObjectSP read_object_sp = connection->GetReadObject(); - GDBRemoteCommunicationServer::SetConnection(connection.release()); +Error GDBRemoteCommunicationServerLLGS::InitializeConnection( + std::unique_ptr<Connection> &&connection) { + IOObjectSP read_object_sp = connection->GetReadObject(); + GDBRemoteCommunicationServer::SetConnection(connection.release()); - Error error; - m_network_handle_up = m_mainloop.RegisterReadObject(read_object_sp, - [this] (MainLoopBase &) { DataAvailableCallback(); }, error); - return error; + Error error; + m_network_handle_up = m_mainloop.RegisterReadObject( + read_object_sp, [this](MainLoopBase &) { DataAvailableCallback(); }, + error); + return error; } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::SendONotification (const char *buffer, uint32_t len) -{ - if ((buffer == nullptr) || (len == 0)) - { - // Nothing to send. - return PacketResult::Success; - } - - StreamString response; - response.PutChar ('O'); - response.PutBytesAsRawHex8 (buffer, len); - - return SendPacketNoLock (response.GetData (), response.GetSize ()); -} - -Error -GDBRemoteCommunicationServerLLGS::SetSTDIOFileDescriptor (int fd) -{ - Error error; - - // Set up the reading/handling of process I/O - std::unique_ptr<ConnectionFileDescriptor> conn_up (new ConnectionFileDescriptor (fd, true)); - if (!conn_up) - { - error.SetErrorString ("failed to create ConnectionFileDescriptor"); - return error; - } +GDBRemoteCommunicationServerLLGS::SendONotification(const char *buffer, + uint32_t len) { + if ((buffer == nullptr) || (len == 0)) { + // Nothing to send. + return PacketResult::Success; + } - m_stdio_communication.SetCloseOnEOF (false); - m_stdio_communication.SetConnection (conn_up.release()); - if (!m_stdio_communication.IsConnected ()) - { - error.SetErrorString ("failed to set connection for inferior I/O communication"); - return error; - } + StreamString response; + response.PutChar('O'); + response.PutBytesAsRawHex8(buffer, len); - return Error(); + return SendPacketNoLock(response.GetString()); } -void -GDBRemoteCommunicationServerLLGS::StartSTDIOForwarding() -{ - // Don't forward if not connected (e.g. when attaching). - if (! m_stdio_communication.IsConnected()) - return; - - // llgs local-process debugging may specify PTY paths, which will make these - // file actions non-null - // process launch -e/o will also make these file actions non-null - // nullptr means that the traffic is expected to flow over gdb-remote protocol - if ( m_process_launch_info.GetFileActionForFD(STDOUT_FILENO) && - m_process_launch_info.GetFileActionForFD(STDERR_FILENO)) - return; - - Error error; - lldbassert(! m_stdio_handle_up); - m_stdio_handle_up = m_mainloop.RegisterReadObject( - m_stdio_communication.GetConnection()->GetReadObject(), - [this] (MainLoopBase &) { SendProcessOutput(); }, error); - - if (! m_stdio_handle_up) - { - // Not much we can do about the failure. Log it and continue without forwarding. - if (Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)) - log->Printf("GDBRemoteCommunicationServerLLGS::%s Failed to set up stdio forwarding: %s", - __FUNCTION__, error.AsCString()); - } -} +Error GDBRemoteCommunicationServerLLGS::SetSTDIOFileDescriptor(int fd) { + Error error; -void -GDBRemoteCommunicationServerLLGS::StopSTDIOForwarding() -{ - m_stdio_handle_up.reset(); -} + // Set up the reading/handling of process I/O + std::unique_ptr<ConnectionFileDescriptor> conn_up( + new ConnectionFileDescriptor(fd, true)); + if (!conn_up) { + error.SetErrorString("failed to create ConnectionFileDescriptor"); + return error; + } -void -GDBRemoteCommunicationServerLLGS::SendProcessOutput() -{ - char buffer[1024]; - ConnectionStatus status; - Error error; - while (true) - { - size_t bytes_read = m_stdio_communication.Read(buffer, sizeof buffer, 0, status, &error); - switch (status) - { - case eConnectionStatusSuccess: - SendONotification(buffer, bytes_read); - break; - case eConnectionStatusLostConnection: - case eConnectionStatusEndOfFile: - case eConnectionStatusError: - case eConnectionStatusNoConnection: - if (Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)) - log->Printf("GDBRemoteCommunicationServerLLGS::%s Stopping stdio forwarding as communication returned status %d (error: %s)", __FUNCTION__, status, error.AsCString()); - m_stdio_handle_up.reset(); - return; - - case eConnectionStatusInterrupted: - case eConnectionStatusTimedOut: - return; - } - } + m_stdio_communication.SetCloseOnEOF(false); + m_stdio_communication.SetConnection(conn_up.release()); + if (!m_stdio_communication.IsConnected()) { + error.SetErrorString( + "failed to set connection for inferior I/O communication"); + return error; + } + + return Error(); +} + +void GDBRemoteCommunicationServerLLGS::StartSTDIOForwarding() { + // Don't forward if not connected (e.g. when attaching). + if (!m_stdio_communication.IsConnected()) + return; + + Error error; + lldbassert(!m_stdio_handle_up); + m_stdio_handle_up = m_mainloop.RegisterReadObject( + m_stdio_communication.GetConnection()->GetReadObject(), + [this](MainLoopBase &) { SendProcessOutput(); }, error); + + if (!m_stdio_handle_up) { + // Not much we can do about the failure. Log it and continue without + // forwarding. + if (Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)) + log->Printf("GDBRemoteCommunicationServerLLGS::%s Failed to set up stdio " + "forwarding: %s", + __FUNCTION__, error.AsCString()); + } +} + +void GDBRemoteCommunicationServerLLGS::StopSTDIOForwarding() { + m_stdio_handle_up.reset(); +} + +void GDBRemoteCommunicationServerLLGS::SendProcessOutput() { + char buffer[1024]; + ConnectionStatus status; + Error error; + while (true) { + size_t bytes_read = m_stdio_communication.Read( + buffer, sizeof buffer, std::chrono::microseconds(0), status, &error); + switch (status) { + case eConnectionStatusSuccess: + SendONotification(buffer, bytes_read); + break; + case eConnectionStatusLostConnection: + case eConnectionStatusEndOfFile: + case eConnectionStatusError: + case eConnectionStatusNoConnection: + if (Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)) + log->Printf("GDBRemoteCommunicationServerLLGS::%s Stopping stdio " + "forwarding as communication returned status %d (error: " + "%s)", + __FUNCTION__, status, error.AsCString()); + m_stdio_handle_up.reset(); + return; + + case eConnectionStatusInterrupted: + case eConnectionStatusTimedOut: + return; + } + } } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_qProcessInfo (StringExtractorGDBRemote &packet) -{ - // Fail if we don't have a current process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - return SendErrorResponse (68); +GDBRemoteCommunicationServerLLGS::Handle_qProcessInfo( + StringExtractorGDBRemote &packet) { + // Fail if we don't have a current process. + if (!m_debugged_process_sp || + (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) + return SendErrorResponse(68); - lldb::pid_t pid = m_debugged_process_sp->GetID (); + lldb::pid_t pid = m_debugged_process_sp->GetID(); - if (pid == LLDB_INVALID_PROCESS_ID) - return SendErrorResponse (1); + if (pid == LLDB_INVALID_PROCESS_ID) + return SendErrorResponse(1); - ProcessInstanceInfo proc_info; - if (!Host::GetProcessInfo (pid, proc_info)) - return SendErrorResponse (1); + ProcessInstanceInfo proc_info; + if (!Host::GetProcessInfo(pid, proc_info)) + return SendErrorResponse(1); - StreamString response; - CreateProcessInfoResponse_DebugServerStyle(proc_info, response); - return SendPacketNoLock (response.GetData (), response.GetSize ()); + StreamString response; + CreateProcessInfoResponse_DebugServerStyle(proc_info, response); + return SendPacketNoLock(response.GetString()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_qC (StringExtractorGDBRemote &packet) -{ - // Fail if we don't have a current process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - return SendErrorResponse (68); +GDBRemoteCommunicationServerLLGS::Handle_qC(StringExtractorGDBRemote &packet) { + // Fail if we don't have a current process. + if (!m_debugged_process_sp || + (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) + return SendErrorResponse(68); - // Make sure we set the current thread so g and p packets return - // the data the gdb will expect. - lldb::tid_t tid = m_debugged_process_sp->GetCurrentThreadID (); - SetCurrentThreadID (tid); + // Make sure we set the current thread so g and p packets return + // the data the gdb will expect. + lldb::tid_t tid = m_debugged_process_sp->GetCurrentThreadID(); + SetCurrentThreadID(tid); - NativeThreadProtocolSP thread_sp = m_debugged_process_sp->GetCurrentThread (); - if (!thread_sp) - return SendErrorResponse (69); + NativeThreadProtocolSP thread_sp = m_debugged_process_sp->GetCurrentThread(); + if (!thread_sp) + return SendErrorResponse(69); - StreamString response; - response.Printf ("QC%" PRIx64, thread_sp->GetID ()); + StreamString response; + response.Printf("QC%" PRIx64, thread_sp->GetID()); - return SendPacketNoLock (response.GetData(), response.GetSize()); + return SendPacketNoLock(response.GetString()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_k (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); +GDBRemoteCommunicationServerLLGS::Handle_k(StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - StopSTDIOForwarding(); + StopSTDIOForwarding(); - if (! m_debugged_process_sp) - { - if (log) - log->Printf("GDBRemoteCommunicationServerLLGS::%s No debugged process found.", __FUNCTION__); - return PacketResult::Success; - } + if (!m_debugged_process_sp) { + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s No debugged process found.", + __FUNCTION__); + return PacketResult::Success; + } - Error error = m_debugged_process_sp->Kill(); - if (error.Fail() && log) - log->Printf("GDBRemoteCommunicationServerLLGS::%s Failed to kill debugged process %" PRIu64 ": %s", - __FUNCTION__, m_debugged_process_sp->GetID(), error.AsCString()); + Error error = m_debugged_process_sp->Kill(); + if (error.Fail() && log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s Failed to kill debugged " + "process %" PRIu64 ": %s", + __FUNCTION__, m_debugged_process_sp->GetID(), + error.AsCString()); - // No OK response for kill packet. - // return SendOKResponse (); - return PacketResult::Success; + // No OK response for kill packet. + // return SendOKResponse (); + return PacketResult::Success; } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_QSetDisableASLR (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen ("QSetDisableASLR:")); - if (packet.GetU32(0)) - m_process_launch_info.GetFlags().Set (eLaunchFlagDisableASLR); - else - m_process_launch_info.GetFlags().Clear (eLaunchFlagDisableASLR); - return SendOKResponse (); +GDBRemoteCommunicationServerLLGS::Handle_QSetDisableASLR( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("QSetDisableASLR:")); + if (packet.GetU32(0)) + m_process_launch_info.GetFlags().Set(eLaunchFlagDisableASLR); + else + m_process_launch_info.GetFlags().Clear(eLaunchFlagDisableASLR); + return SendOKResponse(); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_QSetWorkingDir (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos (::strlen ("QSetWorkingDir:")); - std::string path; - packet.GetHexByteString (path); - m_process_launch_info.SetWorkingDirectory(FileSpec{path, true}); - return SendOKResponse (); +GDBRemoteCommunicationServerLLGS::Handle_QSetWorkingDir( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("QSetWorkingDir:")); + std::string path; + packet.GetHexByteString(path); + m_process_launch_info.SetWorkingDirectory(FileSpec{path, true}); + return SendOKResponse(); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_qGetWorkingDir (StringExtractorGDBRemote &packet) -{ - FileSpec working_dir{m_process_launch_info.GetWorkingDirectory()}; - if (working_dir) - { - StreamString response; - response.PutCStringAsRawHex8(working_dir.GetCString()); - return SendPacketNoLock(response.GetData(), response.GetSize()); - } +GDBRemoteCommunicationServerLLGS::Handle_qGetWorkingDir( + StringExtractorGDBRemote &packet) { + FileSpec working_dir{m_process_launch_info.GetWorkingDirectory()}; + if (working_dir) { + StreamString response; + response.PutCStringAsRawHex8(working_dir.GetCString()); + return SendPacketNoLock(response.GetString()); + } - return SendErrorResponse(14); + return SendErrorResponse(14); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_C (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_THREAD)); - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__); - - // Ensure we have a native process. - if (!m_debugged_process_sp) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s no debugged process shared pointer", __FUNCTION__); - return SendErrorResponse (0x36); - } - - // Pull out the signal number. - packet.SetFilePos (::strlen ("C")); - if (packet.GetBytesLeft () < 1) - { - // Shouldn't be using a C without a signal. - return SendIllFormedResponse (packet, "C packet specified without signal."); - } - const uint32_t signo = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ()); - if (signo == std::numeric_limits<uint32_t>::max ()) - return SendIllFormedResponse (packet, "failed to parse signal number"); - - // Handle optional continue address. - if (packet.GetBytesLeft () > 0) - { - // FIXME add continue at address support for $C{signo}[;{continue-address}]. - if (*packet.Peek () == ';') - return SendUnimplementedResponse (packet.GetStringRef().c_str()); - else - return SendIllFormedResponse (packet, "unexpected content after $C{signal-number}"); - } +GDBRemoteCommunicationServerLLGS::Handle_C(StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__); - ResumeActionList resume_actions (StateType::eStateRunning, 0); - Error error; - - // We have two branches: what to do if a continue thread is specified (in which case we target - // sending the signal to that thread), or when we don't have a continue thread set (in which - // case we send a signal to the process). - - // TODO discuss with Greg Clayton, make sure this makes sense. - - lldb::tid_t signal_tid = GetContinueThreadID (); - if (signal_tid != LLDB_INVALID_THREAD_ID) - { - // The resume action for the continue thread (or all threads if a continue thread is not set). - ResumeAction action = { GetContinueThreadID (), StateType::eStateRunning, static_cast<int> (signo) }; - - // Add the action for the continue thread (or all threads when the continue thread isn't present). - resume_actions.Append (action); - } + // Ensure we have a native process. + if (!m_debugged_process_sp) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s no debugged process " + "shared pointer", + __FUNCTION__); + return SendErrorResponse(0x36); + } + + // Pull out the signal number. + packet.SetFilePos(::strlen("C")); + if (packet.GetBytesLeft() < 1) { + // Shouldn't be using a C without a signal. + return SendIllFormedResponse(packet, "C packet specified without signal."); + } + const uint32_t signo = + packet.GetHexMaxU32(false, std::numeric_limits<uint32_t>::max()); + if (signo == std::numeric_limits<uint32_t>::max()) + return SendIllFormedResponse(packet, "failed to parse signal number"); + + // Handle optional continue address. + if (packet.GetBytesLeft() > 0) { + // FIXME add continue at address support for $C{signo}[;{continue-address}]. + if (*packet.Peek() == ';') + return SendUnimplementedResponse(packet.GetStringRef().c_str()); else - { - // Send the signal to the process since we weren't targeting a specific continue thread with the signal. - error = m_debugged_process_sp->Signal (signo); - if (error.Fail ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to send signal for process %" PRIu64 ": %s", - __FUNCTION__, - m_debugged_process_sp->GetID (), - error.AsCString ()); - - return SendErrorResponse (0x52); - } - } - - // Resume the threads. - error = m_debugged_process_sp->Resume (resume_actions); - if (error.Fail ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to resume threads for process %" PRIu64 ": %s", - __FUNCTION__, - m_debugged_process_sp->GetID (), - error.AsCString ()); + return SendIllFormedResponse( + packet, "unexpected content after $C{signal-number}"); + } + + ResumeActionList resume_actions(StateType::eStateRunning, 0); + Error error; + + // We have two branches: what to do if a continue thread is specified (in + // which case we target + // sending the signal to that thread), or when we don't have a continue thread + // set (in which + // case we send a signal to the process). + + // TODO discuss with Greg Clayton, make sure this makes sense. + + lldb::tid_t signal_tid = GetContinueThreadID(); + if (signal_tid != LLDB_INVALID_THREAD_ID) { + // The resume action for the continue thread (or all threads if a continue + // thread is not set). + ResumeAction action = {GetContinueThreadID(), StateType::eStateRunning, + static_cast<int>(signo)}; + + // Add the action for the continue thread (or all threads when the continue + // thread isn't present). + resume_actions.Append(action); + } else { + // Send the signal to the process since we weren't targeting a specific + // continue thread with the signal. + error = m_debugged_process_sp->Signal(signo); + if (error.Fail()) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed to send " + "signal for process %" PRIu64 ": %s", + __FUNCTION__, m_debugged_process_sp->GetID(), + error.AsCString()); + + return SendErrorResponse(0x52); + } + } + + // Resume the threads. + error = m_debugged_process_sp->Resume(resume_actions); + if (error.Fail()) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed to resume " + "threads for process %" PRIu64 ": %s", + __FUNCTION__, m_debugged_process_sp->GetID(), + error.AsCString()); - return SendErrorResponse (0x38); - } + return SendErrorResponse(0x38); + } - // Don't send an "OK" packet; response is the stopped/exited message. - return PacketResult::Success; + // Don't send an "OK" packet; response is the stopped/exited message. + return PacketResult::Success; } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_c (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_THREAD)); - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__); - - packet.SetFilePos (packet.GetFilePos() + ::strlen ("c")); +GDBRemoteCommunicationServerLLGS::Handle_c(StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__); - // For now just support all continue. - const bool has_continue_address = (packet.GetBytesLeft () > 0); - if (has_continue_address) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s not implemented for c{address} variant [%s remains]", __FUNCTION__, packet.Peek ()); - return SendUnimplementedResponse (packet.GetStringRef().c_str()); - } + packet.SetFilePos(packet.GetFilePos() + ::strlen("c")); - // Ensure we have a native process. - if (!m_debugged_process_sp) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s no debugged process shared pointer", __FUNCTION__); - return SendErrorResponse (0x36); - } + // For now just support all continue. + const bool has_continue_address = (packet.GetBytesLeft() > 0); + if (has_continue_address) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s not implemented for " + "c{address} variant [%s remains]", + __FUNCTION__, packet.Peek()); + return SendUnimplementedResponse(packet.GetStringRef().c_str()); + } + + // Ensure we have a native process. + if (!m_debugged_process_sp) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s no debugged process " + "shared pointer", + __FUNCTION__); + return SendErrorResponse(0x36); + } - // Build the ResumeActionList - ResumeActionList actions (StateType::eStateRunning, 0); + // Build the ResumeActionList + ResumeActionList actions(StateType::eStateRunning, 0); - Error error = m_debugged_process_sp->Resume (actions); - if (error.Fail ()) - { - if (log) - { - log->Printf ("GDBRemoteCommunicationServerLLGS::%s c failed for process %" PRIu64 ": %s", - __FUNCTION__, - m_debugged_process_sp->GetID (), - error.AsCString ()); - } - return SendErrorResponse (GDBRemoteServerError::eErrorResume); + Error error = m_debugged_process_sp->Resume(actions); + if (error.Fail()) { + if (log) { + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s c failed for process %" PRIu64 + ": %s", + __FUNCTION__, m_debugged_process_sp->GetID(), error.AsCString()); } + return SendErrorResponse(GDBRemoteServerError::eErrorResume); + } - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s continued process %" PRIu64, __FUNCTION__, m_debugged_process_sp->GetID ()); + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s continued process %" PRIu64, + __FUNCTION__, m_debugged_process_sp->GetID()); - // No response required from continue. - return PacketResult::Success; + // No response required from continue. + return PacketResult::Success; } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_vCont_actions (StringExtractorGDBRemote &packet) -{ - StreamString response; - response.Printf("vCont;c;C;s;S"); +GDBRemoteCommunicationServerLLGS::Handle_vCont_actions( + StringExtractorGDBRemote &packet) { + StreamString response; + response.Printf("vCont;c;C;s;S"); - return SendPacketNoLock(response.GetData(), response.GetSize()); + return SendPacketNoLock(response.GetString()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_vCont (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s handling vCont packet", __FUNCTION__); - - packet.SetFilePos (::strlen ("vCont")); +GDBRemoteCommunicationServerLLGS::Handle_vCont( + StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s handling vCont packet", + __FUNCTION__); - if (packet.GetBytesLeft() == 0) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s missing action from vCont package", __FUNCTION__); - return SendIllFormedResponse (packet, "Missing action from vCont package"); - } + packet.SetFilePos(::strlen("vCont")); - // Check if this is all continue (no options or ";c"). - if (::strcmp (packet.Peek (), ";c") == 0) - { - // Move past the ';', then do a simple 'c'. - packet.SetFilePos (packet.GetFilePos () + 1); - return Handle_c (packet); - } - else if (::strcmp (packet.Peek (), ";s") == 0) - { - // Move past the ';', then do a simple 's'. - packet.SetFilePos (packet.GetFilePos () + 1); - return Handle_s (packet); - } + if (packet.GetBytesLeft() == 0) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s missing action from " + "vCont package", + __FUNCTION__); + return SendIllFormedResponse(packet, "Missing action from vCont package"); + } + + // Check if this is all continue (no options or ";c"). + if (::strcmp(packet.Peek(), ";c") == 0) { + // Move past the ';', then do a simple 'c'. + packet.SetFilePos(packet.GetFilePos() + 1); + return Handle_c(packet); + } else if (::strcmp(packet.Peek(), ";s") == 0) { + // Move past the ';', then do a simple 's'. + packet.SetFilePos(packet.GetFilePos() + 1); + return Handle_s(packet); + } + + // Ensure we have a native process. + if (!m_debugged_process_sp) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s no debugged process " + "shared pointer", + __FUNCTION__); + return SendErrorResponse(0x36); + } + + ResumeActionList thread_actions; + + while (packet.GetBytesLeft() && *packet.Peek() == ';') { + // Skip the semi-colon. + packet.GetChar(); + + // Build up the thread action. + ResumeAction thread_action; + thread_action.tid = LLDB_INVALID_THREAD_ID; + thread_action.state = eStateInvalid; + thread_action.signal = 0; + + const char action = packet.GetChar(); + switch (action) { + case 'C': + thread_action.signal = packet.GetHexMaxU32(false, 0); + if (thread_action.signal == 0) + return SendIllFormedResponse( + packet, "Could not parse signal in vCont packet C action"); + LLVM_FALLTHROUGH; + + case 'c': + // Continue + thread_action.state = eStateRunning; + break; + + case 'S': + thread_action.signal = packet.GetHexMaxU32(false, 0); + if (thread_action.signal == 0) + return SendIllFormedResponse( + packet, "Could not parse signal in vCont packet S action"); + LLVM_FALLTHROUGH; + + case 's': + // Step + thread_action.state = eStateStepping; + break; - // Ensure we have a native process. - if (!m_debugged_process_sp) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s no debugged process shared pointer", __FUNCTION__); - return SendErrorResponse (0x36); + default: + return SendIllFormedResponse(packet, "Unsupported vCont action"); + break; } - ResumeActionList thread_actions; - - while (packet.GetBytesLeft () && *packet.Peek () == ';') - { - // Skip the semi-colon. - packet.GetChar (); - - // Build up the thread action. - ResumeAction thread_action; - thread_action.tid = LLDB_INVALID_THREAD_ID; - thread_action.state = eStateInvalid; - thread_action.signal = 0; - - const char action = packet.GetChar (); - switch (action) - { - case 'C': - thread_action.signal = packet.GetHexMaxU32 (false, 0); - if (thread_action.signal == 0) - return SendIllFormedResponse (packet, "Could not parse signal in vCont packet C action"); - LLVM_FALLTHROUGH; - - case 'c': - // Continue - thread_action.state = eStateRunning; - break; - - case 'S': - thread_action.signal = packet.GetHexMaxU32 (false, 0); - if (thread_action.signal == 0) - return SendIllFormedResponse (packet, "Could not parse signal in vCont packet S action"); - LLVM_FALLTHROUGH; - - case 's': - // Step - thread_action.state = eStateStepping; - break; - - default: - return SendIllFormedResponse (packet, "Unsupported vCont action"); - break; - } - - // Parse out optional :{thread-id} value. - if (packet.GetBytesLeft () && (*packet.Peek () == ':')) - { - // Consume the separator. - packet.GetChar (); - - thread_action.tid = packet.GetHexMaxU32 (false, LLDB_INVALID_THREAD_ID); - if (thread_action.tid == LLDB_INVALID_THREAD_ID) - return SendIllFormedResponse (packet, "Could not parse thread number in vCont packet"); - } + // Parse out optional :{thread-id} value. + if (packet.GetBytesLeft() && (*packet.Peek() == ':')) { + // Consume the separator. + packet.GetChar(); - thread_actions.Append (thread_action); + thread_action.tid = packet.GetHexMaxU32(false, LLDB_INVALID_THREAD_ID); + if (thread_action.tid == LLDB_INVALID_THREAD_ID) + return SendIllFormedResponse( + packet, "Could not parse thread number in vCont packet"); } - Error error = m_debugged_process_sp->Resume (thread_actions); - if (error.Fail ()) - { - if (log) - { - log->Printf ("GDBRemoteCommunicationServerLLGS::%s vCont failed for process %" PRIu64 ": %s", - __FUNCTION__, - m_debugged_process_sp->GetID (), - error.AsCString ()); - } - return SendErrorResponse (GDBRemoteServerError::eErrorResume); + thread_actions.Append(thread_action); + } + + Error error = m_debugged_process_sp->Resume(thread_actions); + if (error.Fail()) { + if (log) { + log->Printf("GDBRemoteCommunicationServerLLGS::%s vCont failed for " + "process %" PRIu64 ": %s", + __FUNCTION__, m_debugged_process_sp->GetID(), + error.AsCString()); } + return SendErrorResponse(GDBRemoteServerError::eErrorResume); + } - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s continued process %" PRIu64, __FUNCTION__, m_debugged_process_sp->GetID ()); + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s continued process %" PRIu64, + __FUNCTION__, m_debugged_process_sp->GetID()); - // No response required from vCont. - return PacketResult::Success; + // No response required from vCont. + return PacketResult::Success; } -void -GDBRemoteCommunicationServerLLGS::SetCurrentThreadID (lldb::tid_t tid) -{ - Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_THREAD)); - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s setting current thread id to %" PRIu64, __FUNCTION__, tid); +void GDBRemoteCommunicationServerLLGS::SetCurrentThreadID(lldb::tid_t tid) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s setting current thread " + "id to %" PRIu64, + __FUNCTION__, tid); - m_current_tid = tid; - if (m_debugged_process_sp) - m_debugged_process_sp->SetCurrentThreadID (m_current_tid); + m_current_tid = tid; + if (m_debugged_process_sp) + m_debugged_process_sp->SetCurrentThreadID(m_current_tid); } -void -GDBRemoteCommunicationServerLLGS::SetContinueThreadID (lldb::tid_t tid) -{ - Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_THREAD)); - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s setting continue thread id to %" PRIu64, __FUNCTION__, tid); +void GDBRemoteCommunicationServerLLGS::SetContinueThreadID(lldb::tid_t tid) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s setting continue thread " + "id to %" PRIu64, + __FUNCTION__, tid); - m_continue_tid = tid; + m_continue_tid = tid; } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_stop_reason (StringExtractorGDBRemote &packet) -{ - // Handle the $? gdbremote command. +GDBRemoteCommunicationServerLLGS::Handle_stop_reason( + StringExtractorGDBRemote &packet) { + // Handle the $? gdbremote command. - // If no process, indicate error - if (!m_debugged_process_sp) - return SendErrorResponse (02); + // If no process, indicate error + if (!m_debugged_process_sp) + return SendErrorResponse(02); - return SendStopReasonForState (m_debugged_process_sp->GetState()); + return SendStopReasonForState(m_debugged_process_sp->GetState()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::SendStopReasonForState (lldb::StateType process_state) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - - switch (process_state) - { - case eStateAttaching: - case eStateLaunching: - case eStateRunning: - case eStateStepping: - case eStateDetached: - // NOTE: gdb protocol doc looks like it should return $OK - // when everything is running (i.e. no stopped result). - return PacketResult::Success; // Ignore - - case eStateSuspended: - case eStateStopped: - case eStateCrashed: - { - lldb::tid_t tid = m_debugged_process_sp->GetCurrentThreadID (); - // Make sure we set the current thread so g and p packets return - // the data the gdb will expect. - SetCurrentThreadID (tid); - return SendStopReplyPacketForThread (tid); - } +GDBRemoteCommunicationServerLLGS::SendStopReasonForState( + lldb::StateType process_state) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + switch (process_state) { + case eStateAttaching: + case eStateLaunching: + case eStateRunning: + case eStateStepping: + case eStateDetached: + // NOTE: gdb protocol doc looks like it should return $OK + // when everything is running (i.e. no stopped result). + return PacketResult::Success; // Ignore + + case eStateSuspended: + case eStateStopped: + case eStateCrashed: { + lldb::tid_t tid = m_debugged_process_sp->GetCurrentThreadID(); + // Make sure we set the current thread so g and p packets return + // the data the gdb will expect. + SetCurrentThreadID(tid); + return SendStopReplyPacketForThread(tid); + } - case eStateInvalid: - case eStateUnloaded: - case eStateExited: - return SendWResponse(m_debugged_process_sp.get()); + case eStateInvalid: + case eStateUnloaded: + case eStateExited: + return SendWResponse(m_debugged_process_sp.get()); - default: - if (log) - { - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 ", current state reporting not handled: %s", - __FUNCTION__, - m_debugged_process_sp->GetID (), - StateAsCString (process_state)); - } - break; + default: + if (log) { + log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 + ", current state reporting not handled: %s", + __FUNCTION__, m_debugged_process_sp->GetID(), + StateAsCString(process_state)); } - - return SendErrorResponse (0); + break; + } + + return SendErrorResponse(0); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_qRegisterInfo (StringExtractorGDBRemote &packet) -{ - // Fail if we don't have a current process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - return SendErrorResponse (68); - - // Ensure we have a thread. - NativeThreadProtocolSP thread_sp (m_debugged_process_sp->GetThreadAtIndex (0)); - if (!thread_sp) - return SendErrorResponse (69); - - // Get the register context for the first thread. - NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ()); - if (!reg_context_sp) - return SendErrorResponse (69); - - // Parse out the register number from the request. - packet.SetFilePos (strlen("qRegisterInfo")); - const uint32_t reg_index = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ()); - if (reg_index == std::numeric_limits<uint32_t>::max ()) - return SendErrorResponse (69); - - // Return the end of registers response if we've iterated one past the end of the register set. - if (reg_index >= reg_context_sp->GetUserRegisterCount ()) - return SendErrorResponse (69); - - const RegisterInfo *reg_info = reg_context_sp->GetRegisterInfoAtIndex(reg_index); - if (!reg_info) - return SendErrorResponse (69); - - // Build the reginfos response. - StreamGDBRemote response; - - response.PutCString ("name:"); - response.PutCString (reg_info->name); - response.PutChar (';'); - - if (reg_info->alt_name && reg_info->alt_name[0]) - { - response.PutCString ("alt-name:"); - response.PutCString (reg_info->alt_name); - response.PutChar (';'); - } - - response.Printf ("bitsize:%" PRIu32 ";offset:%" PRIu32 ";", reg_info->byte_size * 8, reg_info->byte_offset); - - switch (reg_info->encoding) - { - case eEncodingUint: response.PutCString ("encoding:uint;"); break; - case eEncodingSint: response.PutCString ("encoding:sint;"); break; - case eEncodingIEEE754: response.PutCString ("encoding:ieee754;"); break; - case eEncodingVector: response.PutCString ("encoding:vector;"); break; - default: break; - } - - switch (reg_info->format) - { - case eFormatBinary: response.PutCString ("format:binary;"); break; - case eFormatDecimal: response.PutCString ("format:decimal;"); break; - case eFormatHex: response.PutCString ("format:hex;"); break; - case eFormatFloat: response.PutCString ("format:float;"); break; - case eFormatVectorOfSInt8: response.PutCString ("format:vector-sint8;"); break; - case eFormatVectorOfUInt8: response.PutCString ("format:vector-uint8;"); break; - case eFormatVectorOfSInt16: response.PutCString ("format:vector-sint16;"); break; - case eFormatVectorOfUInt16: response.PutCString ("format:vector-uint16;"); break; - case eFormatVectorOfSInt32: response.PutCString ("format:vector-sint32;"); break; - case eFormatVectorOfUInt32: response.PutCString ("format:vector-uint32;"); break; - case eFormatVectorOfFloat32: response.PutCString ("format:vector-float32;"); break; - case eFormatVectorOfUInt128: response.PutCString ("format:vector-uint128;"); break; - default: break; - }; - - const char *const register_set_name = reg_context_sp->GetRegisterSetNameForRegisterAtIndex(reg_index); - if (register_set_name) - { - response.PutCString ("set:"); - response.PutCString (register_set_name); - response.PutChar (';'); - } - - if (reg_info->kinds[RegisterKind::eRegisterKindEHFrame] != LLDB_INVALID_REGNUM) - response.Printf ("ehframe:%" PRIu32 ";", reg_info->kinds[RegisterKind::eRegisterKindEHFrame]); - - if (reg_info->kinds[RegisterKind::eRegisterKindDWARF] != LLDB_INVALID_REGNUM) - response.Printf ("dwarf:%" PRIu32 ";", reg_info->kinds[RegisterKind::eRegisterKindDWARF]); - - switch (reg_info->kinds[RegisterKind::eRegisterKindGeneric]) - { - case LLDB_REGNUM_GENERIC_PC: response.PutCString("generic:pc;"); break; - case LLDB_REGNUM_GENERIC_SP: response.PutCString("generic:sp;"); break; - case LLDB_REGNUM_GENERIC_FP: response.PutCString("generic:fp;"); break; - case LLDB_REGNUM_GENERIC_RA: response.PutCString("generic:ra;"); break; - case LLDB_REGNUM_GENERIC_FLAGS: response.PutCString("generic:flags;"); break; - case LLDB_REGNUM_GENERIC_ARG1: response.PutCString("generic:arg1;"); break; - case LLDB_REGNUM_GENERIC_ARG2: response.PutCString("generic:arg2;"); break; - case LLDB_REGNUM_GENERIC_ARG3: response.PutCString("generic:arg3;"); break; - case LLDB_REGNUM_GENERIC_ARG4: response.PutCString("generic:arg4;"); break; - case LLDB_REGNUM_GENERIC_ARG5: response.PutCString("generic:arg5;"); break; - case LLDB_REGNUM_GENERIC_ARG6: response.PutCString("generic:arg6;"); break; - case LLDB_REGNUM_GENERIC_ARG7: response.PutCString("generic:arg7;"); break; - case LLDB_REGNUM_GENERIC_ARG8: response.PutCString("generic:arg8;"); break; - default: break; - } - - if (reg_info->value_regs && reg_info->value_regs[0] != LLDB_INVALID_REGNUM) - { - response.PutCString ("container-regs:"); - int i = 0; - for (const uint32_t *reg_num = reg_info->value_regs; *reg_num != LLDB_INVALID_REGNUM; ++reg_num, ++i) - { - if (i > 0) - response.PutChar (','); - response.Printf ("%" PRIx32, *reg_num); - } - response.PutChar (';'); - } - - if (reg_info->invalidate_regs && reg_info->invalidate_regs[0]) - { - response.PutCString ("invalidate-regs:"); - int i = 0; - for (const uint32_t *reg_num = reg_info->invalidate_regs; *reg_num != LLDB_INVALID_REGNUM; ++reg_num, ++i) - { - if (i > 0) - response.PutChar (','); - response.Printf ("%" PRIx32, *reg_num); - } - response.PutChar (';'); - } - - if (reg_info->dynamic_size_dwarf_expr_bytes) - { - const size_t dwarf_opcode_len = reg_info->dynamic_size_dwarf_len; - response.PutCString("dynamic_size_dwarf_expr_bytes:"); - for(uint32_t i = 0; i < dwarf_opcode_len; ++i) - response.PutHex8 (reg_info->dynamic_size_dwarf_expr_bytes[i]); - response.PutChar(';'); - } - return SendPacketNoLock(response.GetData(), response.GetSize()); +GDBRemoteCommunicationServerLLGS::Handle_qRegisterInfo( + StringExtractorGDBRemote &packet) { + // Fail if we don't have a current process. + if (!m_debugged_process_sp || + (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) + return SendErrorResponse(68); + + // Ensure we have a thread. + NativeThreadProtocolSP thread_sp(m_debugged_process_sp->GetThreadAtIndex(0)); + if (!thread_sp) + return SendErrorResponse(69); + + // Get the register context for the first thread. + NativeRegisterContextSP reg_context_sp(thread_sp->GetRegisterContext()); + if (!reg_context_sp) + return SendErrorResponse(69); + + // Parse out the register number from the request. + packet.SetFilePos(strlen("qRegisterInfo")); + const uint32_t reg_index = + packet.GetHexMaxU32(false, std::numeric_limits<uint32_t>::max()); + if (reg_index == std::numeric_limits<uint32_t>::max()) + return SendErrorResponse(69); + + // Return the end of registers response if we've iterated one past the end of + // the register set. + if (reg_index >= reg_context_sp->GetUserRegisterCount()) + return SendErrorResponse(69); + + const RegisterInfo *reg_info = + reg_context_sp->GetRegisterInfoAtIndex(reg_index); + if (!reg_info) + return SendErrorResponse(69); + + // Build the reginfos response. + StreamGDBRemote response; + + response.PutCString("name:"); + response.PutCString(reg_info->name); + response.PutChar(';'); + + if (reg_info->alt_name && reg_info->alt_name[0]) { + response.PutCString("alt-name:"); + response.PutCString(reg_info->alt_name); + response.PutChar(';'); + } + + response.Printf("bitsize:%" PRIu32 ";offset:%" PRIu32 ";", + reg_info->byte_size * 8, reg_info->byte_offset); + + switch (reg_info->encoding) { + case eEncodingUint: + response.PutCString("encoding:uint;"); + break; + case eEncodingSint: + response.PutCString("encoding:sint;"); + break; + case eEncodingIEEE754: + response.PutCString("encoding:ieee754;"); + break; + case eEncodingVector: + response.PutCString("encoding:vector;"); + break; + default: + break; + } + + switch (reg_info->format) { + case eFormatBinary: + response.PutCString("format:binary;"); + break; + case eFormatDecimal: + response.PutCString("format:decimal;"); + break; + case eFormatHex: + response.PutCString("format:hex;"); + break; + case eFormatFloat: + response.PutCString("format:float;"); + break; + case eFormatVectorOfSInt8: + response.PutCString("format:vector-sint8;"); + break; + case eFormatVectorOfUInt8: + response.PutCString("format:vector-uint8;"); + break; + case eFormatVectorOfSInt16: + response.PutCString("format:vector-sint16;"); + break; + case eFormatVectorOfUInt16: + response.PutCString("format:vector-uint16;"); + break; + case eFormatVectorOfSInt32: + response.PutCString("format:vector-sint32;"); + break; + case eFormatVectorOfUInt32: + response.PutCString("format:vector-uint32;"); + break; + case eFormatVectorOfFloat32: + response.PutCString("format:vector-float32;"); + break; + case eFormatVectorOfUInt64: + response.PutCString("format:vector-uint64;"); + break; + case eFormatVectorOfUInt128: + response.PutCString("format:vector-uint128;"); + break; + default: + break; + }; + + const char *const register_set_name = + reg_context_sp->GetRegisterSetNameForRegisterAtIndex(reg_index); + if (register_set_name) { + response.PutCString("set:"); + response.PutCString(register_set_name); + response.PutChar(';'); + } + + if (reg_info->kinds[RegisterKind::eRegisterKindEHFrame] != + LLDB_INVALID_REGNUM) + response.Printf("ehframe:%" PRIu32 ";", + reg_info->kinds[RegisterKind::eRegisterKindEHFrame]); + + if (reg_info->kinds[RegisterKind::eRegisterKindDWARF] != LLDB_INVALID_REGNUM) + response.Printf("dwarf:%" PRIu32 ";", + reg_info->kinds[RegisterKind::eRegisterKindDWARF]); + + switch (reg_info->kinds[RegisterKind::eRegisterKindGeneric]) { + case LLDB_REGNUM_GENERIC_PC: + response.PutCString("generic:pc;"); + break; + case LLDB_REGNUM_GENERIC_SP: + response.PutCString("generic:sp;"); + break; + case LLDB_REGNUM_GENERIC_FP: + response.PutCString("generic:fp;"); + break; + case LLDB_REGNUM_GENERIC_RA: + response.PutCString("generic:ra;"); + break; + case LLDB_REGNUM_GENERIC_FLAGS: + response.PutCString("generic:flags;"); + break; + case LLDB_REGNUM_GENERIC_ARG1: + response.PutCString("generic:arg1;"); + break; + case LLDB_REGNUM_GENERIC_ARG2: + response.PutCString("generic:arg2;"); + break; + case LLDB_REGNUM_GENERIC_ARG3: + response.PutCString("generic:arg3;"); + break; + case LLDB_REGNUM_GENERIC_ARG4: + response.PutCString("generic:arg4;"); + break; + case LLDB_REGNUM_GENERIC_ARG5: + response.PutCString("generic:arg5;"); + break; + case LLDB_REGNUM_GENERIC_ARG6: + response.PutCString("generic:arg6;"); + break; + case LLDB_REGNUM_GENERIC_ARG7: + response.PutCString("generic:arg7;"); + break; + case LLDB_REGNUM_GENERIC_ARG8: + response.PutCString("generic:arg8;"); + break; + default: + break; + } + + if (reg_info->value_regs && reg_info->value_regs[0] != LLDB_INVALID_REGNUM) { + response.PutCString("container-regs:"); + int i = 0; + for (const uint32_t *reg_num = reg_info->value_regs; + *reg_num != LLDB_INVALID_REGNUM; ++reg_num, ++i) { + if (i > 0) + response.PutChar(','); + response.Printf("%" PRIx32, *reg_num); + } + response.PutChar(';'); + } + + if (reg_info->invalidate_regs && reg_info->invalidate_regs[0]) { + response.PutCString("invalidate-regs:"); + int i = 0; + for (const uint32_t *reg_num = reg_info->invalidate_regs; + *reg_num != LLDB_INVALID_REGNUM; ++reg_num, ++i) { + if (i > 0) + response.PutChar(','); + response.Printf("%" PRIx32, *reg_num); + } + response.PutChar(';'); + } + + if (reg_info->dynamic_size_dwarf_expr_bytes) { + const size_t dwarf_opcode_len = reg_info->dynamic_size_dwarf_len; + response.PutCString("dynamic_size_dwarf_expr_bytes:"); + for (uint32_t i = 0; i < dwarf_opcode_len; ++i) + response.PutHex8(reg_info->dynamic_size_dwarf_expr_bytes[i]); + response.PutChar(';'); + } + return SendPacketNoLock(response.GetString()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_qfThreadInfo (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); - - // Fail if we don't have a current process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s() no process (%s), returning OK", __FUNCTION__, m_debugged_process_sp ? "invalid process id" : "null m_debugged_process_sp"); - return SendOKResponse (); - } - - StreamGDBRemote response; - response.PutChar ('m'); +GDBRemoteCommunicationServerLLGS::Handle_qfThreadInfo( + StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + // Fail if we don't have a current process. + if (!m_debugged_process_sp || + (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) { if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s() starting thread iteration", __FUNCTION__); - - NativeThreadProtocolSP thread_sp; - uint32_t thread_index; - for (thread_index = 0, thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index); - thread_sp; - ++thread_index, thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index)) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s() iterated thread %" PRIu32 "(%s, tid=0x%" PRIx64 ")", __FUNCTION__, thread_index, thread_sp ? "is not null" : "null", thread_sp ? thread_sp->GetID () : LLDB_INVALID_THREAD_ID); - if (thread_index > 0) - response.PutChar(','); - response.Printf ("%" PRIx64, thread_sp->GetID ()); - } - + log->Printf("GDBRemoteCommunicationServerLLGS::%s() no process (%s), " + "returning OK", + __FUNCTION__, + m_debugged_process_sp ? "invalid process id" + : "null m_debugged_process_sp"); + return SendOKResponse(); + } + + StreamGDBRemote response; + response.PutChar('m'); + + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s() starting thread iteration", + __FUNCTION__); + + NativeThreadProtocolSP thread_sp; + uint32_t thread_index; + for (thread_index = 0, + thread_sp = m_debugged_process_sp->GetThreadAtIndex(thread_index); + thread_sp; ++thread_index, + thread_sp = m_debugged_process_sp->GetThreadAtIndex(thread_index)) { if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s() finished thread iteration", __FUNCTION__); + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s() iterated thread %" PRIu32 + "(%s, tid=0x%" PRIx64 ")", + __FUNCTION__, thread_index, thread_sp ? "is not null" : "null", + thread_sp ? thread_sp->GetID() : LLDB_INVALID_THREAD_ID); + if (thread_index > 0) + response.PutChar(','); + response.Printf("%" PRIx64, thread_sp->GetID()); + } + + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s() finished thread iteration", + __FUNCTION__); - return SendPacketNoLock(response.GetData(), response.GetSize()); + return SendPacketNoLock(response.GetString()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_qsThreadInfo (StringExtractorGDBRemote &packet) -{ - // FIXME for now we return the full thread list in the initial packet and always do nothing here. - return SendPacketNoLock ("l", 1); +GDBRemoteCommunicationServerLLGS::Handle_qsThreadInfo( + StringExtractorGDBRemote &packet) { + // FIXME for now we return the full thread list in the initial packet and + // always do nothing here. + return SendPacketNoLock("l"); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_p (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); - - // Parse out the register number from the request. - packet.SetFilePos (strlen("p")); - const uint32_t reg_index = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ()); - if (reg_index == std::numeric_limits<uint32_t>::max ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, could not parse register number from request \"%s\"", __FUNCTION__, packet.GetStringRef ().c_str ()); - return SendErrorResponse (0x15); - } - - // Get the thread to use. - NativeThreadProtocolSP thread_sp = GetThreadFromSuffix (packet); - if (!thread_sp) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no thread available", __FUNCTION__); - return SendErrorResponse (0x15); - } - - // Get the thread's register context. - NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ()); - if (!reg_context_sp) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 " failed, no register context available for the thread", __FUNCTION__, m_debugged_process_sp->GetID (), thread_sp->GetID ()); - return SendErrorResponse (0x15); - } - - // Return the end of registers response if we've iterated one past the end of the register set. - if (reg_index >= reg_context_sp->GetUserRegisterCount ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, requested register %" PRIu32 " beyond register count %" PRIu32, __FUNCTION__, reg_index, reg_context_sp->GetUserRegisterCount ()); - return SendErrorResponse (0x15); - } - - const RegisterInfo *reg_info = reg_context_sp->GetRegisterInfoAtIndex(reg_index); - if (!reg_info) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, requested register %" PRIu32 " returned NULL", __FUNCTION__, reg_index); - return SendErrorResponse (0x15); - } - - // Build the reginfos response. - StreamGDBRemote response; - - // Retrieve the value - RegisterValue reg_value; - Error error = reg_context_sp->ReadRegister (reg_info, reg_value); - if (error.Fail ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, read of requested register %" PRIu32 " (%s) failed: %s", __FUNCTION__, reg_index, reg_info->name, error.AsCString ()); - return SendErrorResponse (0x15); - } - - const uint8_t *const data = reinterpret_cast<const uint8_t*> (reg_value.GetBytes ()); - if (!data) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to get data bytes from requested register %" PRIu32, __FUNCTION__, reg_index); - return SendErrorResponse (0x15); - } +GDBRemoteCommunicationServerLLGS::Handle_p(StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + + // Parse out the register number from the request. + packet.SetFilePos(strlen("p")); + const uint32_t reg_index = + packet.GetHexMaxU32(false, std::numeric_limits<uint32_t>::max()); + if (reg_index == std::numeric_limits<uint32_t>::max()) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed, could not " + "parse register number from request \"%s\"", + __FUNCTION__, packet.GetStringRef().c_str()); + return SendErrorResponse(0x15); + } + + // Get the thread to use. + NativeThreadProtocolSP thread_sp = GetThreadFromSuffix(packet); + if (!thread_sp) { + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s failed, no thread available", + __FUNCTION__); + return SendErrorResponse(0x15); + } + + // Get the thread's register context. + NativeRegisterContextSP reg_context_sp(thread_sp->GetRegisterContext()); + if (!reg_context_sp) { + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 + " failed, no register context available for the thread", + __FUNCTION__, m_debugged_process_sp->GetID(), thread_sp->GetID()); + return SendErrorResponse(0x15); + } + + // Return the end of registers response if we've iterated one past the end of + // the register set. + if (reg_index >= reg_context_sp->GetUserRegisterCount()) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed, requested " + "register %" PRIu32 " beyond register count %" PRIu32, + __FUNCTION__, reg_index, + reg_context_sp->GetUserRegisterCount()); + return SendErrorResponse(0x15); + } + + const RegisterInfo *reg_info = + reg_context_sp->GetRegisterInfoAtIndex(reg_index); + if (!reg_info) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed, requested " + "register %" PRIu32 " returned NULL", + __FUNCTION__, reg_index); + return SendErrorResponse(0x15); + } + + // Build the reginfos response. + StreamGDBRemote response; + + // Retrieve the value + RegisterValue reg_value; + Error error = reg_context_sp->ReadRegister(reg_info, reg_value); + if (error.Fail()) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed, read of " + "requested register %" PRIu32 " (%s) failed: %s", + __FUNCTION__, reg_index, reg_info->name, error.AsCString()); + return SendErrorResponse(0x15); + } + + const uint8_t *const data = + reinterpret_cast<const uint8_t *>(reg_value.GetBytes()); + if (!data) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed to get data " + "bytes from requested register %" PRIu32, + __FUNCTION__, reg_index); + return SendErrorResponse(0x15); + } - // FIXME flip as needed to get data in big/little endian format for this host. - for (uint32_t i = 0; i < reg_value.GetByteSize (); ++i) - response.PutHex8 (data[i]); + // FIXME flip as needed to get data in big/little endian format for this host. + for (uint32_t i = 0; i < reg_value.GetByteSize(); ++i) + response.PutHex8(data[i]); - return SendPacketNoLock (response.GetData (), response.GetSize ()); + return SendPacketNoLock(response.GetString()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_P (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); - - // Ensure there is more content. - if (packet.GetBytesLeft () < 1) - return SendIllFormedResponse (packet, "Empty P packet"); - - // Parse out the register number from the request. - packet.SetFilePos (strlen("P")); - const uint32_t reg_index = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ()); - if (reg_index == std::numeric_limits<uint32_t>::max ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, could not parse register number from request \"%s\"", __FUNCTION__, packet.GetStringRef ().c_str ()); - return SendErrorResponse (0x29); - } - - // Note debugserver would send an E30 here. - if ((packet.GetBytesLeft () < 1) || (packet.GetChar () != '=')) - return SendIllFormedResponse (packet, "P packet missing '=' char after register number"); - - // Get process architecture. - ArchSpec process_arch; - if (!m_debugged_process_sp || !m_debugged_process_sp->GetArchitecture (process_arch)) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to retrieve inferior architecture", __FUNCTION__); - return SendErrorResponse (0x49); - } - - // Parse out the value. - uint8_t reg_bytes[32]; // big enough to support up to 256 bit ymmN register - size_t reg_size = packet.GetHexBytesAvail (reg_bytes, sizeof(reg_bytes)); - - // Get the thread to use. - NativeThreadProtocolSP thread_sp = GetThreadFromSuffix (packet); - if (!thread_sp) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no thread available (thread index 0)", __FUNCTION__); - return SendErrorResponse (0x28); - } - - // Get the thread's register context. - NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ()); - if (!reg_context_sp) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 " failed, no register context available for the thread", __FUNCTION__, m_debugged_process_sp->GetID (), thread_sp->GetID ()); - return SendErrorResponse (0x15); - } - - const RegisterInfo *reg_info = reg_context_sp->GetRegisterInfoAtIndex (reg_index); - if (!reg_info) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, requested register %" PRIu32 " returned NULL", __FUNCTION__, reg_index); - return SendErrorResponse (0x48); - } - - // Return the end of registers response if we've iterated one past the end of the register set. - if (reg_index >= reg_context_sp->GetUserRegisterCount ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, requested register %" PRIu32 " beyond register count %" PRIu32, __FUNCTION__, reg_index, reg_context_sp->GetUserRegisterCount ()); - return SendErrorResponse (0x47); - } - - // The dwarf expression are evaluate on host site - // which may cause register size to change - // Hence the reg_size may not be same as reg_info->bytes_size - if ((reg_size != reg_info->byte_size) && !(reg_info->dynamic_size_dwarf_expr_bytes)) - { - return SendIllFormedResponse (packet, "P packet register size is incorrect"); - } - - // Build the reginfos response. - StreamGDBRemote response; - - RegisterValue reg_value (reg_bytes, reg_size, process_arch.GetByteOrder ()); - Error error = reg_context_sp->WriteRegister (reg_info, reg_value); - if (error.Fail ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, write of requested register %" PRIu32 " (%s) failed: %s", __FUNCTION__, reg_index, reg_info->name, error.AsCString ()); - return SendErrorResponse (0x32); - } +GDBRemoteCommunicationServerLLGS::Handle_P(StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + + // Ensure there is more content. + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse(packet, "Empty P packet"); + + // Parse out the register number from the request. + packet.SetFilePos(strlen("P")); + const uint32_t reg_index = + packet.GetHexMaxU32(false, std::numeric_limits<uint32_t>::max()); + if (reg_index == std::numeric_limits<uint32_t>::max()) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed, could not " + "parse register number from request \"%s\"", + __FUNCTION__, packet.GetStringRef().c_str()); + return SendErrorResponse(0x29); + } + + // Note debugserver would send an E30 here. + if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != '=')) + return SendIllFormedResponse( + packet, "P packet missing '=' char after register number"); + + // Get process architecture. + ArchSpec process_arch; + if (!m_debugged_process_sp || + !m_debugged_process_sp->GetArchitecture(process_arch)) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed to retrieve " + "inferior architecture", + __FUNCTION__); + return SendErrorResponse(0x49); + } + + // Parse out the value. + uint8_t reg_bytes[32]; // big enough to support up to 256 bit ymmN register + size_t reg_size = packet.GetHexBytesAvail(reg_bytes); + + // Get the thread to use. + NativeThreadProtocolSP thread_sp = GetThreadFromSuffix(packet); + if (!thread_sp) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed, no thread " + "available (thread index 0)", + __FUNCTION__); + return SendErrorResponse(0x28); + } + + // Get the thread's register context. + NativeRegisterContextSP reg_context_sp(thread_sp->GetRegisterContext()); + if (!reg_context_sp) { + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 + " failed, no register context available for the thread", + __FUNCTION__, m_debugged_process_sp->GetID(), thread_sp->GetID()); + return SendErrorResponse(0x15); + } + + const RegisterInfo *reg_info = + reg_context_sp->GetRegisterInfoAtIndex(reg_index); + if (!reg_info) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed, requested " + "register %" PRIu32 " returned NULL", + __FUNCTION__, reg_index); + return SendErrorResponse(0x48); + } + + // Return the end of registers response if we've iterated one past the end of + // the register set. + if (reg_index >= reg_context_sp->GetUserRegisterCount()) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed, requested " + "register %" PRIu32 " beyond register count %" PRIu32, + __FUNCTION__, reg_index, + reg_context_sp->GetUserRegisterCount()); + return SendErrorResponse(0x47); + } + + // The dwarf expression are evaluate on host site + // which may cause register size to change + // Hence the reg_size may not be same as reg_info->bytes_size + if ((reg_size != reg_info->byte_size) && + !(reg_info->dynamic_size_dwarf_expr_bytes)) { + return SendIllFormedResponse(packet, "P packet register size is incorrect"); + } + + // Build the reginfos response. + StreamGDBRemote response; + + RegisterValue reg_value(reg_bytes, reg_size, process_arch.GetByteOrder()); + Error error = reg_context_sp->WriteRegister(reg_info, reg_value); + if (error.Fail()) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed, write of " + "requested register %" PRIu32 " (%s) failed: %s", + __FUNCTION__, reg_index, reg_info->name, error.AsCString()); + return SendErrorResponse(0x32); + } - return SendOKResponse(); + return SendOKResponse(); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_H (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); - - // Fail if we don't have a current process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__); - return SendErrorResponse (0x15); - } - - // Parse out which variant of $H is requested. - packet.SetFilePos (strlen("H")); - if (packet.GetBytesLeft () < 1) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, H command missing {g,c} variant", __FUNCTION__); - return SendIllFormedResponse (packet, "H command missing {g,c} variant"); - } - - const char h_variant = packet.GetChar (); - switch (h_variant) - { - case 'g': - break; - - case 'c': - break; - - default: - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, invalid $H variant %c", __FUNCTION__, h_variant); - return SendIllFormedResponse (packet, "H variant unsupported, should be c or g"); - } - - // Parse out the thread number. - // FIXME return a parse success/fail value. All values are valid here. - const lldb::tid_t tid = packet.GetHexMaxU64 (false, std::numeric_limits<lldb::tid_t>::max ()); +GDBRemoteCommunicationServerLLGS::Handle_H(StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); - // Ensure we have the given thread when not specifying -1 (all threads) or 0 (any thread). - if (tid != LLDB_INVALID_THREAD_ID && tid != 0) - { - NativeThreadProtocolSP thread_sp (m_debugged_process_sp->GetThreadByID (tid)); - if (!thread_sp) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, tid %" PRIu64 " not found", __FUNCTION__, tid); - return SendErrorResponse (0x15); - } - } + // Fail if we don't have a current process. + if (!m_debugged_process_sp || + (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s failed, no process available", + __FUNCTION__); + return SendErrorResponse(0x15); + } + + // Parse out which variant of $H is requested. + packet.SetFilePos(strlen("H")); + if (packet.GetBytesLeft() < 1) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed, H command " + "missing {g,c} variant", + __FUNCTION__); + return SendIllFormedResponse(packet, "H command missing {g,c} variant"); + } - // Now switch the given thread type. - switch (h_variant) - { - case 'g': - SetCurrentThreadID (tid); - break; + const char h_variant = packet.GetChar(); + switch (h_variant) { + case 'g': + break; - case 'c': - SetContinueThreadID (tid); - break; + case 'c': + break; - default: - assert (false && "unsupported $H variant - shouldn't get here"); - return SendIllFormedResponse (packet, "H variant unsupported, should be c or g"); - } - - return SendOKResponse(); + default: + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s failed, invalid $H variant %c", + __FUNCTION__, h_variant); + return SendIllFormedResponse(packet, + "H variant unsupported, should be c or g"); + } + + // Parse out the thread number. + // FIXME return a parse success/fail value. All values are valid here. + const lldb::tid_t tid = + packet.GetHexMaxU64(false, std::numeric_limits<lldb::tid_t>::max()); + + // Ensure we have the given thread when not specifying -1 (all threads) or 0 + // (any thread). + if (tid != LLDB_INVALID_THREAD_ID && tid != 0) { + NativeThreadProtocolSP thread_sp(m_debugged_process_sp->GetThreadByID(tid)); + if (!thread_sp) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed, tid %" PRIu64 + " not found", + __FUNCTION__, tid); + return SendErrorResponse(0x15); + } + } + + // Now switch the given thread type. + switch (h_variant) { + case 'g': + SetCurrentThreadID(tid); + break; + + case 'c': + SetContinueThreadID(tid); + break; + + default: + assert(false && "unsupported $H variant - shouldn't get here"); + return SendIllFormedResponse(packet, + "H variant unsupported, should be c or g"); + } + + return SendOKResponse(); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_I (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); +GDBRemoteCommunicationServerLLGS::Handle_I(StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); - // Fail if we don't have a current process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__); - return SendErrorResponse (0x15); - } - - packet.SetFilePos (::strlen("I")); - char tmp[4096]; - for (;;) - { - size_t read = packet.GetHexBytesAvail(tmp, sizeof(tmp)); - if (read == 0) - { - break; - } - // write directly to stdin *this might block if stdin buffer is full* - // TODO: enqueue this block in circular buffer and send window size to remote host - ConnectionStatus status; - Error error; - m_stdio_communication.Write(tmp, read, status, &error); - if (error.Fail()) - { - return SendErrorResponse (0x15); - } + // Fail if we don't have a current process. + if (!m_debugged_process_sp || + (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s failed, no process available", + __FUNCTION__); + return SendErrorResponse(0x15); + } + + packet.SetFilePos(::strlen("I")); + uint8_t tmp[4096]; + for (;;) { + size_t read = packet.GetHexBytesAvail(tmp); + if (read == 0) { + break; + } + // write directly to stdin *this might block if stdin buffer is full* + // TODO: enqueue this block in circular buffer and send window size to + // remote host + ConnectionStatus status; + Error error; + m_stdio_communication.Write(tmp, read, status, &error); + if (error.Fail()) { + return SendErrorResponse(0x15); } + } - return SendOKResponse(); + return SendOKResponse(); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_interrupt (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); - - // Fail if we don't have a current process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__); - return SendErrorResponse (0x15); - } - - // Interrupt the process. - Error error = m_debugged_process_sp->Interrupt (); - if (error.Fail ()) - { - if (log) - { - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed for process %" PRIu64 ": %s", - __FUNCTION__, - m_debugged_process_sp->GetID (), - error.AsCString ()); - } - return SendErrorResponse (GDBRemoteServerError::eErrorResume); - } +GDBRemoteCommunicationServerLLGS::Handle_interrupt( + StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); + // Fail if we don't have a current process. + if (!m_debugged_process_sp || + (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) { if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s stopped process %" PRIu64, __FUNCTION__, m_debugged_process_sp->GetID ()); + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s failed, no process available", + __FUNCTION__); + return SendErrorResponse(0x15); + } + + // Interrupt the process. + Error error = m_debugged_process_sp->Interrupt(); + if (error.Fail()) { + if (log) { + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s failed for process %" PRIu64 + ": %s", + __FUNCTION__, m_debugged_process_sp->GetID(), error.AsCString()); + } + return SendErrorResponse(GDBRemoteServerError::eErrorResume); + } + + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s stopped process %" PRIu64, + __FUNCTION__, m_debugged_process_sp->GetID()); - // No response required from stop all. - return PacketResult::Success; + // No response required from stop all. + return PacketResult::Success; } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_memory_read(StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__); - return SendErrorResponse (0x15); - } - - // Parse out the memory address. - packet.SetFilePos (strlen("m")); - if (packet.GetBytesLeft() < 1) - return SendIllFormedResponse(packet, "Too short m packet"); - - // Read the address. Punting on validation. - // FIXME replace with Hex U64 read with no default value that fails on failed read. - const lldb::addr_t read_addr = packet.GetHexMaxU64(false, 0); - - // Validate comma. - if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ',')) - return SendIllFormedResponse(packet, "Comma sep missing in m packet"); - - // Get # bytes to read. - if (packet.GetBytesLeft() < 1) - return SendIllFormedResponse(packet, "Length missing in m packet"); - - const uint64_t byte_count = packet.GetHexMaxU64(false, 0); - if (byte_count == 0) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s nothing to read: zero-length packet", __FUNCTION__); - return SendOKResponse(); - } - - // Allocate the response buffer. - std::string buf(byte_count, '\0'); - if (buf.empty()) - return SendErrorResponse (0x78); - - - // Retrieve the process memory. - size_t bytes_read = 0; - Error error = m_debugged_process_sp->ReadMemoryWithoutTrap(read_addr, &buf[0], byte_count, bytes_read); - if (error.Fail ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " mem 0x%" PRIx64 ": failed to read. Error: %s", __FUNCTION__, m_debugged_process_sp->GetID (), read_addr, error.AsCString ()); - return SendErrorResponse (0x08); - } +GDBRemoteCommunicationServerLLGS::Handle_memory_read( + StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (bytes_read == 0) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " mem 0x%" PRIx64 ": read 0 of %" PRIu64 " requested bytes", __FUNCTION__, m_debugged_process_sp->GetID (), read_addr, byte_count); - return SendErrorResponse (0x08); - } - - StreamGDBRemote response; - packet.SetFilePos(0); - char kind = packet.GetChar('?'); - if (kind == 'x') - response.PutEscapedBytes(buf.data(), byte_count); - else - { - assert(kind == 'm'); - for (size_t i = 0; i < bytes_read; ++i) - response.PutHex8(buf[i]); - } - - return SendPacketNoLock(response.GetData(), response.GetSize()); + if (!m_debugged_process_sp || + (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s failed, no process available", + __FUNCTION__); + return SendErrorResponse(0x15); + } + + // Parse out the memory address. + packet.SetFilePos(strlen("m")); + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse(packet, "Too short m packet"); + + // Read the address. Punting on validation. + // FIXME replace with Hex U64 read with no default value that fails on failed + // read. + const lldb::addr_t read_addr = packet.GetHexMaxU64(false, 0); + + // Validate comma. + if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ',')) + return SendIllFormedResponse(packet, "Comma sep missing in m packet"); + + // Get # bytes to read. + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse(packet, "Length missing in m packet"); + + const uint64_t byte_count = packet.GetHexMaxU64(false, 0); + if (byte_count == 0) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s nothing to read: " + "zero-length packet", + __FUNCTION__); + return SendOKResponse(); + } + + // Allocate the response buffer. + std::string buf(byte_count, '\0'); + if (buf.empty()) + return SendErrorResponse(0x78); + + // Retrieve the process memory. + size_t bytes_read = 0; + Error error = m_debugged_process_sp->ReadMemoryWithoutTrap( + read_addr, &buf[0], byte_count, bytes_read); + if (error.Fail()) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 + " mem 0x%" PRIx64 ": failed to read. Error: %s", + __FUNCTION__, m_debugged_process_sp->GetID(), read_addr, + error.AsCString()); + return SendErrorResponse(0x08); + } + + if (bytes_read == 0) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 + " mem 0x%" PRIx64 ": read 0 of %" PRIu64 " requested bytes", + __FUNCTION__, m_debugged_process_sp->GetID(), read_addr, + byte_count); + return SendErrorResponse(0x08); + } + + StreamGDBRemote response; + packet.SetFilePos(0); + char kind = packet.GetChar('?'); + if (kind == 'x') + response.PutEscapedBytes(buf.data(), byte_count); + else { + assert(kind == 'm'); + for (size_t i = 0; i < bytes_read; ++i) + response.PutHex8(buf[i]); + } + + return SendPacketNoLock(response.GetString()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_M (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__); - return SendErrorResponse (0x15); - } - - // Parse out the memory address. - packet.SetFilePos (strlen("M")); - if (packet.GetBytesLeft() < 1) - return SendIllFormedResponse(packet, "Too short M packet"); - - // Read the address. Punting on validation. - // FIXME replace with Hex U64 read with no default value that fails on failed read. - const lldb::addr_t write_addr = packet.GetHexMaxU64(false, 0); - - // Validate comma. - if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ',')) - return SendIllFormedResponse(packet, "Comma sep missing in M packet"); - - // Get # bytes to read. - if (packet.GetBytesLeft() < 1) - return SendIllFormedResponse(packet, "Length missing in M packet"); +GDBRemoteCommunicationServerLLGS::Handle_M(StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - const uint64_t byte_count = packet.GetHexMaxU64(false, 0); - if (byte_count == 0) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s nothing to write: zero-length packet", __FUNCTION__); - return PacketResult::Success; - } - - // Validate colon. - if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ':')) - return SendIllFormedResponse(packet, "Comma sep missing in M packet after byte length"); - - // Allocate the conversion buffer. - std::vector<uint8_t> buf(byte_count, 0); - if (buf.empty()) - return SendErrorResponse (0x78); - - // Convert the hex memory write contents to bytes. - StreamGDBRemote response; - const uint64_t convert_count = packet.GetHexBytes(&buf[0], byte_count, 0); - if (convert_count != byte_count) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " mem 0x%" PRIx64 ": asked to write %" PRIu64 " bytes, but only found %" PRIu64 " to convert.", __FUNCTION__, m_debugged_process_sp->GetID (), write_addr, byte_count, convert_count); - return SendIllFormedResponse (packet, "M content byte length specified did not match hex-encoded content length"); - } - - // Write the process memory. - size_t bytes_written = 0; - Error error = m_debugged_process_sp->WriteMemory (write_addr, &buf[0], byte_count, bytes_written); - if (error.Fail ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " mem 0x%" PRIx64 ": failed to write. Error: %s", __FUNCTION__, m_debugged_process_sp->GetID (), write_addr, error.AsCString ()); - return SendErrorResponse (0x09); - } - - if (bytes_written == 0) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " mem 0x%" PRIx64 ": wrote 0 of %" PRIu64 " requested bytes", __FUNCTION__, m_debugged_process_sp->GetID (), write_addr, byte_count); - return SendErrorResponse (0x09); - } + if (!m_debugged_process_sp || + (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s failed, no process available", + __FUNCTION__); + return SendErrorResponse(0x15); + } + + // Parse out the memory address. + packet.SetFilePos(strlen("M")); + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse(packet, "Too short M packet"); + + // Read the address. Punting on validation. + // FIXME replace with Hex U64 read with no default value that fails on failed + // read. + const lldb::addr_t write_addr = packet.GetHexMaxU64(false, 0); + + // Validate comma. + if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ',')) + return SendIllFormedResponse(packet, "Comma sep missing in M packet"); + + // Get # bytes to read. + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse(packet, "Length missing in M packet"); + + const uint64_t byte_count = packet.GetHexMaxU64(false, 0); + if (byte_count == 0) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s nothing to write: " + "zero-length packet", + __FUNCTION__); + return PacketResult::Success; + } + + // Validate colon. + if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ':')) + return SendIllFormedResponse( + packet, "Comma sep missing in M packet after byte length"); + + // Allocate the conversion buffer. + std::vector<uint8_t> buf(byte_count, 0); + if (buf.empty()) + return SendErrorResponse(0x78); + + // Convert the hex memory write contents to bytes. + StreamGDBRemote response; + const uint64_t convert_count = packet.GetHexBytes(buf, 0); + if (convert_count != byte_count) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 + " mem 0x%" PRIx64 ": asked to write %" PRIu64 + " bytes, but only found %" PRIu64 " to convert.", + __FUNCTION__, m_debugged_process_sp->GetID(), write_addr, + byte_count, convert_count); + return SendIllFormedResponse(packet, "M content byte length specified did " + "not match hex-encoded content " + "length"); + } + + // Write the process memory. + size_t bytes_written = 0; + Error error = m_debugged_process_sp->WriteMemory(write_addr, &buf[0], + byte_count, bytes_written); + if (error.Fail()) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 + " mem 0x%" PRIx64 ": failed to write. Error: %s", + __FUNCTION__, m_debugged_process_sp->GetID(), write_addr, + error.AsCString()); + return SendErrorResponse(0x09); + } + + if (bytes_written == 0) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 + " mem 0x%" PRIx64 ": wrote 0 of %" PRIu64 " requested bytes", + __FUNCTION__, m_debugged_process_sp->GetID(), write_addr, + byte_count); + return SendErrorResponse(0x09); + } - return SendOKResponse (); + return SendOKResponse(); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfoSupported (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - - // Currently only the NativeProcessProtocol knows if it can handle a qMemoryRegionInfoSupported - // request, but we're not guaranteed to be attached to a process. For now we'll assume the - // client only asks this when a process is being debugged. - - // Ensure we have a process running; otherwise, we can't figure this out - // since we won't have a NativeProcessProtocol. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__); - return SendErrorResponse (0x15); - } +GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfoSupported( + StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + // Currently only the NativeProcessProtocol knows if it can handle a + // qMemoryRegionInfoSupported + // request, but we're not guaranteed to be attached to a process. For now + // we'll assume the + // client only asks this when a process is being debugged. + + // Ensure we have a process running; otherwise, we can't figure this out + // since we won't have a NativeProcessProtocol. + if (!m_debugged_process_sp || + (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s failed, no process available", + __FUNCTION__); + return SendErrorResponse(0x15); + } - // Test if we can get any region back when asking for the region around NULL. - MemoryRegionInfo region_info; - const Error error = m_debugged_process_sp->GetMemoryRegionInfo (0, region_info); - if (error.Fail ()) - { - // We don't support memory region info collection for this NativeProcessProtocol. - return SendUnimplementedResponse (""); - } + // Test if we can get any region back when asking for the region around NULL. + MemoryRegionInfo region_info; + const Error error = + m_debugged_process_sp->GetMemoryRegionInfo(0, region_info); + if (error.Fail()) { + // We don't support memory region info collection for this + // NativeProcessProtocol. + return SendUnimplementedResponse(""); + } - return SendOKResponse(); + return SendOKResponse(); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - - // Ensure we have a process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__); - return SendErrorResponse (0x15); - } - - // Parse out the memory address. - packet.SetFilePos (strlen("qMemoryRegionInfo:")); - if (packet.GetBytesLeft() < 1) - return SendIllFormedResponse(packet, "Too short qMemoryRegionInfo: packet"); - - // Read the address. Punting on validation. - const lldb::addr_t read_addr = packet.GetHexMaxU64(false, 0); +GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo( + StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - StreamGDBRemote response; - - // Get the memory region info for the target address. - MemoryRegionInfo region_info; - const Error error = m_debugged_process_sp->GetMemoryRegionInfo (read_addr, region_info); - if (error.Fail ()) - { - // Return the error message. - - response.PutCString ("error:"); - response.PutCStringAsRawHex8 (error.AsCString ()); - response.PutChar (';'); - } - else - { - // Range start and size. - response.Printf ("start:%" PRIx64 ";size:%" PRIx64 ";", region_info.GetRange ().GetRangeBase (), region_info.GetRange ().GetByteSize ()); - - // Permissions. - if (region_info.GetReadable () || - region_info.GetWritable () || - region_info.GetExecutable ()) - { - // Write permissions info. - response.PutCString ("permissions:"); - - if (region_info.GetReadable ()) - response.PutChar ('r'); - if (region_info.GetWritable ()) - response.PutChar('w'); - if (region_info.GetExecutable()) - response.PutChar ('x'); - - response.PutChar (';'); - } - } - - return SendPacketNoLock(response.GetData(), response.GetSize()); + // Ensure we have a process. + if (!m_debugged_process_sp || + (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s failed, no process available", + __FUNCTION__); + return SendErrorResponse(0x15); + } + + // Parse out the memory address. + packet.SetFilePos(strlen("qMemoryRegionInfo:")); + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse(packet, "Too short qMemoryRegionInfo: packet"); + + // Read the address. Punting on validation. + const lldb::addr_t read_addr = packet.GetHexMaxU64(false, 0); + + StreamGDBRemote response; + + // Get the memory region info for the target address. + MemoryRegionInfo region_info; + const Error error = + m_debugged_process_sp->GetMemoryRegionInfo(read_addr, region_info); + if (error.Fail()) { + // Return the error message. + + response.PutCString("error:"); + response.PutCStringAsRawHex8(error.AsCString()); + response.PutChar(';'); + } else { + // Range start and size. + response.Printf("start:%" PRIx64 ";size:%" PRIx64 ";", + region_info.GetRange().GetRangeBase(), + region_info.GetRange().GetByteSize()); + + // Permissions. + if (region_info.GetReadable() || region_info.GetWritable() || + region_info.GetExecutable()) { + // Write permissions info. + response.PutCString("permissions:"); + + if (region_info.GetReadable()) + response.PutChar('r'); + if (region_info.GetWritable()) + response.PutChar('w'); + if (region_info.GetExecutable()) + response.PutChar('x'); + + response.PutChar(';'); + } + + // Name + ConstString name = region_info.GetName(); + if (name) { + response.PutCString("name:"); + response.PutCStringAsRawHex8(name.AsCString()); + response.PutChar(';'); + } + } + + return SendPacketNoLock(response.GetString()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_Z (StringExtractorGDBRemote &packet) -{ - // Ensure we have a process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - { - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__); - return SendErrorResponse (0x15); - } - - // Parse out software or hardware breakpoint or watchpoint requested. - packet.SetFilePos (strlen("Z")); - if (packet.GetBytesLeft() < 1) - return SendIllFormedResponse(packet, "Too short Z packet, missing software/hardware specifier"); - - bool want_breakpoint = true; - bool want_hardware = false; - uint32_t watch_flags = 0; - - const GDBStoppointType stoppoint_type = - GDBStoppointType(packet.GetS32 (eStoppointInvalid)); - switch (stoppoint_type) - { - case eBreakpointSoftware: - want_hardware = false; want_breakpoint = true; break; - case eBreakpointHardware: - want_hardware = true; want_breakpoint = true; break; - case eWatchpointWrite: - watch_flags = 1; - want_hardware = true; want_breakpoint = false; break; - case eWatchpointRead: - watch_flags = 2; - want_hardware = true; want_breakpoint = false; break; - case eWatchpointReadWrite: - watch_flags = 3; - want_hardware = true; want_breakpoint = false; break; - case eStoppointInvalid: - return SendIllFormedResponse(packet, "Z packet had invalid software/hardware specifier"); - - } - - if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',') - return SendIllFormedResponse(packet, "Malformed Z packet, expecting comma after stoppoint type"); - - // Parse out the stoppoint address. - if (packet.GetBytesLeft() < 1) - return SendIllFormedResponse(packet, "Too short Z packet, missing address"); - const lldb::addr_t addr = packet.GetHexMaxU64(false, 0); - - if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',') - return SendIllFormedResponse(packet, "Malformed Z packet, expecting comma after address"); - - // Parse out the stoppoint size (i.e. size hint for opcode size). - const uint32_t size = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ()); - if (size == std::numeric_limits<uint32_t>::max ()) - return SendIllFormedResponse(packet, "Malformed Z packet, failed to parse size argument"); - - if (want_breakpoint) - { - // Try to set the breakpoint. - const Error error = m_debugged_process_sp->SetBreakpoint (addr, size, want_hardware); - if (error.Success ()) - return SendOKResponse (); - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 - " failed to set breakpoint: %s", - __FUNCTION__, - m_debugged_process_sp->GetID (), - error.AsCString ()); - return SendErrorResponse (0x09); - } - else - { - // Try to set the watchpoint. - const Error error = m_debugged_process_sp->SetWatchpoint ( - addr, size, watch_flags, want_hardware); - if (error.Success ()) - return SendOKResponse (); - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 - " failed to set watchpoint: %s", - __FUNCTION__, - m_debugged_process_sp->GetID (), - error.AsCString ()); - return SendErrorResponse (0x09); - } +GDBRemoteCommunicationServerLLGS::Handle_Z(StringExtractorGDBRemote &packet) { + // Ensure we have a process. + if (!m_debugged_process_sp || + (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s failed, no process available", + __FUNCTION__); + return SendErrorResponse(0x15); + } + + // Parse out software or hardware breakpoint or watchpoint requested. + packet.SetFilePos(strlen("Z")); + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse( + packet, "Too short Z packet, missing software/hardware specifier"); + + bool want_breakpoint = true; + bool want_hardware = false; + uint32_t watch_flags = 0; + + const GDBStoppointType stoppoint_type = + GDBStoppointType(packet.GetS32(eStoppointInvalid)); + switch (stoppoint_type) { + case eBreakpointSoftware: + want_hardware = false; + want_breakpoint = true; + break; + case eBreakpointHardware: + want_hardware = true; + want_breakpoint = true; + break; + case eWatchpointWrite: + watch_flags = 1; + want_hardware = true; + want_breakpoint = false; + break; + case eWatchpointRead: + watch_flags = 2; + want_hardware = true; + want_breakpoint = false; + break; + case eWatchpointReadWrite: + watch_flags = 3; + want_hardware = true; + want_breakpoint = false; + break; + case eStoppointInvalid: + return SendIllFormedResponse( + packet, "Z packet had invalid software/hardware specifier"); + } + + if ((packet.GetBytesLeft() < 1) || packet.GetChar() != ',') + return SendIllFormedResponse( + packet, "Malformed Z packet, expecting comma after stoppoint type"); + + // Parse out the stoppoint address. + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse(packet, "Too short Z packet, missing address"); + const lldb::addr_t addr = packet.GetHexMaxU64(false, 0); + + if ((packet.GetBytesLeft() < 1) || packet.GetChar() != ',') + return SendIllFormedResponse( + packet, "Malformed Z packet, expecting comma after address"); + + // Parse out the stoppoint size (i.e. size hint for opcode size). + const uint32_t size = + packet.GetHexMaxU32(false, std::numeric_limits<uint32_t>::max()); + if (size == std::numeric_limits<uint32_t>::max()) + return SendIllFormedResponse( + packet, "Malformed Z packet, failed to parse size argument"); + + if (want_breakpoint) { + // Try to set the breakpoint. + const Error error = + m_debugged_process_sp->SetBreakpoint(addr, size, want_hardware); + if (error.Success()) + return SendOKResponse(); + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 + " failed to set breakpoint: %s", + __FUNCTION__, m_debugged_process_sp->GetID(), + error.AsCString()); + return SendErrorResponse(0x09); + } else { + // Try to set the watchpoint. + const Error error = m_debugged_process_sp->SetWatchpoint( + addr, size, watch_flags, want_hardware); + if (error.Success()) + return SendOKResponse(); + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 + " failed to set watchpoint: %s", + __FUNCTION__, m_debugged_process_sp->GetID(), + error.AsCString()); + return SendErrorResponse(0x09); + } } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_z (StringExtractorGDBRemote &packet) -{ - // Ensure we have a process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - { - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__); - return SendErrorResponse (0x15); - } - - // Parse out software or hardware breakpoint or watchpoint requested. - packet.SetFilePos (strlen("z")); - if (packet.GetBytesLeft() < 1) - return SendIllFormedResponse(packet, "Too short z packet, missing software/hardware specifier"); - - bool want_breakpoint = true; - - const GDBStoppointType stoppoint_type = - GDBStoppointType(packet.GetS32 (eStoppointInvalid)); - switch (stoppoint_type) - { - case eBreakpointHardware: want_breakpoint = true; break; - case eBreakpointSoftware: want_breakpoint = true; break; - case eWatchpointWrite: want_breakpoint = false; break; - case eWatchpointRead: want_breakpoint = false; break; - case eWatchpointReadWrite: want_breakpoint = false; break; - default: - return SendIllFormedResponse(packet, "z packet had invalid software/hardware specifier"); - - } - - if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',') - return SendIllFormedResponse(packet, "Malformed z packet, expecting comma after stoppoint type"); - - // Parse out the stoppoint address. - if (packet.GetBytesLeft() < 1) - return SendIllFormedResponse(packet, "Too short z packet, missing address"); - const lldb::addr_t addr = packet.GetHexMaxU64(false, 0); - - if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',') - return SendIllFormedResponse(packet, "Malformed z packet, expecting comma after address"); - - /* - // Parse out the stoppoint size (i.e. size hint for opcode size). - const uint32_t size = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ()); - if (size == std::numeric_limits<uint32_t>::max ()) - return SendIllFormedResponse(packet, "Malformed z packet, failed to parse size argument"); - */ - - if (want_breakpoint) - { - // Try to clear the breakpoint. - const Error error = m_debugged_process_sp->RemoveBreakpoint (addr); - if (error.Success ()) - return SendOKResponse (); - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 - " failed to remove breakpoint: %s", - __FUNCTION__, - m_debugged_process_sp->GetID (), - error.AsCString ()); - return SendErrorResponse (0x09); - } - else - { - // Try to clear the watchpoint. - const Error error = m_debugged_process_sp->RemoveWatchpoint (addr); - if (error.Success ()) - return SendOKResponse (); - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 - " failed to remove watchpoint: %s", - __FUNCTION__, - m_debugged_process_sp->GetID (), - error.AsCString ()); - return SendErrorResponse (0x09); - } +GDBRemoteCommunicationServerLLGS::Handle_z(StringExtractorGDBRemote &packet) { + // Ensure we have a process. + if (!m_debugged_process_sp || + (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s failed, no process available", + __FUNCTION__); + return SendErrorResponse(0x15); + } + + // Parse out software or hardware breakpoint or watchpoint requested. + packet.SetFilePos(strlen("z")); + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse( + packet, "Too short z packet, missing software/hardware specifier"); + + bool want_breakpoint = true; + + const GDBStoppointType stoppoint_type = + GDBStoppointType(packet.GetS32(eStoppointInvalid)); + switch (stoppoint_type) { + case eBreakpointHardware: + want_breakpoint = true; + break; + case eBreakpointSoftware: + want_breakpoint = true; + break; + case eWatchpointWrite: + want_breakpoint = false; + break; + case eWatchpointRead: + want_breakpoint = false; + break; + case eWatchpointReadWrite: + want_breakpoint = false; + break; + default: + return SendIllFormedResponse( + packet, "z packet had invalid software/hardware specifier"); + } + + if ((packet.GetBytesLeft() < 1) || packet.GetChar() != ',') + return SendIllFormedResponse( + packet, "Malformed z packet, expecting comma after stoppoint type"); + + // Parse out the stoppoint address. + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse(packet, "Too short z packet, missing address"); + const lldb::addr_t addr = packet.GetHexMaxU64(false, 0); + + if ((packet.GetBytesLeft() < 1) || packet.GetChar() != ',') + return SendIllFormedResponse( + packet, "Malformed z packet, expecting comma after address"); + + /* + // Parse out the stoppoint size (i.e. size hint for opcode size). + const uint32_t size = packet.GetHexMaxU32 (false, + std::numeric_limits<uint32_t>::max ()); + if (size == std::numeric_limits<uint32_t>::max ()) + return SendIllFormedResponse(packet, "Malformed z packet, failed to parse + size argument"); + */ + + if (want_breakpoint) { + // Try to clear the breakpoint. + const Error error = m_debugged_process_sp->RemoveBreakpoint(addr); + if (error.Success()) + return SendOKResponse(); + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 + " failed to remove breakpoint: %s", + __FUNCTION__, m_debugged_process_sp->GetID(), + error.AsCString()); + return SendErrorResponse(0x09); + } else { + // Try to clear the watchpoint. + const Error error = m_debugged_process_sp->RemoveWatchpoint(addr); + if (error.Success()) + return SendOKResponse(); + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 + " failed to remove watchpoint: %s", + __FUNCTION__, m_debugged_process_sp->GetID(), + error.AsCString()); + return SendErrorResponse(0x09); + } } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_s (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_THREAD)); - - // Ensure we have a process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__); - return SendErrorResponse (0x32); - } +GDBRemoteCommunicationServerLLGS::Handle_s(StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); - // We first try to use a continue thread id. If any one or any all set, use the current thread. - // Bail out if we don't have a thread id. - lldb::tid_t tid = GetContinueThreadID (); - if (tid == 0 || tid == LLDB_INVALID_THREAD_ID) - tid = GetCurrentThreadID (); - if (tid == LLDB_INVALID_THREAD_ID) - return SendErrorResponse (0x33); - - // Double check that we have such a thread. - // TODO investigate: on MacOSX we might need to do an UpdateThreads () here. - NativeThreadProtocolSP thread_sp = m_debugged_process_sp->GetThreadByID (tid); - if (!thread_sp || thread_sp->GetID () != tid) - return SendErrorResponse (0x33); - - // Create the step action for the given thread. - ResumeAction action = { tid, eStateStepping, 0 }; - - // Setup the actions list. - ResumeActionList actions; - actions.Append (action); - - // All other threads stop while we're single stepping a thread. - actions.SetDefaultThreadActionIfNeeded(eStateStopped, 0); - Error error = m_debugged_process_sp->Resume (actions); - if (error.Fail ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 " Resume() failed with error: %s", __FUNCTION__, m_debugged_process_sp->GetID (), tid, error.AsCString ()); - return SendErrorResponse(0x49); - } + // Ensure we have a process. + if (!m_debugged_process_sp || + (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s failed, no process available", + __FUNCTION__); + return SendErrorResponse(0x32); + } + + // We first try to use a continue thread id. If any one or any all set, use + // the current thread. + // Bail out if we don't have a thread id. + lldb::tid_t tid = GetContinueThreadID(); + if (tid == 0 || tid == LLDB_INVALID_THREAD_ID) + tid = GetCurrentThreadID(); + if (tid == LLDB_INVALID_THREAD_ID) + return SendErrorResponse(0x33); + + // Double check that we have such a thread. + // TODO investigate: on MacOSX we might need to do an UpdateThreads () here. + NativeThreadProtocolSP thread_sp = m_debugged_process_sp->GetThreadByID(tid); + if (!thread_sp || thread_sp->GetID() != tid) + return SendErrorResponse(0x33); + + // Create the step action for the given thread. + ResumeAction action = {tid, eStateStepping, 0}; + + // Setup the actions list. + ResumeActionList actions; + actions.Append(action); + + // All other threads stop while we're single stepping a thread. + actions.SetDefaultThreadActionIfNeeded(eStateStopped, 0); + Error error = m_debugged_process_sp->Resume(actions); + if (error.Fail()) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 + " tid %" PRIu64 " Resume() failed with error: %s", + __FUNCTION__, m_debugged_process_sp->GetID(), tid, + error.AsCString()); + return SendErrorResponse(0x49); + } - // No response here - the stop or exit will come from the resulting action. - return PacketResult::Success; + // No response here - the stop or exit will come from the resulting action. + return PacketResult::Success; } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_qXfer_auxv_read (StringExtractorGDBRemote &packet) -{ - // *BSD impls should be able to do this too. +GDBRemoteCommunicationServerLLGS::Handle_qXfer_auxv_read( + StringExtractorGDBRemote &packet) { +// *BSD impls should be able to do this too. #if defined(__linux__) - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - - // Parse out the offset. - packet.SetFilePos (strlen("qXfer:auxv:read::")); - if (packet.GetBytesLeft () < 1) - return SendIllFormedResponse (packet, "qXfer:auxv:read:: packet missing offset"); - - const uint64_t auxv_offset = packet.GetHexMaxU64 (false, std::numeric_limits<uint64_t>::max ()); - if (auxv_offset == std::numeric_limits<uint64_t>::max ()) - return SendIllFormedResponse (packet, "qXfer:auxv:read:: packet missing offset"); - - // Parse out comma. - if (packet.GetBytesLeft () < 1 || packet.GetChar () != ',') - return SendIllFormedResponse (packet, "qXfer:auxv:read:: packet missing comma after offset"); - - // Parse out the length. - const uint64_t auxv_length = packet.GetHexMaxU64 (false, std::numeric_limits<uint64_t>::max ()); - if (auxv_length == std::numeric_limits<uint64_t>::max ()) - return SendIllFormedResponse (packet, "qXfer:auxv:read:: packet missing length"); - - // Grab the auxv data if we need it. - if (!m_active_auxv_buffer_sp) - { - // Make sure we have a valid process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__); - return SendErrorResponse (0x10); - } - - // Grab the auxv data. - m_active_auxv_buffer_sp = Host::GetAuxvData (m_debugged_process_sp->GetID ()); - if (!m_active_auxv_buffer_sp || m_active_auxv_buffer_sp->GetByteSize () == 0) - { - // Hmm, no auxv data, call that an error. - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no auxv data retrieved", __FUNCTION__); - m_active_auxv_buffer_sp.reset (); - return SendErrorResponse (0x11); - } - } - - // FIXME find out if/how I lock the stream here. - - StreamGDBRemote response; - bool done_with_buffer = false; - - if (auxv_offset >= m_active_auxv_buffer_sp->GetByteSize ()) - { - // We have nothing left to send. Mark the buffer as complete. - response.PutChar ('l'); - done_with_buffer = true; - } - else - { - // Figure out how many bytes are available starting at the given offset. - const uint64_t bytes_remaining = m_active_auxv_buffer_sp->GetByteSize () - auxv_offset; - - // Figure out how many bytes we're going to read. - const uint64_t bytes_to_read = (auxv_length > bytes_remaining) ? bytes_remaining : auxv_length; - - // Mark the response type according to whether we're reading the remainder of the auxv data. - if (bytes_to_read >= bytes_remaining) - { - // There will be nothing left to read after this - response.PutChar ('l'); - done_with_buffer = true; - } - else - { - // There will still be bytes to read after this request. - response.PutChar ('m'); - } - - // Now write the data in encoded binary form. - response.PutEscapedBytes (m_active_auxv_buffer_sp->GetBytes () + auxv_offset, bytes_to_read); - } - - if (done_with_buffer) - m_active_auxv_buffer_sp.reset (); - - return SendPacketNoLock(response.GetData(), response.GetSize()); + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + // Parse out the offset. + packet.SetFilePos(strlen("qXfer:auxv:read::")); + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse(packet, + "qXfer:auxv:read:: packet missing offset"); + + const uint64_t auxv_offset = + packet.GetHexMaxU64(false, std::numeric_limits<uint64_t>::max()); + if (auxv_offset == std::numeric_limits<uint64_t>::max()) + return SendIllFormedResponse(packet, + "qXfer:auxv:read:: packet missing offset"); + + // Parse out comma. + if (packet.GetBytesLeft() < 1 || packet.GetChar() != ',') + return SendIllFormedResponse( + packet, "qXfer:auxv:read:: packet missing comma after offset"); + + // Parse out the length. + const uint64_t auxv_length = + packet.GetHexMaxU64(false, std::numeric_limits<uint64_t>::max()); + if (auxv_length == std::numeric_limits<uint64_t>::max()) + return SendIllFormedResponse(packet, + "qXfer:auxv:read:: packet missing length"); + + // Grab the auxv data if we need it. + if (!m_active_auxv_buffer_sp) { + // Make sure we have a valid process. + if (!m_debugged_process_sp || + (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s failed, no process available", + __FUNCTION__); + return SendErrorResponse(0x10); + } + + // Grab the auxv data. + m_active_auxv_buffer_sp = Host::GetAuxvData(m_debugged_process_sp->GetID()); + if (!m_active_auxv_buffer_sp || + m_active_auxv_buffer_sp->GetByteSize() == 0) { + // Hmm, no auxv data, call that an error. + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed, no auxv data " + "retrieved", + __FUNCTION__); + m_active_auxv_buffer_sp.reset(); + return SendErrorResponse(0x11); + } + } + + // FIXME find out if/how I lock the stream here. + + StreamGDBRemote response; + bool done_with_buffer = false; + + if (auxv_offset >= m_active_auxv_buffer_sp->GetByteSize()) { + // We have nothing left to send. Mark the buffer as complete. + response.PutChar('l'); + done_with_buffer = true; + } else { + // Figure out how many bytes are available starting at the given offset. + const uint64_t bytes_remaining = + m_active_auxv_buffer_sp->GetByteSize() - auxv_offset; + + // Figure out how many bytes we're going to read. + const uint64_t bytes_to_read = + (auxv_length > bytes_remaining) ? bytes_remaining : auxv_length; + + // Mark the response type according to whether we're reading the remainder + // of the auxv data. + if (bytes_to_read >= bytes_remaining) { + // There will be nothing left to read after this + response.PutChar('l'); + done_with_buffer = true; + } else { + // There will still be bytes to read after this request. + response.PutChar('m'); + } + + // Now write the data in encoded binary form. + response.PutEscapedBytes(m_active_auxv_buffer_sp->GetBytes() + auxv_offset, + bytes_to_read); + } + + if (done_with_buffer) + m_active_auxv_buffer_sp.reset(); + + return SendPacketNoLock(response.GetString()); #else - return SendUnimplementedResponse ("not implemented on this platform"); + return SendUnimplementedResponse("not implemented on this platform"); #endif } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_QSaveRegisterState (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); - - // Move past packet name. - packet.SetFilePos (strlen ("QSaveRegisterState")); - - // Get the thread to use. - NativeThreadProtocolSP thread_sp = GetThreadFromSuffix (packet); - if (!thread_sp) - { - if (m_thread_suffix_supported) - return SendIllFormedResponse (packet, "No thread specified in QSaveRegisterState packet"); - else - return SendIllFormedResponse (packet, "No thread was is set with the Hg packet"); - } - - // Grab the register context for the thread. - NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ()); - if (!reg_context_sp) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 " failed, no register context available for the thread", __FUNCTION__, m_debugged_process_sp->GetID (), thread_sp->GetID ()); - return SendErrorResponse (0x15); - } - - // Save registers to a buffer. - DataBufferSP register_data_sp; - Error error = reg_context_sp->ReadAllRegisterValues (register_data_sp); - if (error.Fail ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " failed to save all register values: %s", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ()); - return SendErrorResponse (0x75); - } - - // Allocate a new save id. - const uint32_t save_id = GetNextSavedRegistersID (); - assert ((m_saved_registers_map.find (save_id) == m_saved_registers_map.end ()) && "GetNextRegisterSaveID() returned an existing register save id"); +GDBRemoteCommunicationServerLLGS::Handle_QSaveRegisterState( + StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + + // Move past packet name. + packet.SetFilePos(strlen("QSaveRegisterState")); + + // Get the thread to use. + NativeThreadProtocolSP thread_sp = GetThreadFromSuffix(packet); + if (!thread_sp) { + if (m_thread_suffix_supported) + return SendIllFormedResponse( + packet, "No thread specified in QSaveRegisterState packet"); + else + return SendIllFormedResponse(packet, + "No thread was is set with the Hg packet"); + } - // Save the register data buffer under the save id. - { - std::lock_guard<std::mutex> guard(m_saved_registers_mutex); - m_saved_registers_map[save_id] = register_data_sp; - } + // Grab the register context for the thread. + NativeRegisterContextSP reg_context_sp(thread_sp->GetRegisterContext()); + if (!reg_context_sp) { + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 + " failed, no register context available for the thread", + __FUNCTION__, m_debugged_process_sp->GetID(), thread_sp->GetID()); + return SendErrorResponse(0x15); + } + + // Save registers to a buffer. + DataBufferSP register_data_sp; + Error error = reg_context_sp->ReadAllRegisterValues(register_data_sp); + if (error.Fail()) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 + " failed to save all register values: %s", + __FUNCTION__, m_debugged_process_sp->GetID(), + error.AsCString()); + return SendErrorResponse(0x75); + } + + // Allocate a new save id. + const uint32_t save_id = GetNextSavedRegistersID(); + assert((m_saved_registers_map.find(save_id) == m_saved_registers_map.end()) && + "GetNextRegisterSaveID() returned an existing register save id"); + + // Save the register data buffer under the save id. + { + std::lock_guard<std::mutex> guard(m_saved_registers_mutex); + m_saved_registers_map[save_id] = register_data_sp; + } - // Write the response. - StreamGDBRemote response; - response.Printf ("%" PRIu32, save_id); - return SendPacketNoLock(response.GetData(), response.GetSize()); + // Write the response. + StreamGDBRemote response; + response.Printf("%" PRIu32, save_id); + return SendPacketNoLock(response.GetString()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_QRestoreRegisterState (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); - - // Parse out save id. - packet.SetFilePos (strlen ("QRestoreRegisterState:")); - if (packet.GetBytesLeft () < 1) - return SendIllFormedResponse (packet, "QRestoreRegisterState packet missing register save id"); - - const uint32_t save_id = packet.GetU32 (0); - if (save_id == 0) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s QRestoreRegisterState packet has malformed save id, expecting decimal uint32_t", __FUNCTION__); - return SendErrorResponse (0x76); - } +GDBRemoteCommunicationServerLLGS::Handle_QRestoreRegisterState( + StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + + // Parse out save id. + packet.SetFilePos(strlen("QRestoreRegisterState:")); + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse( + packet, "QRestoreRegisterState packet missing register save id"); + + const uint32_t save_id = packet.GetU32(0); + if (save_id == 0) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s QRestoreRegisterState " + "packet has malformed save id, expecting decimal uint32_t", + __FUNCTION__); + return SendErrorResponse(0x76); + } + + // Get the thread to use. + NativeThreadProtocolSP thread_sp = GetThreadFromSuffix(packet); + if (!thread_sp) { + if (m_thread_suffix_supported) + return SendIllFormedResponse( + packet, "No thread specified in QRestoreRegisterState packet"); + else + return SendIllFormedResponse(packet, + "No thread was is set with the Hg packet"); + } - // Get the thread to use. - NativeThreadProtocolSP thread_sp = GetThreadFromSuffix (packet); - if (!thread_sp) - { - if (m_thread_suffix_supported) - return SendIllFormedResponse (packet, "No thread specified in QRestoreRegisterState packet"); - else - return SendIllFormedResponse (packet, "No thread was is set with the Hg packet"); - } + // Grab the register context for the thread. + NativeRegisterContextSP reg_context_sp(thread_sp->GetRegisterContext()); + if (!reg_context_sp) { + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 + " failed, no register context available for the thread", + __FUNCTION__, m_debugged_process_sp->GetID(), thread_sp->GetID()); + return SendErrorResponse(0x15); + } + + // Retrieve register state buffer, then remove from the list. + DataBufferSP register_data_sp; + { + std::lock_guard<std::mutex> guard(m_saved_registers_mutex); - // Grab the register context for the thread. - NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ()); - if (!reg_context_sp) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 " failed, no register context available for the thread", __FUNCTION__, m_debugged_process_sp->GetID (), thread_sp->GetID ()); - return SendErrorResponse (0x15); + // Find the register set buffer for the given save id. + auto it = m_saved_registers_map.find(save_id); + if (it == m_saved_registers_map.end()) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 + " does not have a register set save buffer for id %" PRIu32, + __FUNCTION__, m_debugged_process_sp->GetID(), save_id); + return SendErrorResponse(0x77); } + register_data_sp = it->second; - // Retrieve register state buffer, then remove from the list. - DataBufferSP register_data_sp; - { - std::lock_guard<std::mutex> guard(m_saved_registers_mutex); - - // Find the register set buffer for the given save id. - auto it = m_saved_registers_map.find (save_id); - if (it == m_saved_registers_map.end ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " does not have a register set save buffer for id %" PRIu32, __FUNCTION__, m_debugged_process_sp->GetID (), save_id); - return SendErrorResponse (0x77); - } - register_data_sp = it->second; - - // Remove it from the map. - m_saved_registers_map.erase (it); - } + // Remove it from the map. + m_saved_registers_map.erase(it); + } - Error error = reg_context_sp->WriteAllRegisterValues (register_data_sp); - if (error.Fail ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " failed to restore all register values: %s", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ()); - return SendErrorResponse (0x77); - } + Error error = reg_context_sp->WriteAllRegisterValues(register_data_sp); + if (error.Fail()) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 + " failed to restore all register values: %s", + __FUNCTION__, m_debugged_process_sp->GetID(), + error.AsCString()); + return SendErrorResponse(0x77); + } - return SendOKResponse(); + return SendOKResponse(); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_vAttach (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - - // Consume the ';' after vAttach. - packet.SetFilePos (strlen ("vAttach")); - if (!packet.GetBytesLeft () || packet.GetChar () != ';') - return SendIllFormedResponse (packet, "vAttach missing expected ';'"); - - // Grab the PID to which we will attach (assume hex encoding). - lldb::pid_t pid = packet.GetU32 (LLDB_INVALID_PROCESS_ID, 16); - if (pid == LLDB_INVALID_PROCESS_ID) - return SendIllFormedResponse (packet, "vAttach failed to parse the process id"); - - // Attempt to attach. +GDBRemoteCommunicationServerLLGS::Handle_vAttach( + StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + // Consume the ';' after vAttach. + packet.SetFilePos(strlen("vAttach")); + if (!packet.GetBytesLeft() || packet.GetChar() != ';') + return SendIllFormedResponse(packet, "vAttach missing expected ';'"); + + // Grab the PID to which we will attach (assume hex encoding). + lldb::pid_t pid = packet.GetU32(LLDB_INVALID_PROCESS_ID, 16); + if (pid == LLDB_INVALID_PROCESS_ID) + return SendIllFormedResponse(packet, + "vAttach failed to parse the process id"); + + // Attempt to attach. + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s attempting to attach to " + "pid %" PRIu64, + __FUNCTION__, pid); + + Error error = AttachToProcess(pid); + + if (error.Fail()) { if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s attempting to attach to pid %" PRIu64, __FUNCTION__, pid); + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed to attach to " + "pid %" PRIu64 ": %s\n", + __FUNCTION__, pid, error.AsCString()); + return SendErrorResponse(0x01); + } - Error error = AttachToProcess (pid); - - if (error.Fail ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to attach to pid %" PRIu64 ": %s\n", __FUNCTION__, pid, error.AsCString()); - return SendErrorResponse (0x01); - } - - // Notify we attached by sending a stop packet. - return SendStopReasonForState (m_debugged_process_sp->GetState ()); + // Notify we attached by sending a stop packet. + return SendStopReasonForState(m_debugged_process_sp->GetState()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_D (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS)); +GDBRemoteCommunicationServerLLGS::Handle_D(StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - StopSTDIOForwarding(); + StopSTDIOForwarding(); - // Fail if we don't have a current process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__); - return SendErrorResponse (0x15); - } - - lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; - - // Consume the ';' after D. - packet.SetFilePos (1); - if (packet.GetBytesLeft ()) - { - if (packet.GetChar () != ';') - return SendIllFormedResponse (packet, "D missing expected ';'"); - - // Grab the PID from which we will detach (assume hex encoding). - pid = packet.GetU32 (LLDB_INVALID_PROCESS_ID, 16); - if (pid == LLDB_INVALID_PROCESS_ID) - return SendIllFormedResponse (packet, "D failed to parse the process id"); - } + // Fail if we don't have a current process. + if (!m_debugged_process_sp || + (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (log) + log->Printf( + "GDBRemoteCommunicationServerLLGS::%s failed, no process available", + __FUNCTION__); + return SendErrorResponse(0x15); + } + + lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; + + // Consume the ';' after D. + packet.SetFilePos(1); + if (packet.GetBytesLeft()) { + if (packet.GetChar() != ';') + return SendIllFormedResponse(packet, "D missing expected ';'"); + + // Grab the PID from which we will detach (assume hex encoding). + pid = packet.GetU32(LLDB_INVALID_PROCESS_ID, 16); + if (pid == LLDB_INVALID_PROCESS_ID) + return SendIllFormedResponse(packet, "D failed to parse the process id"); + } - if (pid != LLDB_INVALID_PROCESS_ID && - m_debugged_process_sp->GetID () != pid) - { - return SendIllFormedResponse (packet, "Invalid pid"); - } + if (pid != LLDB_INVALID_PROCESS_ID && m_debugged_process_sp->GetID() != pid) { + return SendIllFormedResponse(packet, "Invalid pid"); + } - const Error error = m_debugged_process_sp->Detach (); - if (error.Fail ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to detach from pid %" PRIu64 ": %s\n", - __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ()); - return SendErrorResponse (0x01); - } + const Error error = m_debugged_process_sp->Detach(); + if (error.Fail()) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed to detach from " + "pid %" PRIu64 ": %s\n", + __FUNCTION__, m_debugged_process_sp->GetID(), + error.AsCString()); + return SendErrorResponse(0x01); + } - return SendOKResponse (); + return SendOKResponse(); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_qThreadStopInfo (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); - - packet.SetFilePos (strlen("qThreadStopInfo")); - const lldb::tid_t tid = packet.GetHexMaxU32 (false, LLDB_INVALID_THREAD_ID); - if (tid == LLDB_INVALID_THREAD_ID) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, could not parse thread id from request \"%s\"", __FUNCTION__, packet.GetStringRef ().c_str ()); - return SendErrorResponse (0x15); - } - return SendStopReplyPacketForThread (tid); +GDBRemoteCommunicationServerLLGS::Handle_qThreadStopInfo( + StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + + packet.SetFilePos(strlen("qThreadStopInfo")); + const lldb::tid_t tid = packet.GetHexMaxU32(false, LLDB_INVALID_THREAD_ID); + if (tid == LLDB_INVALID_THREAD_ID) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed, could not " + "parse thread id from request \"%s\"", + __FUNCTION__, packet.GetStringRef().c_str()); + return SendErrorResponse(0x15); + } + return SendStopReplyPacketForThread(tid); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_jThreadsInfo (StringExtractorGDBRemote &) -{ - Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); - - // Ensure we have a debugged process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - return SendErrorResponse (50); - - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s preparing packet for pid %" PRIu64, +GDBRemoteCommunicationServerLLGS::Handle_jThreadsInfo( + StringExtractorGDBRemote &) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); + + // Ensure we have a debugged process. + if (!m_debugged_process_sp || + (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) + return SendErrorResponse(50); + + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s preparing packet for pid " + "%" PRIu64, __FUNCTION__, m_debugged_process_sp->GetID()); + StreamString response; + const bool threads_with_valid_stop_info_only = false; + JSONArray::SP threads_array_sp = GetJSONThreadsInfo( + *m_debugged_process_sp, threads_with_valid_stop_info_only); + if (!threads_array_sp) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s failed to prepare a " + "packet for pid %" PRIu64, + __FUNCTION__, m_debugged_process_sp->GetID()); + return SendErrorResponse(52); + } - StreamString response; - const bool threads_with_valid_stop_info_only = false; - JSONArray::SP threads_array_sp = GetJSONThreadsInfo(*m_debugged_process_sp, - threads_with_valid_stop_info_only); - if (! threads_array_sp) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to prepare a packet for pid %" PRIu64, - __FUNCTION__, m_debugged_process_sp->GetID()); - return SendErrorResponse(52); - } - - threads_array_sp->Write(response); - StreamGDBRemote escaped_response; - escaped_response.PutEscapedBytes(response.GetData(), response.GetSize()); - return SendPacketNoLock (escaped_response.GetData(), escaped_response.GetSize()); + threads_array_sp->Write(response); + StreamGDBRemote escaped_response; + escaped_response.PutEscapedBytes(response.GetData(), response.GetSize()); + return SendPacketNoLock(escaped_response.GetString()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_qWatchpointSupportInfo (StringExtractorGDBRemote &packet) -{ - // Fail if we don't have a current process. - if (!m_debugged_process_sp || - m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID) - return SendErrorResponse (68); - - packet.SetFilePos(strlen("qWatchpointSupportInfo")); - if (packet.GetBytesLeft() == 0) - return SendOKResponse(); - if (packet.GetChar() != ':') - return SendErrorResponse(67); +GDBRemoteCommunicationServerLLGS::Handle_qWatchpointSupportInfo( + StringExtractorGDBRemote &packet) { + // Fail if we don't have a current process. + if (!m_debugged_process_sp || + m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID) + return SendErrorResponse(68); + + packet.SetFilePos(strlen("qWatchpointSupportInfo")); + if (packet.GetBytesLeft() == 0) + return SendOKResponse(); + if (packet.GetChar() != ':') + return SendErrorResponse(67); - uint32_t num = m_debugged_process_sp->GetMaxWatchpoints(); - StreamGDBRemote response; - response.Printf ("num:%d;", num); - return SendPacketNoLock(response.GetData(), response.GetSize()); + uint32_t num = m_debugged_process_sp->GetMaxWatchpoints(); + StreamGDBRemote response; + response.Printf("num:%d;", num); + return SendPacketNoLock(response.GetString()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_qFileLoadAddress (StringExtractorGDBRemote &packet) -{ - // Fail if we don't have a current process. - if (!m_debugged_process_sp || - m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID) - return SendErrorResponse(67); +GDBRemoteCommunicationServerLLGS::Handle_qFileLoadAddress( + StringExtractorGDBRemote &packet) { + // Fail if we don't have a current process. + if (!m_debugged_process_sp || + m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID) + return SendErrorResponse(67); - packet.SetFilePos(strlen("qFileLoadAddress:")); - if (packet.GetBytesLeft() == 0) - return SendErrorResponse(68); + packet.SetFilePos(strlen("qFileLoadAddress:")); + if (packet.GetBytesLeft() == 0) + return SendErrorResponse(68); - std::string file_name; - packet.GetHexByteString(file_name); + std::string file_name; + packet.GetHexByteString(file_name); - lldb::addr_t file_load_address = LLDB_INVALID_ADDRESS; - Error error = m_debugged_process_sp->GetFileLoadAddress(file_name, file_load_address); - if (error.Fail()) - return SendErrorResponse(69); + lldb::addr_t file_load_address = LLDB_INVALID_ADDRESS; + Error error = + m_debugged_process_sp->GetFileLoadAddress(file_name, file_load_address); + if (error.Fail()) + return SendErrorResponse(69); - if (file_load_address == LLDB_INVALID_ADDRESS) - return SendErrorResponse(1); // File not loaded + if (file_load_address == LLDB_INVALID_ADDRESS) + return SendErrorResponse(1); // File not loaded - StreamGDBRemote response; - response.PutHex64(file_load_address); - return SendPacketNoLock(response.GetData(), response.GetSize()); -} - -void -GDBRemoteCommunicationServerLLGS::MaybeCloseInferiorTerminalConnection () -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - - // Tell the stdio connection to shut down. - if (m_stdio_communication.IsConnected()) - { - auto connection = m_stdio_communication.GetConnection(); - if (connection) - { - Error error; - connection->Disconnect (&error); - - if (error.Success ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s disconnect process terminal stdio - SUCCESS", __FUNCTION__); - } - else - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s disconnect process terminal stdio - FAIL: %s", __FUNCTION__, error.AsCString ()); - } - } - } + StreamGDBRemote response; + response.PutHex64(file_load_address); + return SendPacketNoLock(response.GetString()); } +void GDBRemoteCommunicationServerLLGS::MaybeCloseInferiorTerminalConnection() { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); -NativeThreadProtocolSP -GDBRemoteCommunicationServerLLGS::GetThreadFromSuffix (StringExtractorGDBRemote &packet) -{ - NativeThreadProtocolSP thread_sp; + // Tell the stdio connection to shut down. + if (m_stdio_communication.IsConnected()) { + auto connection = m_stdio_communication.GetConnection(); + if (connection) { + Error error; + connection->Disconnect(&error); - // We have no thread if we don't have a process. - if (!m_debugged_process_sp || m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID) - return thread_sp; - - // If the client hasn't asked for thread suffix support, there will not be a thread suffix. - // Use the current thread in that case. - if (!m_thread_suffix_supported) - { - const lldb::tid_t current_tid = GetCurrentThreadID (); - if (current_tid == LLDB_INVALID_THREAD_ID) - return thread_sp; - else if (current_tid == 0) - { - // Pick a thread. - return m_debugged_process_sp->GetThreadAtIndex (0); - } - else - return m_debugged_process_sp->GetThreadByID (current_tid); + if (error.Success()) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s disconnect process " + "terminal stdio - SUCCESS", + __FUNCTION__); + } else { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s disconnect process " + "terminal stdio - FAIL: %s", + __FUNCTION__, error.AsCString()); + } } + } +} - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); +NativeThreadProtocolSP GDBRemoteCommunicationServerLLGS::GetThreadFromSuffix( + StringExtractorGDBRemote &packet) { + NativeThreadProtocolSP thread_sp; - // Parse out the ';'. - if (packet.GetBytesLeft () < 1 || packet.GetChar () != ';') - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s gdb-remote parse error: expected ';' prior to start of thread suffix: packet contents = '%s'", __FUNCTION__, packet.GetStringRef ().c_str ()); - return thread_sp; - } + // We have no thread if we don't have a process. + if (!m_debugged_process_sp || + m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID) + return thread_sp; - if (!packet.GetBytesLeft ()) - return thread_sp; + // If the client hasn't asked for thread suffix support, there will not be a + // thread suffix. + // Use the current thread in that case. + if (!m_thread_suffix_supported) { + const lldb::tid_t current_tid = GetCurrentThreadID(); + if (current_tid == LLDB_INVALID_THREAD_ID) + return thread_sp; + else if (current_tid == 0) { + // Pick a thread. + return m_debugged_process_sp->GetThreadAtIndex(0); + } else + return m_debugged_process_sp->GetThreadByID(current_tid); + } + + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + + // Parse out the ';'. + if (packet.GetBytesLeft() < 1 || packet.GetChar() != ';') { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s gdb-remote parse " + "error: expected ';' prior to start of thread suffix: packet " + "contents = '%s'", + __FUNCTION__, packet.GetStringRef().c_str()); + return thread_sp; + } - // Parse out thread: portion. - if (strncmp (packet.Peek (), "thread:", strlen("thread:")) != 0) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s gdb-remote parse error: expected 'thread:' but not found, packet contents = '%s'", __FUNCTION__, packet.GetStringRef ().c_str ()); - return thread_sp; - } - packet.SetFilePos (packet.GetFilePos () + strlen("thread:")); - const lldb::tid_t tid = packet.GetHexMaxU64(false, 0); - if (tid != 0) - return m_debugged_process_sp->GetThreadByID (tid); + if (!packet.GetBytesLeft()) + return thread_sp; + // Parse out thread: portion. + if (strncmp(packet.Peek(), "thread:", strlen("thread:")) != 0) { + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s gdb-remote parse " + "error: expected 'thread:' but not found, packet contents = " + "'%s'", + __FUNCTION__, packet.GetStringRef().c_str()); return thread_sp; + } + packet.SetFilePos(packet.GetFilePos() + strlen("thread:")); + const lldb::tid_t tid = packet.GetHexMaxU64(false, 0); + if (tid != 0) + return m_debugged_process_sp->GetThreadByID(tid); + + return thread_sp; } -lldb::tid_t -GDBRemoteCommunicationServerLLGS::GetCurrentThreadID () const -{ - if (m_current_tid == 0 || m_current_tid == LLDB_INVALID_THREAD_ID) - { - // Use whatever the debug process says is the current thread id - // since the protocol either didn't specify or specified we want - // any/all threads marked as the current thread. - if (!m_debugged_process_sp) - return LLDB_INVALID_THREAD_ID; - return m_debugged_process_sp->GetCurrentThreadID (); - } - // Use the specific current thread id set by the gdb remote protocol. - return m_current_tid; +lldb::tid_t GDBRemoteCommunicationServerLLGS::GetCurrentThreadID() const { + if (m_current_tid == 0 || m_current_tid == LLDB_INVALID_THREAD_ID) { + // Use whatever the debug process says is the current thread id + // since the protocol either didn't specify or specified we want + // any/all threads marked as the current thread. + if (!m_debugged_process_sp) + return LLDB_INVALID_THREAD_ID; + return m_debugged_process_sp->GetCurrentThreadID(); + } + // Use the specific current thread id set by the gdb remote protocol. + return m_current_tid; } -uint32_t -GDBRemoteCommunicationServerLLGS::GetNextSavedRegistersID () -{ - std::lock_guard<std::mutex> guard(m_saved_registers_mutex); - return m_next_saved_registers_id++; +uint32_t GDBRemoteCommunicationServerLLGS::GetNextSavedRegistersID() { + std::lock_guard<std::mutex> guard(m_saved_registers_mutex); + return m_next_saved_registers_id++; } -void -GDBRemoteCommunicationServerLLGS::ClearProcessSpecificData () -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|GDBR_LOG_PROCESS)); - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s()", __FUNCTION__); +void GDBRemoteCommunicationServerLLGS::ClearProcessSpecificData() { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | GDBR_LOG_PROCESS)); + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s()", __FUNCTION__); - // Clear any auxv cached data. - // *BSD impls should be able to do this too. +// Clear any auxv cached data. +// *BSD impls should be able to do this too. #if defined(__linux__) - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s clearing auxv buffer (previously %s)", - __FUNCTION__, - m_active_auxv_buffer_sp ? "was set" : "was not set"); - m_active_auxv_buffer_sp.reset (); + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s clearing auxv buffer " + "(previously %s)", + __FUNCTION__, + m_active_auxv_buffer_sp ? "was set" : "was not set"); + m_active_auxv_buffer_sp.reset(); #endif } FileSpec -GDBRemoteCommunicationServerLLGS::FindModuleFile(const std::string& module_path, - const ArchSpec& arch) -{ - if (m_debugged_process_sp) - { - FileSpec file_spec; - if (m_debugged_process_sp->GetLoadedModuleFileSpec(module_path.c_str(), file_spec).Success()) - { - if (file_spec.Exists()) - return file_spec; - } - } - - return GDBRemoteCommunicationServerCommon::FindModuleFile(module_path, arch); +GDBRemoteCommunicationServerLLGS::FindModuleFile(const std::string &module_path, + const ArchSpec &arch) { + if (m_debugged_process_sp) { + FileSpec file_spec; + if (m_debugged_process_sp + ->GetLoadedModuleFileSpec(module_path.c_str(), file_spec) + .Success()) { + if (file_spec.Exists()) + return file_spec; + } + } + + return GDBRemoteCommunicationServerCommon::FindModuleFile(module_path, arch); } diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h index caf6eb3..fa52cda 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h @@ -16,10 +16,10 @@ #include <unordered_map> // Other libraries and framework includes -#include "lldb/lldb-private-forward.h" #include "lldb/Core/Communication.h" -#include "lldb/Host/common/NativeProcessProtocol.h" #include "lldb/Host/MainLoop.h" +#include "lldb/Host/common/NativeProcessProtocol.h" +#include "lldb/lldb-private-forward.h" // Project includes #include "GDBRemoteCommunicationServerCommon.h" @@ -32,282 +32,220 @@ namespace process_gdb_remote { class ProcessGDBRemote; -class GDBRemoteCommunicationServerLLGS : - public GDBRemoteCommunicationServerCommon, - public NativeProcessProtocol::NativeDelegate -{ +class GDBRemoteCommunicationServerLLGS + : public GDBRemoteCommunicationServerCommon, + public NativeProcessProtocol::NativeDelegate { public: - //------------------------------------------------------------------ - // Constructors and Destructors - //------------------------------------------------------------------ - GDBRemoteCommunicationServerLLGS(MainLoop &mainloop); - - //------------------------------------------------------------------ - /// Specify the program to launch and its arguments. - /// - /// @param[in] args - /// The command line to launch. - /// - /// @param[in] argc - /// The number of elements in the args array of cstring pointers. - /// - /// @return - /// An Error object indicating the success or failure of making - /// the setting. - //------------------------------------------------------------------ - Error - SetLaunchArguments (const char *const args[], int argc); - - //------------------------------------------------------------------ - /// Specify the launch flags for the process. - /// - /// @param[in] launch_flags - /// The launch flags to use when launching this process. - /// - /// @return - /// An Error object indicating the success or failure of making - /// the setting. - //------------------------------------------------------------------ - Error - SetLaunchFlags (unsigned int launch_flags); - - //------------------------------------------------------------------ - /// Launch a process with the current launch settings. - /// - /// This method supports running an lldb-gdbserver or similar - /// server in a situation where the startup code has been provided - /// with all the information for a child process to be launched. - /// - /// @return - /// An Error object indicating the success or failure of the - /// launch. - //------------------------------------------------------------------ - Error - LaunchProcess () override; - - //------------------------------------------------------------------ - /// Attach to a process. - /// - /// This method supports attaching llgs to a process accessible via the - /// configured Platform. - /// - /// @return - /// An Error object indicating the success or failure of the - /// attach operation. - //------------------------------------------------------------------ - Error - AttachToProcess (lldb::pid_t pid); - - //------------------------------------------------------------------ - // NativeProcessProtocol::NativeDelegate overrides - //------------------------------------------------------------------ - void - InitializeDelegate (NativeProcessProtocol *process) override; - - void - ProcessStateChanged (NativeProcessProtocol *process, lldb::StateType state) override; - - void - DidExec (NativeProcessProtocol *process) override; - - Error - InitializeConnection (std::unique_ptr<Connection> &&connection); + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + GDBRemoteCommunicationServerLLGS(MainLoop &mainloop); + + //------------------------------------------------------------------ + /// Specify the program to launch and its arguments. + /// + /// @param[in] args + /// The command line to launch. + /// + /// @param[in] argc + /// The number of elements in the args array of cstring pointers. + /// + /// @return + /// An Error object indicating the success or failure of making + /// the setting. + //------------------------------------------------------------------ + Error SetLaunchArguments(const char *const args[], int argc); + + //------------------------------------------------------------------ + /// Specify the launch flags for the process. + /// + /// @param[in] launch_flags + /// The launch flags to use when launching this process. + /// + /// @return + /// An Error object indicating the success or failure of making + /// the setting. + //------------------------------------------------------------------ + Error SetLaunchFlags(unsigned int launch_flags); + + //------------------------------------------------------------------ + /// Launch a process with the current launch settings. + /// + /// This method supports running an lldb-gdbserver or similar + /// server in a situation where the startup code has been provided + /// with all the information for a child process to be launched. + /// + /// @return + /// An Error object indicating the success or failure of the + /// launch. + //------------------------------------------------------------------ + Error LaunchProcess() override; + + //------------------------------------------------------------------ + /// Attach to a process. + /// + /// This method supports attaching llgs to a process accessible via the + /// configured Platform. + /// + /// @return + /// An Error object indicating the success or failure of the + /// attach operation. + //------------------------------------------------------------------ + Error AttachToProcess(lldb::pid_t pid); + + //------------------------------------------------------------------ + // NativeProcessProtocol::NativeDelegate overrides + //------------------------------------------------------------------ + void InitializeDelegate(NativeProcessProtocol *process) override; + + void ProcessStateChanged(NativeProcessProtocol *process, + lldb::StateType state) override; + + void DidExec(NativeProcessProtocol *process) override; + + Error InitializeConnection(std::unique_ptr<Connection> &&connection); protected: - MainLoop &m_mainloop; - MainLoop::ReadHandleUP m_network_handle_up; - lldb::tid_t m_current_tid; - lldb::tid_t m_continue_tid; - std::recursive_mutex m_debugged_process_mutex; - NativeProcessProtocolSP m_debugged_process_sp; + MainLoop &m_mainloop; + MainLoop::ReadHandleUP m_network_handle_up; + lldb::tid_t m_current_tid; + lldb::tid_t m_continue_tid; + std::recursive_mutex m_debugged_process_mutex; + NativeProcessProtocolSP m_debugged_process_sp; - Communication m_stdio_communication; - MainLoop::ReadHandleUP m_stdio_handle_up; + Communication m_stdio_communication; + MainLoop::ReadHandleUP m_stdio_handle_up; - lldb::StateType m_inferior_prev_state; - lldb::DataBufferSP m_active_auxv_buffer_sp; - std::mutex m_saved_registers_mutex; - std::unordered_map<uint32_t, lldb::DataBufferSP> m_saved_registers_map; - uint32_t m_next_saved_registers_id; - bool m_handshake_completed : 1; + lldb::StateType m_inferior_prev_state; + lldb::DataBufferSP m_active_auxv_buffer_sp; + std::mutex m_saved_registers_mutex; + std::unordered_map<uint32_t, lldb::DataBufferSP> m_saved_registers_map; + uint32_t m_next_saved_registers_id; + bool m_handshake_completed : 1; - PacketResult - SendONotification (const char *buffer, uint32_t len); + PacketResult SendONotification(const char *buffer, uint32_t len); - PacketResult - SendWResponse (NativeProcessProtocol *process); + PacketResult SendWResponse(NativeProcessProtocol *process); - PacketResult - SendStopReplyPacketForThread (lldb::tid_t tid); + PacketResult SendStopReplyPacketForThread(lldb::tid_t tid); - PacketResult - SendStopReasonForState (lldb::StateType process_state); + PacketResult SendStopReasonForState(lldb::StateType process_state); - PacketResult - Handle_k (StringExtractorGDBRemote &packet); + PacketResult Handle_k(StringExtractorGDBRemote &packet); - PacketResult - Handle_qProcessInfo (StringExtractorGDBRemote &packet); + PacketResult Handle_qProcessInfo(StringExtractorGDBRemote &packet); - PacketResult - Handle_qC (StringExtractorGDBRemote &packet); + PacketResult Handle_qC(StringExtractorGDBRemote &packet); - PacketResult - Handle_QSetDisableASLR (StringExtractorGDBRemote &packet); + PacketResult Handle_QSetDisableASLR(StringExtractorGDBRemote &packet); - PacketResult - Handle_QSetWorkingDir (StringExtractorGDBRemote &packet); + PacketResult Handle_QSetWorkingDir(StringExtractorGDBRemote &packet); - PacketResult - Handle_qGetWorkingDir (StringExtractorGDBRemote &packet); + PacketResult Handle_qGetWorkingDir(StringExtractorGDBRemote &packet); - PacketResult - Handle_C (StringExtractorGDBRemote &packet); + PacketResult Handle_C(StringExtractorGDBRemote &packet); - PacketResult - Handle_c (StringExtractorGDBRemote &packet); + PacketResult Handle_c(StringExtractorGDBRemote &packet); - PacketResult - Handle_vCont (StringExtractorGDBRemote &packet); + PacketResult Handle_vCont(StringExtractorGDBRemote &packet); - PacketResult - Handle_vCont_actions (StringExtractorGDBRemote &packet); + PacketResult Handle_vCont_actions(StringExtractorGDBRemote &packet); - PacketResult - Handle_stop_reason (StringExtractorGDBRemote &packet); + PacketResult Handle_stop_reason(StringExtractorGDBRemote &packet); - PacketResult - Handle_qRegisterInfo (StringExtractorGDBRemote &packet); + PacketResult Handle_qRegisterInfo(StringExtractorGDBRemote &packet); - PacketResult - Handle_qfThreadInfo (StringExtractorGDBRemote &packet); + PacketResult Handle_qfThreadInfo(StringExtractorGDBRemote &packet); - PacketResult - Handle_qsThreadInfo (StringExtractorGDBRemote &packet); + PacketResult Handle_qsThreadInfo(StringExtractorGDBRemote &packet); - PacketResult - Handle_p (StringExtractorGDBRemote &packet); + PacketResult Handle_p(StringExtractorGDBRemote &packet); - PacketResult - Handle_P (StringExtractorGDBRemote &packet); + PacketResult Handle_P(StringExtractorGDBRemote &packet); - PacketResult - Handle_H (StringExtractorGDBRemote &packet); + PacketResult Handle_H(StringExtractorGDBRemote &packet); - PacketResult - Handle_I (StringExtractorGDBRemote &packet); + PacketResult Handle_I(StringExtractorGDBRemote &packet); - PacketResult - Handle_interrupt (StringExtractorGDBRemote &packet); + PacketResult Handle_interrupt(StringExtractorGDBRemote &packet); - // Handles $m and $x packets. - PacketResult - Handle_memory_read (StringExtractorGDBRemote &packet); + // Handles $m and $x packets. + PacketResult Handle_memory_read(StringExtractorGDBRemote &packet); - PacketResult - Handle_M (StringExtractorGDBRemote &packet); + PacketResult Handle_M(StringExtractorGDBRemote &packet); - PacketResult - Handle_qMemoryRegionInfoSupported (StringExtractorGDBRemote &packet); + PacketResult + Handle_qMemoryRegionInfoSupported(StringExtractorGDBRemote &packet); - PacketResult - Handle_qMemoryRegionInfo (StringExtractorGDBRemote &packet); + PacketResult Handle_qMemoryRegionInfo(StringExtractorGDBRemote &packet); - PacketResult - Handle_Z (StringExtractorGDBRemote &packet); + PacketResult Handle_Z(StringExtractorGDBRemote &packet); - PacketResult - Handle_z (StringExtractorGDBRemote &packet); + PacketResult Handle_z(StringExtractorGDBRemote &packet); - PacketResult - Handle_s (StringExtractorGDBRemote &packet); + PacketResult Handle_s(StringExtractorGDBRemote &packet); - PacketResult - Handle_qXfer_auxv_read (StringExtractorGDBRemote &packet); + PacketResult Handle_qXfer_auxv_read(StringExtractorGDBRemote &packet); - PacketResult - Handle_QSaveRegisterState (StringExtractorGDBRemote &packet); + PacketResult Handle_QSaveRegisterState(StringExtractorGDBRemote &packet); - PacketResult - Handle_QRestoreRegisterState (StringExtractorGDBRemote &packet); + PacketResult Handle_QRestoreRegisterState(StringExtractorGDBRemote &packet); - PacketResult - Handle_vAttach (StringExtractorGDBRemote &packet); + PacketResult Handle_vAttach(StringExtractorGDBRemote &packet); - PacketResult - Handle_D (StringExtractorGDBRemote &packet); + PacketResult Handle_D(StringExtractorGDBRemote &packet); - PacketResult - Handle_qThreadStopInfo (StringExtractorGDBRemote &packet); + PacketResult Handle_qThreadStopInfo(StringExtractorGDBRemote &packet); - PacketResult - Handle_jThreadsInfo (StringExtractorGDBRemote &packet); + PacketResult Handle_jThreadsInfo(StringExtractorGDBRemote &packet); - PacketResult - Handle_qWatchpointSupportInfo (StringExtractorGDBRemote &packet); + PacketResult Handle_qWatchpointSupportInfo(StringExtractorGDBRemote &packet); - PacketResult - Handle_qFileLoadAddress (StringExtractorGDBRemote &packet); + PacketResult Handle_qFileLoadAddress(StringExtractorGDBRemote &packet); - void - SetCurrentThreadID (lldb::tid_t tid); + void SetCurrentThreadID(lldb::tid_t tid); - lldb::tid_t - GetCurrentThreadID () const; + lldb::tid_t GetCurrentThreadID() const; - void - SetContinueThreadID (lldb::tid_t tid); + void SetContinueThreadID(lldb::tid_t tid); - lldb::tid_t - GetContinueThreadID () const { return m_continue_tid; } + lldb::tid_t GetContinueThreadID() const { return m_continue_tid; } - Error - SetSTDIOFileDescriptor (int fd); + Error SetSTDIOFileDescriptor(int fd); - FileSpec - FindModuleFile (const std::string& module_path, const ArchSpec& arch) override; + FileSpec FindModuleFile(const std::string &module_path, + const ArchSpec &arch) override; private: - void - HandleInferiorState_Exited (NativeProcessProtocol *process); + void HandleInferiorState_Exited(NativeProcessProtocol *process); - void - HandleInferiorState_Stopped (NativeProcessProtocol *process); + void HandleInferiorState_Stopped(NativeProcessProtocol *process); - NativeThreadProtocolSP - GetThreadFromSuffix (StringExtractorGDBRemote &packet); + NativeThreadProtocolSP GetThreadFromSuffix(StringExtractorGDBRemote &packet); - uint32_t - GetNextSavedRegistersID (); + uint32_t GetNextSavedRegistersID(); - void - MaybeCloseInferiorTerminalConnection (); + void MaybeCloseInferiorTerminalConnection(); - void - ClearProcessSpecificData (); + void ClearProcessSpecificData(); - void - RegisterPacketHandlers (); + void RegisterPacketHandlers(); - void - DataAvailableCallback (); + void DataAvailableCallback(); - void - SendProcessOutput (); + void SendProcessOutput(); - void - StartSTDIOForwarding(); + void StartSTDIOForwarding(); - void - StopSTDIOForwarding(); + void StopSTDIOForwarding(); - //------------------------------------------------------------------ - // For GDBRemoteCommunicationServerLLGS only - //------------------------------------------------------------------ - DISALLOW_COPY_AND_ASSIGN (GDBRemoteCommunicationServerLLGS); + //------------------------------------------------------------------ + // For GDBRemoteCommunicationServerLLGS only + //------------------------------------------------------------------ + DISALLOW_COPY_AND_ASSIGN(GDBRemoteCommunicationServerLLGS); }; } // namespace process_gdb_remote } // namespace lldb_private -#endif // liblldb_GDBRemoteCommunicationServerLLGS_h_ +#endif // liblldb_GDBRemoteCommunicationServerLLGS_h_ diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp index d6900c2..1106974 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp @@ -13,8 +13,8 @@ // C Includes // C++ Includes -#include <cstring> #include <chrono> +#include <cstring> #include <mutex> #include <sstream> @@ -47,549 +47,525 @@ using namespace lldb_private::process_gdb_remote; //---------------------------------------------------------------------- // GDBRemoteCommunicationServerPlatform constructor //---------------------------------------------------------------------- -GDBRemoteCommunicationServerPlatform::GDBRemoteCommunicationServerPlatform(const Socket::SocketProtocol socket_protocol, - const char *socket_scheme) - : GDBRemoteCommunicationServerCommon("gdb-remote.server", "gdb-remote.server.rx_packet"), - m_socket_protocol(socket_protocol), - m_socket_scheme(socket_scheme), - m_spawned_pids_mutex(), - m_port_map(), - m_port_offset(0) -{ - m_pending_gdb_server.pid = LLDB_INVALID_PROCESS_ID; - m_pending_gdb_server.port = 0; - - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qC, - &GDBRemoteCommunicationServerPlatform::Handle_qC); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir, - &GDBRemoteCommunicationServerPlatform::Handle_qGetWorkingDir); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qLaunchGDBServer, - &GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qQueryGDBServer, - &GDBRemoteCommunicationServerPlatform::Handle_qQueryGDBServer); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qKillSpawnedProcess, - &GDBRemoteCommunicationServerPlatform::Handle_qKillSpawnedProcess); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qProcessInfo, - &GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir, - &GDBRemoteCommunicationServerPlatform::Handle_QSetWorkingDir); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_jSignalsInfo, - &GDBRemoteCommunicationServerPlatform::Handle_jSignalsInfo); - - RegisterPacketHandler(StringExtractorGDBRemote::eServerPacketType_interrupt, - [this](StringExtractorGDBRemote packet, Error &error, bool &interrupt, bool &quit) { - error.SetErrorString("interrupt received"); - interrupt = true; - return PacketResult::Success; - }); +GDBRemoteCommunicationServerPlatform::GDBRemoteCommunicationServerPlatform( + const Socket::SocketProtocol socket_protocol, const char *socket_scheme) + : GDBRemoteCommunicationServerCommon("gdb-remote.server", + "gdb-remote.server.rx_packet"), + m_socket_protocol(socket_protocol), m_socket_scheme(socket_scheme), + m_spawned_pids_mutex(), m_port_map(), m_port_offset(0) { + m_pending_gdb_server.pid = LLDB_INVALID_PROCESS_ID; + m_pending_gdb_server.port = 0; + + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qC, + &GDBRemoteCommunicationServerPlatform::Handle_qC); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir, + &GDBRemoteCommunicationServerPlatform::Handle_qGetWorkingDir); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qLaunchGDBServer, + &GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qQueryGDBServer, + &GDBRemoteCommunicationServerPlatform::Handle_qQueryGDBServer); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qKillSpawnedProcess, + &GDBRemoteCommunicationServerPlatform::Handle_qKillSpawnedProcess); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qProcessInfo, + &GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir, + &GDBRemoteCommunicationServerPlatform::Handle_QSetWorkingDir); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_jSignalsInfo, + &GDBRemoteCommunicationServerPlatform::Handle_jSignalsInfo); + + RegisterPacketHandler(StringExtractorGDBRemote::eServerPacketType_interrupt, + [this](StringExtractorGDBRemote packet, Error &error, + bool &interrupt, bool &quit) { + error.SetErrorString("interrupt received"); + interrupt = true; + return PacketResult::Success; + }); } //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- -GDBRemoteCommunicationServerPlatform::~GDBRemoteCommunicationServerPlatform() -{ -} - -Error -GDBRemoteCommunicationServerPlatform::LaunchGDBServer(const lldb_private::Args& args, - std::string hostname, - lldb::pid_t& pid, - uint16_t& port, - std::string& socket_name) -{ - if (port == UINT16_MAX) - port = GetNextAvailablePort(); - - // Spawn a new thread to accept the port that gets bound after - // binding to port 0 (zero). - - // ignore the hostname send from the remote end, just use the ip address - // that we're currently communicating with as the hostname - - // Spawn a debugserver and try to get the port it listens to. - ProcessLaunchInfo debugserver_launch_info; - if (hostname.empty()) - hostname = "127.0.0.1"; - - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); - if (log) - log->Printf("Launching debugserver with: %s:%u...", hostname.c_str(), port); - - // Do not run in a new session so that it can not linger after the - // platform closes. - debugserver_launch_info.SetLaunchInSeparateProcessGroup(false); - debugserver_launch_info.SetMonitorProcessCallback( - std::bind(&GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped, this, std::placeholders::_1), false); - - std::string platform_scheme; - std::string platform_ip; - int platform_port; - std::string platform_path; - bool ok = UriParser::Parse(GetConnection()->GetURI().c_str(), platform_scheme, platform_ip, platform_port, platform_path); - UNUSED_IF_ASSERT_DISABLED(ok); - assert(ok); - - std::ostringstream url; - // debugserver does not accept the URL scheme prefix. +GDBRemoteCommunicationServerPlatform::~GDBRemoteCommunicationServerPlatform() {} + +Error GDBRemoteCommunicationServerPlatform::LaunchGDBServer( + const lldb_private::Args &args, std::string hostname, lldb::pid_t &pid, + uint16_t &port, std::string &socket_name) { + if (port == UINT16_MAX) + port = GetNextAvailablePort(); + + // Spawn a new thread to accept the port that gets bound after + // binding to port 0 (zero). + + // ignore the hostname send from the remote end, just use the ip address + // that we're currently communicating with as the hostname + + // Spawn a debugserver and try to get the port it listens to. + ProcessLaunchInfo debugserver_launch_info; + if (hostname.empty()) + hostname = "127.0.0.1"; + + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) + log->Printf("Launching debugserver with: %s:%u...", hostname.c_str(), port); + + // Do not run in a new session so that it can not linger after the + // platform closes. + debugserver_launch_info.SetLaunchInSeparateProcessGroup(false); + debugserver_launch_info.SetMonitorProcessCallback( + std::bind(&GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped, + this, std::placeholders::_1), + false); + + llvm::StringRef platform_scheme; + llvm::StringRef platform_ip; + int platform_port; + llvm::StringRef platform_path; + bool ok = UriParser::Parse(GetConnection()->GetURI(), platform_scheme, + platform_ip, platform_port, platform_path); + UNUSED_IF_ASSERT_DISABLED(ok); + assert(ok); + + std::ostringstream url; +// debugserver does not accept the URL scheme prefix. #if !defined(__APPLE__) - url << m_socket_scheme << "://"; + url << m_socket_scheme << "://"; #endif - uint16_t* port_ptr = &port; - if (m_socket_protocol == Socket::ProtocolTcp) - url << platform_ip << ":" << port; - else - { - socket_name = GetDomainSocketPath("gdbserver").GetPath(); - url << socket_name; - port_ptr = nullptr; - } - - Error error = StartDebugserverProcess (url.str().c_str(), - nullptr, - debugserver_launch_info, - port_ptr, - args); - - pid = debugserver_launch_info.GetProcessID(); - if (pid != LLDB_INVALID_PROCESS_ID) - { - std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); - m_spawned_pids.insert(pid); - if (port > 0) - AssociatePortWithProcess(port, pid); - } - else - { - if (port > 0) - FreePort(port); - } - return error; + uint16_t *port_ptr = &port; + if (m_socket_protocol == Socket::ProtocolTcp) + url << platform_ip.str() << ":" << port; + else { + socket_name = GetDomainSocketPath("gdbserver").GetPath(); + url << socket_name; + port_ptr = nullptr; + } + + Error error = StartDebugserverProcess( + url.str().c_str(), nullptr, debugserver_launch_info, port_ptr, &args, -1); + + pid = debugserver_launch_info.GetProcessID(); + if (pid != LLDB_INVALID_PROCESS_ID) { + std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); + m_spawned_pids.insert(pid); + if (port > 0) + AssociatePortWithProcess(port, pid); + } else { + if (port > 0) + FreePort(port); + } + return error; } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet) -{ +GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer( + StringExtractorGDBRemote &packet) { #ifdef _WIN32 - return SendErrorResponse(9); + return SendErrorResponse(9); #else - // Spawn a local debugserver as a platform so we can then attach or launch - // a process... - - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); + // Spawn a local debugserver as a platform so we can then attach or launch + // a process... + + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) + log->Printf("GDBRemoteCommunicationServerPlatform::%s() called", + __FUNCTION__); + + ConnectionFileDescriptor file_conn; + std::string hostname; + packet.SetFilePos(::strlen("qLaunchGDBServer;")); + llvm::StringRef name; + llvm::StringRef value; + uint16_t port = UINT16_MAX; + while (packet.GetNameColonValue(name, value)) { + if (name.equals("host")) + hostname = value; + else if (name.equals("port")) + value.getAsInteger(0, port); + } + + lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID; + std::string socket_name; + Error error = + LaunchGDBServer(Args(), hostname, debugserver_pid, port, socket_name); + if (error.Fail()) { if (log) - log->Printf ("GDBRemoteCommunicationServerPlatform::%s() called", __FUNCTION__); - - ConnectionFileDescriptor file_conn; - std::string hostname; - packet.SetFilePos(::strlen ("qLaunchGDBServer;")); - std::string name; - std::string value; - uint16_t port = UINT16_MAX; - while (packet.GetNameColonValue(name, value)) - { - if (name.compare ("host") == 0) - hostname.swap(value); - else if (name.compare ("port") == 0) - port = StringConvert::ToUInt32(value.c_str(), 0, 0); - } - - lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID; - std::string socket_name; - Error error = LaunchGDBServer(Args(), hostname, debugserver_pid, port, socket_name); - if (error.Fail()) - { - if (log) - log->Printf("GDBRemoteCommunicationServerPlatform::%s() debugserver launch failed: %s", __FUNCTION__, error.AsCString ()); - return SendErrorResponse(9); - } - - if (log) - log->Printf ("GDBRemoteCommunicationServerPlatform::%s() debugserver launched successfully as pid %" PRIu64, __FUNCTION__, debugserver_pid); - - StreamGDBRemote response; - response.Printf("pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset); - if (!socket_name.empty()) - { - response.PutCString("socket_name:"); - response.PutCStringAsRawHex8(socket_name.c_str()); - response.PutChar(';'); - } - - PacketResult packet_result = SendPacketNoLock(response.GetData(), response.GetSize()); - if (packet_result != PacketResult::Success) - { - if (debugserver_pid != LLDB_INVALID_PROCESS_ID) - ::kill (debugserver_pid, SIGINT); - } - return packet_result; + log->Printf("GDBRemoteCommunicationServerPlatform::%s() debugserver " + "launch failed: %s", + __FUNCTION__, error.AsCString()); + return SendErrorResponse(9); + } + + if (log) + log->Printf("GDBRemoteCommunicationServerPlatform::%s() debugserver " + "launched successfully as pid %" PRIu64, + __FUNCTION__, debugserver_pid); + + StreamGDBRemote response; + response.Printf("pid:%" PRIu64 ";port:%u;", debugserver_pid, + port + m_port_offset); + if (!socket_name.empty()) { + response.PutCString("socket_name:"); + response.PutCStringAsRawHex8(socket_name.c_str()); + response.PutChar(';'); + } + + PacketResult packet_result = SendPacketNoLock(response.GetString()); + if (packet_result != PacketResult::Success) { + if (debugserver_pid != LLDB_INVALID_PROCESS_ID) + ::kill(debugserver_pid, SIGINT); + } + return packet_result; #endif } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerPlatform::Handle_qQueryGDBServer (StringExtractorGDBRemote &packet) -{ - if (m_pending_gdb_server.pid == LLDB_INVALID_PROCESS_ID) - return SendErrorResponse(4); - - JSONObject::SP server_sp = std::make_shared<JSONObject>(); - server_sp->SetObject("port", std::make_shared<JSONNumber>(m_pending_gdb_server.port)); - if (!m_pending_gdb_server.socket_name.empty()) - server_sp->SetObject("socket_name", - std::make_shared<JSONString>(m_pending_gdb_server.socket_name.c_str())); - - JSONArray server_list; - server_list.AppendObject(server_sp); - - StreamGDBRemote response; - server_list.Write(response); - - StreamGDBRemote escaped_response; - escaped_response.PutEscapedBytes(response.GetData(), response.GetSize()); - return SendPacketNoLock(escaped_response.GetData(), escaped_response.GetSize()); +GDBRemoteCommunicationServerPlatform::Handle_qQueryGDBServer( + StringExtractorGDBRemote &packet) { + if (m_pending_gdb_server.pid == LLDB_INVALID_PROCESS_ID) + return SendErrorResponse(4); + + JSONObject::SP server_sp = std::make_shared<JSONObject>(); + server_sp->SetObject("port", + std::make_shared<JSONNumber>(m_pending_gdb_server.port)); + if (!m_pending_gdb_server.socket_name.empty()) + server_sp->SetObject( + "socket_name", + std::make_shared<JSONString>(m_pending_gdb_server.socket_name.c_str())); + + JSONArray server_list; + server_list.AppendObject(server_sp); + + StreamGDBRemote response; + server_list.Write(response); + + StreamGDBRemote escaped_response; + escaped_response.PutEscapedBytes(response.GetString().data(), + response.GetSize()); + return SendPacketNoLock(escaped_response.GetString()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerPlatform::Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen ("qKillSpawnedProcess:")); +GDBRemoteCommunicationServerPlatform::Handle_qKillSpawnedProcess( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("qKillSpawnedProcess:")); - lldb::pid_t pid = packet.GetU64(LLDB_INVALID_PROCESS_ID); + lldb::pid_t pid = packet.GetU64(LLDB_INVALID_PROCESS_ID); - // verify that we know anything about this pid. - // Scope for locker - { - std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); - if (m_spawned_pids.find(pid) == m_spawned_pids.end()) - { - // not a pid we know about - return SendErrorResponse (10); - } + // verify that we know anything about this pid. + // Scope for locker + { + std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); + if (m_spawned_pids.find(pid) == m_spawned_pids.end()) { + // not a pid we know about + return SendErrorResponse(10); } + } - // go ahead and attempt to kill the spawned process - if (KillSpawnedProcess (pid)) - return SendOKResponse (); - else - return SendErrorResponse (11); + // go ahead and attempt to kill the spawned process + if (KillSpawnedProcess(pid)) + return SendOKResponse(); + else + return SendErrorResponse(11); } -bool -GDBRemoteCommunicationServerPlatform::KillSpawnedProcess (lldb::pid_t pid) -{ - // make sure we know about this process - { - std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); - if (m_spawned_pids.find(pid) == m_spawned_pids.end()) - return false; - } +bool GDBRemoteCommunicationServerPlatform::KillSpawnedProcess(lldb::pid_t pid) { + // make sure we know about this process + { + std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); + if (m_spawned_pids.find(pid) == m_spawned_pids.end()) + return false; + } - // first try a SIGTERM (standard kill) - Host::Kill (pid, SIGTERM); + // first try a SIGTERM (standard kill) + Host::Kill(pid, SIGTERM); - // check if that worked - for (size_t i=0; i<10; ++i) + // check if that worked + for (size_t i = 0; i < 10; ++i) { { - { - std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); - if (m_spawned_pids.find(pid) == m_spawned_pids.end()) - { - // it is now killed - return true; - } - } - usleep (10000); + std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); + if (m_spawned_pids.find(pid) == m_spawned_pids.end()) { + // it is now killed + return true; + } } + usleep(10000); + } - // check one more time after the final usleep - { - std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); - if (m_spawned_pids.find(pid) == m_spawned_pids.end()) - return true; - } + // check one more time after the final usleep + { + std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); + if (m_spawned_pids.find(pid) == m_spawned_pids.end()) + return true; + } - // the launched process still lives. Now try killing it again, - // this time with an unblockable signal. - Host::Kill (pid, SIGKILL); + // the launched process still lives. Now try killing it again, + // this time with an unblockable signal. + Host::Kill(pid, SIGKILL); - for (size_t i=0; i<10; ++i) + for (size_t i = 0; i < 10; ++i) { { - { - std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); - if (m_spawned_pids.find(pid) == m_spawned_pids.end()) - { - // it is now killed - return true; - } - } - usleep (10000); + std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); + if (m_spawned_pids.find(pid) == m_spawned_pids.end()) { + // it is now killed + return true; + } } + usleep(10000); + } - // check one more time after the final usleep - // Scope for locker - { - std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); - if (m_spawned_pids.find(pid) == m_spawned_pids.end()) - return true; - } + // check one more time after the final usleep + // Scope for locker + { + std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); + if (m_spawned_pids.find(pid) == m_spawned_pids.end()) + return true; + } - // no luck - the process still lives - return false; + // no luck - the process still lives + return false; } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo (StringExtractorGDBRemote &packet) -{ - lldb::pid_t pid = m_process_launch_info.GetProcessID (); - m_process_launch_info.Clear (); +GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo( + StringExtractorGDBRemote &packet) { + lldb::pid_t pid = m_process_launch_info.GetProcessID(); + m_process_launch_info.Clear(); - if (pid == LLDB_INVALID_PROCESS_ID) - return SendErrorResponse (1); + if (pid == LLDB_INVALID_PROCESS_ID) + return SendErrorResponse(1); - ProcessInstanceInfo proc_info; - if (!Host::GetProcessInfo (pid, proc_info)) - return SendErrorResponse (1); + ProcessInstanceInfo proc_info; + if (!Host::GetProcessInfo(pid, proc_info)) + return SendErrorResponse(1); - StreamString response; - CreateProcessInfoResponse_DebugServerStyle(proc_info, response); - return SendPacketNoLock (response.GetData (), response.GetSize ()); + StreamString response; + CreateProcessInfoResponse_DebugServerStyle(proc_info, response); + return SendPacketNoLock(response.GetString()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerPlatform::Handle_qGetWorkingDir (StringExtractorGDBRemote &packet) -{ - // If this packet is sent to a platform, then change the current working directory - - char cwd[PATH_MAX]; - if (getcwd(cwd, sizeof(cwd)) == NULL) - return SendErrorResponse(errno); - - StreamString response; - response.PutBytesAsRawHex8(cwd, strlen(cwd)); - return SendPacketNoLock(response.GetData(), response.GetSize()); +GDBRemoteCommunicationServerPlatform::Handle_qGetWorkingDir( + StringExtractorGDBRemote &packet) { + // If this packet is sent to a platform, then change the current working + // directory + + char cwd[PATH_MAX]; + if (getcwd(cwd, sizeof(cwd)) == NULL) + return SendErrorResponse(errno); + + StreamString response; + response.PutBytesAsRawHex8(cwd, strlen(cwd)); + return SendPacketNoLock(response.GetString()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerPlatform::Handle_QSetWorkingDir (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos (::strlen ("QSetWorkingDir:")); - std::string path; - packet.GetHexByteString (path); - - // If this packet is sent to a platform, then change the current working directory - if (::chdir(path.c_str()) != 0) - return SendErrorResponse (errno); - return SendOKResponse (); +GDBRemoteCommunicationServerPlatform::Handle_QSetWorkingDir( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("QSetWorkingDir:")); + std::string path; + packet.GetHexByteString(path); + + // If this packet is sent to a platform, then change the current working + // directory + if (::chdir(path.c_str()) != 0) + return SendErrorResponse(errno); + return SendOKResponse(); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerPlatform::Handle_qC (StringExtractorGDBRemote &packet) -{ - // NOTE: lldb should now be using qProcessInfo for process IDs. This path here - // should not be used. It is reporting process id instead of thread id. The - // correct answer doesn't seem to make much sense for lldb-platform. - // CONSIDER: flip to "unsupported". - lldb::pid_t pid = m_process_launch_info.GetProcessID(); - - StreamString response; - response.Printf("QC%" PRIx64, pid); - - // If we launch a process and this GDB server is acting as a platform, - // then we need to clear the process launch state so we can start - // launching another process. In order to launch a process a bunch or - // packets need to be sent: environment packets, working directory, - // disable ASLR, and many more settings. When we launch a process we - // then need to know when to clear this information. Currently we are - // selecting the 'qC' packet as that packet which seems to make the most - // sense. - if (pid != LLDB_INVALID_PROCESS_ID) - { - m_process_launch_info.Clear(); - } - - return SendPacketNoLock (response.GetData(), response.GetSize()); +GDBRemoteCommunicationServerPlatform::Handle_qC( + StringExtractorGDBRemote &packet) { + // NOTE: lldb should now be using qProcessInfo for process IDs. This path + // here + // should not be used. It is reporting process id instead of thread id. The + // correct answer doesn't seem to make much sense for lldb-platform. + // CONSIDER: flip to "unsupported". + lldb::pid_t pid = m_process_launch_info.GetProcessID(); + + StreamString response; + response.Printf("QC%" PRIx64, pid); + + // If we launch a process and this GDB server is acting as a platform, + // then we need to clear the process launch state so we can start + // launching another process. In order to launch a process a bunch or + // packets need to be sent: environment packets, working directory, + // disable ASLR, and many more settings. When we launch a process we + // then need to know when to clear this information. Currently we are + // selecting the 'qC' packet as that packet which seems to make the most + // sense. + if (pid != LLDB_INVALID_PROCESS_ID) { + m_process_launch_info.Clear(); + } + + return SendPacketNoLock(response.GetString()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerPlatform::Handle_jSignalsInfo(StringExtractorGDBRemote &packet) -{ - StructuredData::Array signal_array; - - const auto &signals = Host::GetUnixSignals(); - for (auto signo = signals->GetFirstSignalNumber(); - signo != LLDB_INVALID_SIGNAL_NUMBER; - signo = signals->GetNextSignalNumber(signo)) - { - auto dictionary = std::make_shared<StructuredData::Dictionary>(); - - dictionary->AddIntegerItem("signo", signo); - dictionary->AddStringItem("name", signals->GetSignalAsCString(signo)); - - bool suppress, stop, notify; - signals->GetSignalInfo(signo, suppress, stop, notify); - dictionary->AddBooleanItem("suppress", suppress); - dictionary->AddBooleanItem("stop", stop); - dictionary->AddBooleanItem("notify", notify); - - signal_array.Push(dictionary); - } - - StreamString response; - signal_array.Dump(response); - return SendPacketNoLock(response.GetData(), response.GetSize()); +GDBRemoteCommunicationServerPlatform::Handle_jSignalsInfo( + StringExtractorGDBRemote &packet) { + StructuredData::Array signal_array; + + const auto &signals = Host::GetUnixSignals(); + for (auto signo = signals->GetFirstSignalNumber(); + signo != LLDB_INVALID_SIGNAL_NUMBER; + signo = signals->GetNextSignalNumber(signo)) { + auto dictionary = std::make_shared<StructuredData::Dictionary>(); + + dictionary->AddIntegerItem("signo", signo); + dictionary->AddStringItem("name", signals->GetSignalAsCString(signo)); + + bool suppress, stop, notify; + signals->GetSignalInfo(signo, suppress, stop, notify); + dictionary->AddBooleanItem("suppress", suppress); + dictionary->AddBooleanItem("stop", stop); + dictionary->AddBooleanItem("notify", notify); + + signal_array.Push(dictionary); + } + + StreamString response; + signal_array.Dump(response); + return SendPacketNoLock(response.GetString()); } -bool -GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped (lldb::pid_t pid) -{ - std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); - FreePortForProcess(pid); - m_spawned_pids.erase(pid); - return true; +bool GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped( + lldb::pid_t pid) { + std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); + FreePortForProcess(pid); + m_spawned_pids.erase(pid); + return true; } -Error -GDBRemoteCommunicationServerPlatform::LaunchProcess () -{ - if (!m_process_launch_info.GetArguments ().GetArgumentCount ()) - return Error ("%s: no process command line specified to launch", __FUNCTION__); - - // specify the process monitor if not already set. This should - // generally be what happens since we need to reap started - // processes. - if (!m_process_launch_info.GetMonitorProcessCallback ()) - m_process_launch_info.SetMonitorProcessCallback( - std::bind(&GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped, this, std::placeholders::_1), - false); - - Error error = Host::LaunchProcess(m_process_launch_info); - if (!error.Success ()) - { - fprintf (stderr, "%s: failed to launch executable %s", __FUNCTION__, m_process_launch_info.GetArguments ().GetArgumentAtIndex (0)); - return error; - } +Error GDBRemoteCommunicationServerPlatform::LaunchProcess() { + if (!m_process_launch_info.GetArguments().GetArgumentCount()) + return Error("%s: no process command line specified to launch", + __FUNCTION__); + + // specify the process monitor if not already set. This should + // generally be what happens since we need to reap started + // processes. + if (!m_process_launch_info.GetMonitorProcessCallback()) + m_process_launch_info.SetMonitorProcessCallback( + std::bind( + &GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped, + this, std::placeholders::_1), + false); + + Error error = Host::LaunchProcess(m_process_launch_info); + if (!error.Success()) { + fprintf(stderr, "%s: failed to launch executable %s", __FUNCTION__, + m_process_launch_info.GetArguments().GetArgumentAtIndex(0)); + return error; + } - printf ("Launched '%s' as process %" PRIu64 "...\n", m_process_launch_info.GetArguments ().GetArgumentAtIndex (0), m_process_launch_info.GetProcessID()); + printf("Launched '%s' as process %" PRIu64 "...\n", + m_process_launch_info.GetArguments().GetArgumentAtIndex(0), + m_process_launch_info.GetProcessID()); - // add to list of spawned processes. On an lldb-gdbserver, we - // would expect there to be only one. - const auto pid = m_process_launch_info.GetProcessID(); - if (pid != LLDB_INVALID_PROCESS_ID) - { - // add to spawned pids - std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); - m_spawned_pids.insert(pid); - } + // add to list of spawned processes. On an lldb-gdbserver, we + // would expect there to be only one. + const auto pid = m_process_launch_info.GetProcessID(); + if (pid != LLDB_INVALID_PROCESS_ID) { + // add to spawned pids + std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); + m_spawned_pids.insert(pid); + } - return error; + return error; } -void -GDBRemoteCommunicationServerPlatform::SetPortMap (PortMap &&port_map) -{ - m_port_map = port_map; +void GDBRemoteCommunicationServerPlatform::SetPortMap(PortMap &&port_map) { + m_port_map = port_map; } -uint16_t -GDBRemoteCommunicationServerPlatform::GetNextAvailablePort () -{ - if (m_port_map.empty()) - return 0; // Bind to port zero and get a port, we didn't have any limitations +uint16_t GDBRemoteCommunicationServerPlatform::GetNextAvailablePort() { + if (m_port_map.empty()) + return 0; // Bind to port zero and get a port, we didn't have any + // limitations - for (auto &pair : m_port_map) - { - if (pair.second == LLDB_INVALID_PROCESS_ID) - { - pair.second = ~(lldb::pid_t)LLDB_INVALID_PROCESS_ID; - return pair.first; - } + for (auto &pair : m_port_map) { + if (pair.second == LLDB_INVALID_PROCESS_ID) { + pair.second = ~(lldb::pid_t)LLDB_INVALID_PROCESS_ID; + return pair.first; } - return UINT16_MAX; + } + return UINT16_MAX; } -bool -GDBRemoteCommunicationServerPlatform::AssociatePortWithProcess (uint16_t port, lldb::pid_t pid) -{ - PortMap::iterator pos = m_port_map.find(port); - if (pos != m_port_map.end()) - { - pos->second = pid; - return true; - } - return false; +bool GDBRemoteCommunicationServerPlatform::AssociatePortWithProcess( + uint16_t port, lldb::pid_t pid) { + PortMap::iterator pos = m_port_map.find(port); + if (pos != m_port_map.end()) { + pos->second = pid; + return true; + } + return false; } -bool -GDBRemoteCommunicationServerPlatform::FreePort (uint16_t port) -{ - PortMap::iterator pos = m_port_map.find(port); - if (pos != m_port_map.end()) - { - pos->second = LLDB_INVALID_PROCESS_ID; - return true; - } - return false; +bool GDBRemoteCommunicationServerPlatform::FreePort(uint16_t port) { + PortMap::iterator pos = m_port_map.find(port); + if (pos != m_port_map.end()) { + pos->second = LLDB_INVALID_PROCESS_ID; + return true; + } + return false; } -bool -GDBRemoteCommunicationServerPlatform::FreePortForProcess (lldb::pid_t pid) -{ - if (!m_port_map.empty()) - { - for (auto &pair : m_port_map) - { - if (pair.second == pid) - { - pair.second = LLDB_INVALID_PROCESS_ID; - return true; - } - } +bool GDBRemoteCommunicationServerPlatform::FreePortForProcess(lldb::pid_t pid) { + if (!m_port_map.empty()) { + for (auto &pair : m_port_map) { + if (pair.second == pid) { + pair.second = LLDB_INVALID_PROCESS_ID; + return true; + } } - return false; + } + return false; } -const FileSpec& -GDBRemoteCommunicationServerPlatform::GetDomainSocketDir() -{ - static FileSpec g_domainsocket_dir; - static std::once_flag g_once_flag; - - std::call_once(g_once_flag, []() { - const char* domainsocket_dir_env = ::getenv("LLDB_DEBUGSERVER_DOMAINSOCKET_DIR"); - if (domainsocket_dir_env != nullptr) - g_domainsocket_dir = FileSpec(domainsocket_dir_env, false); - else - HostInfo::GetLLDBPath(ePathTypeLLDBTempSystemDir, g_domainsocket_dir); - }); - - return g_domainsocket_dir; +const FileSpec &GDBRemoteCommunicationServerPlatform::GetDomainSocketDir() { + static FileSpec g_domainsocket_dir; + static std::once_flag g_once_flag; + + std::call_once(g_once_flag, []() { + const char *domainsocket_dir_env = + ::getenv("LLDB_DEBUGSERVER_DOMAINSOCKET_DIR"); + if (domainsocket_dir_env != nullptr) + g_domainsocket_dir = FileSpec(domainsocket_dir_env, false); + else + HostInfo::GetLLDBPath(ePathTypeLLDBTempSystemDir, g_domainsocket_dir); + }); + + return g_domainsocket_dir; } FileSpec -GDBRemoteCommunicationServerPlatform::GetDomainSocketPath(const char* prefix) -{ - llvm::SmallString<PATH_MAX> socket_path; - llvm::SmallString<PATH_MAX> socket_name((llvm::StringRef(prefix) + ".%%%%%%").str()); +GDBRemoteCommunicationServerPlatform::GetDomainSocketPath(const char *prefix) { + llvm::SmallString<PATH_MAX> socket_path; + llvm::SmallString<PATH_MAX> socket_name( + (llvm::StringRef(prefix) + ".%%%%%%").str()); - FileSpec socket_path_spec(GetDomainSocketDir()); - socket_path_spec.AppendPathComponent(socket_name.c_str()); + FileSpec socket_path_spec(GetDomainSocketDir()); + socket_path_spec.AppendPathComponent(socket_name.c_str()); - llvm::sys::fs::createUniqueFile(socket_path_spec.GetCString(), socket_path); - return FileSpec(socket_path.c_str(), false); + llvm::sys::fs::createUniqueFile(socket_path_spec.GetCString(), socket_path); + return FileSpec(socket_path.c_str(), false); } -void -GDBRemoteCommunicationServerPlatform::SetPortOffset(uint16_t port_offset) -{ - m_port_offset = port_offset; +void GDBRemoteCommunicationServerPlatform::SetPortOffset(uint16_t port_offset) { + m_port_offset = port_offset; } -void -GDBRemoteCommunicationServerPlatform::SetPendingGdbServer(lldb::pid_t pid, - uint16_t port, - const std::string& socket_name) -{ - m_pending_gdb_server.pid = pid; - m_pending_gdb_server.port = port; - m_pending_gdb_server.socket_name = socket_name; +void GDBRemoteCommunicationServerPlatform::SetPendingGdbServer( + lldb::pid_t pid, uint16_t port, const std::string &socket_name) { + m_pending_gdb_server.pid = pid; + m_pending_gdb_server.port = port; + m_pending_gdb_server.socket_name = socket_name; } diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h index 1f4d08c..472d86e 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h @@ -24,110 +24,90 @@ namespace lldb_private { namespace process_gdb_remote { -class GDBRemoteCommunicationServerPlatform : - public GDBRemoteCommunicationServerCommon -{ +class GDBRemoteCommunicationServerPlatform + : public GDBRemoteCommunicationServerCommon { public: - typedef std::map<uint16_t, lldb::pid_t> PortMap; + typedef std::map<uint16_t, lldb::pid_t> PortMap; - GDBRemoteCommunicationServerPlatform(const Socket::SocketProtocol socket_protocol, - const char* socket_scheme); + GDBRemoteCommunicationServerPlatform( + const Socket::SocketProtocol socket_protocol, const char *socket_scheme); - ~GDBRemoteCommunicationServerPlatform() override; + ~GDBRemoteCommunicationServerPlatform() override; - Error - LaunchProcess () override; + Error LaunchProcess() override; - // Set both ports to zero to let the platform automatically bind to - // a port chosen by the OS. - void - SetPortMap (PortMap &&port_map); + // Set both ports to zero to let the platform automatically bind to + // a port chosen by the OS. + void SetPortMap(PortMap &&port_map); - //---------------------------------------------------------------------- - // If we are using a port map where we can only use certain ports, - // get the next available port. - // - // If we are using a port map and we are out of ports, return UINT16_MAX - // - // If we aren't using a port map, return 0 to indicate we should bind to - // port 0 and then figure out which port we used. - //---------------------------------------------------------------------- - uint16_t - GetNextAvailablePort (); + //---------------------------------------------------------------------- + // If we are using a port map where we can only use certain ports, + // get the next available port. + // + // If we are using a port map and we are out of ports, return UINT16_MAX + // + // If we aren't using a port map, return 0 to indicate we should bind to + // port 0 and then figure out which port we used. + //---------------------------------------------------------------------- + uint16_t GetNextAvailablePort(); - bool - AssociatePortWithProcess (uint16_t port, lldb::pid_t pid); + bool AssociatePortWithProcess(uint16_t port, lldb::pid_t pid); - bool - FreePort (uint16_t port); + bool FreePort(uint16_t port); - bool - FreePortForProcess (lldb::pid_t pid); + bool FreePortForProcess(lldb::pid_t pid); - void - SetPortOffset (uint16_t port_offset); + void SetPortOffset(uint16_t port_offset); - void - SetInferiorArguments (const lldb_private::Args& args); + void SetInferiorArguments(const lldb_private::Args &args); - Error - LaunchGDBServer(const lldb_private::Args& args, - std::string hostname, - lldb::pid_t& pid, - uint16_t& port, - std::string& socket_name); + Error LaunchGDBServer(const lldb_private::Args &args, std::string hostname, + lldb::pid_t &pid, uint16_t &port, + std::string &socket_name); - void - SetPendingGdbServer(lldb::pid_t pid, uint16_t port, const std::string& socket_name); + void SetPendingGdbServer(lldb::pid_t pid, uint16_t port, + const std::string &socket_name); protected: - const Socket::SocketProtocol m_socket_protocol; - const std::string m_socket_scheme; - std::recursive_mutex m_spawned_pids_mutex; - std::set<lldb::pid_t> m_spawned_pids; + const Socket::SocketProtocol m_socket_protocol; + const std::string m_socket_scheme; + std::recursive_mutex m_spawned_pids_mutex; + std::set<lldb::pid_t> m_spawned_pids; - PortMap m_port_map; - uint16_t m_port_offset; - struct { lldb::pid_t pid; uint16_t port; std::string socket_name; } m_pending_gdb_server; + PortMap m_port_map; + uint16_t m_port_offset; + struct { + lldb::pid_t pid; + uint16_t port; + std::string socket_name; + } m_pending_gdb_server; - PacketResult - Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet); + PacketResult Handle_qLaunchGDBServer(StringExtractorGDBRemote &packet); - PacketResult - Handle_qQueryGDBServer (StringExtractorGDBRemote &packet); + PacketResult Handle_qQueryGDBServer(StringExtractorGDBRemote &packet); - PacketResult - Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet); + PacketResult Handle_qKillSpawnedProcess(StringExtractorGDBRemote &packet); - PacketResult - Handle_qProcessInfo (StringExtractorGDBRemote &packet); + PacketResult Handle_qProcessInfo(StringExtractorGDBRemote &packet); - PacketResult - Handle_qGetWorkingDir (StringExtractorGDBRemote &packet); + PacketResult Handle_qGetWorkingDir(StringExtractorGDBRemote &packet); - PacketResult - Handle_QSetWorkingDir (StringExtractorGDBRemote &packet); + PacketResult Handle_QSetWorkingDir(StringExtractorGDBRemote &packet); - PacketResult - Handle_qC (StringExtractorGDBRemote &packet); + PacketResult Handle_qC(StringExtractorGDBRemote &packet); - PacketResult - Handle_jSignalsInfo(StringExtractorGDBRemote &packet); + PacketResult Handle_jSignalsInfo(StringExtractorGDBRemote &packet); private: - bool - KillSpawnedProcess (lldb::pid_t pid); + bool KillSpawnedProcess(lldb::pid_t pid); - bool - DebugserverProcessReaped (lldb::pid_t pid); + bool DebugserverProcessReaped(lldb::pid_t pid); - static const FileSpec& - GetDomainSocketDir(); + static const FileSpec &GetDomainSocketDir(); - static FileSpec - GetDomainSocketPath(const char* prefix); + static FileSpec GetDomainSocketPath(const char *prefix); - DISALLOW_COPY_AND_ASSIGN (GDBRemoteCommunicationServerPlatform); + DISALLOW_COPY_AND_ASSIGN(GDBRemoteCommunicationServerPlatform); }; } // namespace process_gdb_remote diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp index 57983c4..27ce67d 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp @@ -21,12 +21,12 @@ #include "lldb/Target/Target.h" #include "lldb/Utility/Utils.h" // Project includes -#include "Utility/StringExtractorGDBRemote.h" #include "ProcessGDBRemote.h" #include "ProcessGDBRemoteLog.h" #include "ThreadGDBRemote.h" #include "Utility/ARM_DWARF_Registers.h" #include "Utility/ARM_ehframe_Registers.h" +#include "Utility/StringExtractorGDBRemote.h" using namespace lldb; using namespace lldb_private; @@ -35,1189 +35,953 @@ using namespace lldb_private::process_gdb_remote; //---------------------------------------------------------------------- // GDBRemoteRegisterContext constructor //---------------------------------------------------------------------- -GDBRemoteRegisterContext::GDBRemoteRegisterContext -( - ThreadGDBRemote &thread, - uint32_t concrete_frame_idx, - GDBRemoteDynamicRegisterInfo ®_info, - bool read_all_at_once -) : - RegisterContext (thread, concrete_frame_idx), - m_reg_info (reg_info), - m_reg_valid (), - m_reg_data (), - m_read_all_at_once (read_all_at_once) -{ - // Resize our vector of bools to contain one bool for every register. - // We will use these boolean values to know when a register value - // is valid in m_reg_data. - m_reg_valid.resize (reg_info.GetNumRegisters()); - - // Make a heap based buffer that is big enough to store all registers - DataBufferSP reg_data_sp(new DataBufferHeap (reg_info.GetRegisterDataByteSize(), 0)); - m_reg_data.SetData (reg_data_sp); - m_reg_data.SetByteOrder(thread.GetProcess()->GetByteOrder()); +GDBRemoteRegisterContext::GDBRemoteRegisterContext( + ThreadGDBRemote &thread, uint32_t concrete_frame_idx, + GDBRemoteDynamicRegisterInfo ®_info, bool read_all_at_once) + : RegisterContext(thread, concrete_frame_idx), m_reg_info(reg_info), + m_reg_valid(), m_reg_data(), m_read_all_at_once(read_all_at_once) { + // Resize our vector of bools to contain one bool for every register. + // We will use these boolean values to know when a register value + // is valid in m_reg_data. + m_reg_valid.resize(reg_info.GetNumRegisters()); + + // Make a heap based buffer that is big enough to store all registers + DataBufferSP reg_data_sp( + new DataBufferHeap(reg_info.GetRegisterDataByteSize(), 0)); + m_reg_data.SetData(reg_data_sp); + m_reg_data.SetByteOrder(thread.GetProcess()->GetByteOrder()); } //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- -GDBRemoteRegisterContext::~GDBRemoteRegisterContext() -{ -} +GDBRemoteRegisterContext::~GDBRemoteRegisterContext() {} -void -GDBRemoteRegisterContext::InvalidateAllRegisters () -{ - SetAllRegisterValid (false); +void GDBRemoteRegisterContext::InvalidateAllRegisters() { + SetAllRegisterValid(false); } -void -GDBRemoteRegisterContext::SetAllRegisterValid (bool b) -{ - std::vector<bool>::iterator pos, end = m_reg_valid.end(); - for (pos = m_reg_valid.begin(); pos != end; ++pos) - *pos = b; +void GDBRemoteRegisterContext::SetAllRegisterValid(bool b) { + std::vector<bool>::iterator pos, end = m_reg_valid.end(); + for (pos = m_reg_valid.begin(); pos != end; ++pos) + *pos = b; } -size_t -GDBRemoteRegisterContext::GetRegisterCount () -{ - return m_reg_info.GetNumRegisters (); +size_t GDBRemoteRegisterContext::GetRegisterCount() { + return m_reg_info.GetNumRegisters(); } const RegisterInfo * -GDBRemoteRegisterContext::GetRegisterInfoAtIndex (size_t reg) -{ - RegisterInfo* reg_info = m_reg_info.GetRegisterInfoAtIndex (reg); - - if (reg_info && reg_info->dynamic_size_dwarf_expr_bytes) - { - const ArchSpec &arch = m_thread.GetProcess ()->GetTarget ().GetArchitecture (); - uint8_t reg_size = UpdateDynamicRegisterSize (arch, reg_info); - reg_info->byte_size = reg_size; - } - return reg_info; +GDBRemoteRegisterContext::GetRegisterInfoAtIndex(size_t reg) { + RegisterInfo *reg_info = m_reg_info.GetRegisterInfoAtIndex(reg); + + if (reg_info && reg_info->dynamic_size_dwarf_expr_bytes) { + const ArchSpec &arch = m_thread.GetProcess()->GetTarget().GetArchitecture(); + uint8_t reg_size = UpdateDynamicRegisterSize(arch, reg_info); + reg_info->byte_size = reg_size; + } + return reg_info; } -size_t -GDBRemoteRegisterContext::GetRegisterSetCount () -{ - return m_reg_info.GetNumRegisterSets (); +size_t GDBRemoteRegisterContext::GetRegisterSetCount() { + return m_reg_info.GetNumRegisterSets(); } - - -const RegisterSet * -GDBRemoteRegisterContext::GetRegisterSet (size_t reg_set) -{ - return m_reg_info.GetRegisterSet (reg_set); +const RegisterSet *GDBRemoteRegisterContext::GetRegisterSet(size_t reg_set) { + return m_reg_info.GetRegisterSet(reg_set); } +bool GDBRemoteRegisterContext::ReadRegister(const RegisterInfo *reg_info, + RegisterValue &value) { + // Read the register + if (ReadRegisterBytes(reg_info, m_reg_data)) { + const bool partial_data_ok = false; + Error error(value.SetValueFromData(reg_info, m_reg_data, + reg_info->byte_offset, partial_data_ok)); + return error.Success(); + } + return false; +} - -bool -GDBRemoteRegisterContext::ReadRegister (const RegisterInfo *reg_info, RegisterValue &value) -{ - // Read the register - if (ReadRegisterBytes (reg_info, m_reg_data)) - { - const bool partial_data_ok = false; - Error error (value.SetValueFromData(reg_info, m_reg_data, reg_info->byte_offset, partial_data_ok)); - return error.Success(); - } +bool GDBRemoteRegisterContext::PrivateSetRegisterValue( + uint32_t reg, llvm::ArrayRef<uint8_t> data) { + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); + if (reg_info == NULL) return false; -} -bool -GDBRemoteRegisterContext::PrivateSetRegisterValue (uint32_t reg, StringExtractor &response) -{ - const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg); - if (reg_info == NULL) - return false; - - // Invalidate if needed - InvalidateIfNeeded(false); - - const uint32_t reg_byte_size = reg_info->byte_size; - const size_t bytes_copied = response.GetHexBytes (const_cast<uint8_t*>(m_reg_data.PeekData(reg_info->byte_offset, reg_byte_size)), reg_byte_size, '\xcc'); - bool success = bytes_copied == reg_byte_size; - if (success) - { - SetRegisterIsValid(reg, true); - } - else if (bytes_copied > 0) - { - // Only set register is valid to false if we copied some bytes, else - // leave it as it was. - SetRegisterIsValid(reg, false); - } - return success; + // Invalidate if needed + InvalidateIfNeeded(false); + + const size_t reg_byte_size = reg_info->byte_size; + memcpy(const_cast<uint8_t *>( + m_reg_data.PeekData(reg_info->byte_offset, reg_byte_size)), + data.data(), std::min(data.size(), reg_byte_size)); + bool success = data.size() >= reg_byte_size; + if (success) { + SetRegisterIsValid(reg, true); + } else if (data.size() > 0) { + // Only set register is valid to false if we copied some bytes, else + // leave it as it was. + SetRegisterIsValid(reg, false); + } + return success; } -bool -GDBRemoteRegisterContext::PrivateSetRegisterValue (uint32_t reg, uint64_t new_reg_val) -{ - const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg); - if (reg_info == NULL) - return false; - - // Early in process startup, we can get a thread that has an invalid byte order - // because the process hasn't been completely set up yet (see the ctor where the - // byte order is setfrom the process). If that's the case, we can't set the - // value here. - if (m_reg_data.GetByteOrder() == eByteOrderInvalid) - { - return false; - } - - // Invalidate if needed - InvalidateIfNeeded (false); +bool GDBRemoteRegisterContext::PrivateSetRegisterValue(uint32_t reg, + uint64_t new_reg_val) { + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); + if (reg_info == NULL) + return false; - DataBufferSP buffer_sp (new DataBufferHeap (&new_reg_val, sizeof (new_reg_val))); - DataExtractor data (buffer_sp, endian::InlHostByteOrder(), sizeof (void*)); + // Early in process startup, we can get a thread that has an invalid byte + // order + // because the process hasn't been completely set up yet (see the ctor where + // the + // byte order is setfrom the process). If that's the case, we can't set the + // value here. + if (m_reg_data.GetByteOrder() == eByteOrderInvalid) { + return false; + } - // If our register context and our register info disagree, which should never happen, don't - // overwrite past the end of the buffer. - if (m_reg_data.GetByteSize() < reg_info->byte_offset + reg_info->byte_size) - return false; + // Invalidate if needed + InvalidateIfNeeded(false); - // Grab a pointer to where we are going to put this register - uint8_t *dst = const_cast<uint8_t*>(m_reg_data.PeekData(reg_info->byte_offset, reg_info->byte_size)); + DataBufferSP buffer_sp(new DataBufferHeap(&new_reg_val, sizeof(new_reg_val))); + DataExtractor data(buffer_sp, endian::InlHostByteOrder(), sizeof(void *)); - if (dst == NULL) - return false; + // If our register context and our register info disagree, which should never + // happen, don't + // overwrite past the end of the buffer. + if (m_reg_data.GetByteSize() < reg_info->byte_offset + reg_info->byte_size) + return false; + // Grab a pointer to where we are going to put this register + uint8_t *dst = const_cast<uint8_t *>( + m_reg_data.PeekData(reg_info->byte_offset, reg_info->byte_size)); - if (data.CopyByteOrderedData (0, // src offset - reg_info->byte_size, // src length - dst, // dst - reg_info->byte_size, // dst length - m_reg_data.GetByteOrder())) // dst byte order - { - SetRegisterIsValid (reg, true); - return true; - } + if (dst == NULL) return false; + + if (data.CopyByteOrderedData(0, // src offset + reg_info->byte_size, // src length + dst, // dst + reg_info->byte_size, // dst length + m_reg_data.GetByteOrder())) // dst byte order + { + SetRegisterIsValid(reg, true); + return true; + } + return false; } // Helper function for GDBRemoteRegisterContext::ReadRegisterBytes(). -bool -GDBRemoteRegisterContext::GetPrimordialRegister(const RegisterInfo *reg_info, - GDBRemoteCommunicationClient &gdb_comm) -{ - const uint32_t lldb_reg = reg_info->kinds[eRegisterKindLLDB]; - const uint32_t remote_reg = reg_info->kinds[eRegisterKindProcessPlugin]; - StringExtractorGDBRemote response; - if (gdb_comm.ReadRegister(m_thread.GetProtocolID(), remote_reg, response)) - return PrivateSetRegisterValue (lldb_reg, response); - return false; +bool GDBRemoteRegisterContext::GetPrimordialRegister( + const RegisterInfo *reg_info, GDBRemoteCommunicationClient &gdb_comm) { + const uint32_t lldb_reg = reg_info->kinds[eRegisterKindLLDB]; + const uint32_t remote_reg = reg_info->kinds[eRegisterKindProcessPlugin]; + StringExtractorGDBRemote response; + if (DataBufferSP buffer_sp = + gdb_comm.ReadRegister(m_thread.GetProtocolID(), remote_reg)) + return PrivateSetRegisterValue( + lldb_reg, llvm::ArrayRef<uint8_t>(buffer_sp->GetBytes(), + buffer_sp->GetByteSize())); + return false; } -bool -GDBRemoteRegisterContext::ReadRegisterBytes (const RegisterInfo *reg_info, DataExtractor &data) -{ - ExecutionContext exe_ctx (CalculateThread()); +bool GDBRemoteRegisterContext::ReadRegisterBytes(const RegisterInfo *reg_info, + DataExtractor &data) { + ExecutionContext exe_ctx(CalculateThread()); - Process *process = exe_ctx.GetProcessPtr(); - Thread *thread = exe_ctx.GetThreadPtr(); - if (process == NULL || thread == NULL) - return false; - - GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote()); + Process *process = exe_ctx.GetProcessPtr(); + Thread *thread = exe_ctx.GetThreadPtr(); + if (process == NULL || thread == NULL) + return false; - InvalidateIfNeeded(false); + GDBRemoteCommunicationClient &gdb_comm( + ((ProcessGDBRemote *)process)->GetGDBRemote()); - const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + InvalidateIfNeeded(false); - if (!GetRegisterIsValid(reg)) - { - if (m_read_all_at_once) - { - StringExtractorGDBRemote response; - if (!gdb_comm.ReadAllRegisters(m_thread.GetProtocolID(), response)) - return false; - if (response.IsNormalResponse()) - if (response.GetHexBytes(const_cast<void *>(reinterpret_cast<const void *>(m_reg_data.GetDataStart())), - m_reg_data.GetByteSize(), '\xcc') == m_reg_data.GetByteSize()) - SetAllRegisterValid (true); - } - else if (reg_info->value_regs) - { - // Process this composite register request by delegating to the constituent - // primordial registers. - - // Index of the primordial register. - bool success = true; - for (uint32_t idx = 0; success; ++idx) - { - const uint32_t prim_reg = reg_info->value_regs[idx]; - if (prim_reg == LLDB_INVALID_REGNUM) - break; - // We have a valid primordial register as our constituent. - // Grab the corresponding register info. - const RegisterInfo *prim_reg_info = GetRegisterInfoAtIndex(prim_reg); - if (prim_reg_info == NULL) - success = false; - else - { - // Read the containing register if it hasn't already been read - if (!GetRegisterIsValid(prim_reg)) - success = GetPrimordialRegister(prim_reg_info, gdb_comm); - } - } + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - if (success) - { - // If we reach this point, all primordial register requests have succeeded. - // Validate this composite register. - SetRegisterIsValid (reg_info, true); - } + if (!GetRegisterIsValid(reg)) { + if (m_read_all_at_once) { + if (DataBufferSP buffer_sp = + gdb_comm.ReadAllRegisters(m_thread.GetProtocolID())) { + memcpy(const_cast<uint8_t *>(m_reg_data.GetDataStart()), + buffer_sp->GetBytes(), + std::min(buffer_sp->GetByteSize(), m_reg_data.GetByteSize())); + if (buffer_sp->GetByteSize() >= m_reg_data.GetByteSize()) { + SetAllRegisterValid(true); + return true; } - else - { - // Get each register individually - GetPrimordialRegister(reg_info, gdb_comm); + } + return false; + } + if (reg_info->value_regs) { + // Process this composite register request by delegating to the + // constituent + // primordial registers. + + // Index of the primordial register. + bool success = true; + for (uint32_t idx = 0; success; ++idx) { + const uint32_t prim_reg = reg_info->value_regs[idx]; + if (prim_reg == LLDB_INVALID_REGNUM) + break; + // We have a valid primordial register as our constituent. + // Grab the corresponding register info. + const RegisterInfo *prim_reg_info = GetRegisterInfoAtIndex(prim_reg); + if (prim_reg_info == NULL) + success = false; + else { + // Read the containing register if it hasn't already been read + if (!GetRegisterIsValid(prim_reg)) + success = GetPrimordialRegister(prim_reg_info, gdb_comm); } - - // Make sure we got a valid register value after reading it - if (!GetRegisterIsValid(reg)) - return false; + } + + if (success) { + // If we reach this point, all primordial register requests have + // succeeded. + // Validate this composite register. + SetRegisterIsValid(reg_info, true); + } + } else { + // Get each register individually + GetPrimordialRegister(reg_info, gdb_comm); } - if (&data != &m_reg_data) - { -#if defined (LLDB_CONFIGURATION_DEBUG) - assert (m_reg_data.GetByteSize() >= reg_info->byte_offset + reg_info->byte_size); -#endif - // If our register context and our register info disagree, which should never happen, don't - // read past the end of the buffer. - if (m_reg_data.GetByteSize() < reg_info->byte_offset + reg_info->byte_size) - return false; - - // If we aren't extracting into our own buffer (which - // only happens when this function is called from - // ReadRegisterValue(uint32_t, Scalar&)) then - // we transfer bytes from our buffer into the data - // buffer that was passed in - - data.SetByteOrder (m_reg_data.GetByteOrder()); - data.SetData (m_reg_data, reg_info->byte_offset, reg_info->byte_size); - } - return true; -} + // Make sure we got a valid register value after reading it + if (!GetRegisterIsValid(reg)) + return false; + } -bool -GDBRemoteRegisterContext::WriteRegister (const RegisterInfo *reg_info, - const RegisterValue &value) -{ - DataExtractor data; - if (value.GetData (data)) - return WriteRegisterBytes (reg_info, data, 0); - return false; + if (&data != &m_reg_data) { +#if defined(LLDB_CONFIGURATION_DEBUG) + assert(m_reg_data.GetByteSize() >= + reg_info->byte_offset + reg_info->byte_size); +#endif + // If our register context and our register info disagree, which should + // never happen, don't + // read past the end of the buffer. + if (m_reg_data.GetByteSize() < reg_info->byte_offset + reg_info->byte_size) + return false; + + // If we aren't extracting into our own buffer (which + // only happens when this function is called from + // ReadRegisterValue(uint32_t, Scalar&)) then + // we transfer bytes from our buffer into the data + // buffer that was passed in + + data.SetByteOrder(m_reg_data.GetByteOrder()); + data.SetData(m_reg_data, reg_info->byte_offset, reg_info->byte_size); + } + return true; } -// Helper function for GDBRemoteRegisterContext::WriteRegisterBytes(). -bool -GDBRemoteRegisterContext::SetPrimordialRegister(const RegisterInfo *reg_info, - GDBRemoteCommunicationClient &gdb_comm) -{ - StreamString packet; - StringExtractorGDBRemote response; - const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - packet.Printf ("P%x=", reg_info->kinds[eRegisterKindProcessPlugin]); - packet.PutBytesAsRawHex8 (m_reg_data.PeekData(reg_info->byte_offset, reg_info->byte_size), - reg_info->byte_size, - endian::InlHostByteOrder(), - endian::InlHostByteOrder()); - - if (gdb_comm.GetThreadSuffixSupported()) - packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID()); - - // Invalidate just this register - SetRegisterIsValid(reg, false); - if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), - packet.GetString().size(), - response, - false) == GDBRemoteCommunication::PacketResult::Success) - { - if (response.IsOKResponse()) - return true; - } - return false; +bool GDBRemoteRegisterContext::WriteRegister(const RegisterInfo *reg_info, + const RegisterValue &value) { + DataExtractor data; + if (value.GetData(data)) + return WriteRegisterBytes(reg_info, data, 0); + return false; } -void -GDBRemoteRegisterContext::SyncThreadState(Process *process) -{ - // NB. We assume our caller has locked the sequence mutex. - - GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *) process)->GetGDBRemote()); - if (!gdb_comm.GetSyncThreadStateSupported()) - return; - - StreamString packet; - StringExtractorGDBRemote response; - packet.Printf ("QSyncThreadState:%4.4" PRIx64 ";", m_thread.GetProtocolID()); - if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), - packet.GetString().size(), - response, - false) == GDBRemoteCommunication::PacketResult::Success) - { - if (response.IsOKResponse()) - InvalidateAllRegisters(); - } +// Helper function for GDBRemoteRegisterContext::WriteRegisterBytes(). +bool GDBRemoteRegisterContext::SetPrimordialRegister( + const RegisterInfo *reg_info, GDBRemoteCommunicationClient &gdb_comm) { + StreamString packet; + StringExtractorGDBRemote response; + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + // Invalidate just this register + SetRegisterIsValid(reg, false); + + return gdb_comm.WriteRegister( + m_thread.GetProtocolID(), reg_info->kinds[eRegisterKindProcessPlugin], + {m_reg_data.PeekData(reg_info->byte_offset, reg_info->byte_size), + reg_info->byte_size}); } -bool -GDBRemoteRegisterContext::WriteRegisterBytes (const RegisterInfo *reg_info, DataExtractor &data, uint32_t data_offset) -{ - ExecutionContext exe_ctx (CalculateThread()); +bool GDBRemoteRegisterContext::WriteRegisterBytes(const RegisterInfo *reg_info, + DataExtractor &data, + uint32_t data_offset) { + ExecutionContext exe_ctx(CalculateThread()); - Process *process = exe_ctx.GetProcessPtr(); - Thread *thread = exe_ctx.GetThreadPtr(); - if (process == NULL || thread == NULL) - return false; - - GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote()); -// FIXME: This check isn't right because IsRunning checks the Public state, but this -// is work you need to do - for instance in ShouldStop & friends - before the public -// state has been changed. -// if (gdb_comm.IsRunning()) -// return false; + Process *process = exe_ctx.GetProcessPtr(); + Thread *thread = exe_ctx.GetThreadPtr(); + if (process == NULL || thread == NULL) + return false; + GDBRemoteCommunicationClient &gdb_comm( + ((ProcessGDBRemote *)process)->GetGDBRemote()); -#if defined (LLDB_CONFIGURATION_DEBUG) - assert (m_reg_data.GetByteSize() >= reg_info->byte_offset + reg_info->byte_size); +#if defined(LLDB_CONFIGURATION_DEBUG) + assert(m_reg_data.GetByteSize() >= + reg_info->byte_offset + reg_info->byte_size); #endif - // If our register context and our register info disagree, which should never happen, don't - // overwrite past the end of the buffer. - if (m_reg_data.GetByteSize() < reg_info->byte_offset + reg_info->byte_size) - return false; + // If our register context and our register info disagree, which should never + // happen, don't + // overwrite past the end of the buffer. + if (m_reg_data.GetByteSize() < reg_info->byte_offset + reg_info->byte_size) + return false; - // Grab a pointer to where we are going to put this register - uint8_t *dst = const_cast<uint8_t*>(m_reg_data.PeekData(reg_info->byte_offset, reg_info->byte_size)); + // Grab a pointer to where we are going to put this register + uint8_t *dst = const_cast<uint8_t *>( + m_reg_data.PeekData(reg_info->byte_offset, reg_info->byte_size)); - if (dst == NULL) - return false; + if (dst == NULL) + return false; + if (data.CopyByteOrderedData(data_offset, // src offset + reg_info->byte_size, // src length + dst, // dst + reg_info->byte_size, // dst length + m_reg_data.GetByteOrder())) // dst byte order + { + GDBRemoteClientBase::Lock lock(gdb_comm, false); + if (lock) { + if (m_read_all_at_once) { + // Invalidate all register values + InvalidateIfNeeded(true); + + // Set all registers in one packet + if (gdb_comm.WriteAllRegisters( + m_thread.GetProtocolID(), + {m_reg_data.GetDataStart(), size_t(m_reg_data.GetByteSize())})) - if (data.CopyByteOrderedData (data_offset, // src offset - reg_info->byte_size, // src length - dst, // dst - reg_info->byte_size, // dst length - m_reg_data.GetByteOrder())) // dst byte order - { - Mutex::Locker locker; - if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for write register.")) { - const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported(); - ProcessSP process_sp (m_thread.GetProcess()); - if (thread_suffix_supported || static_cast<ProcessGDBRemote *>(process_sp.get())->GetGDBRemote().SetCurrentThread(m_thread.GetProtocolID())) - { - StreamString packet; - StringExtractorGDBRemote response; - - if (m_read_all_at_once) - { - // Set all registers in one packet - packet.PutChar ('G'); - packet.PutBytesAsRawHex8 (m_reg_data.GetDataStart(), - m_reg_data.GetByteSize(), - endian::InlHostByteOrder(), - endian::InlHostByteOrder()); - - if (thread_suffix_supported) - packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID()); - - // Invalidate all register values - InvalidateIfNeeded (true); - - if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), - packet.GetString().size(), - response, - false) == GDBRemoteCommunication::PacketResult::Success) - { - SetAllRegisterValid (false); - if (response.IsOKResponse()) - { - return true; - } - } - } - else - { - bool success = true; - - if (reg_info->value_regs) - { - // This register is part of another register. In this case we read the actual - // register data for any "value_regs", and once all that data is read, we will - // have enough data in our register context bytes for the value of this register - - // Invalidate this composite register first. - - for (uint32_t idx = 0; success; ++idx) - { - const uint32_t reg = reg_info->value_regs[idx]; - if (reg == LLDB_INVALID_REGNUM) - break; - // We have a valid primordial register as our constituent. - // Grab the corresponding register info. - const RegisterInfo *value_reg_info = GetRegisterInfoAtIndex(reg); - if (value_reg_info == NULL) - success = false; - else - success = SetPrimordialRegister(value_reg_info, gdb_comm); - } - } - else - { - // This is an actual register, write it - success = SetPrimordialRegister(reg_info, gdb_comm); - } - - // Check if writing this register will invalidate any other register values? - // If so, invalidate them - if (reg_info->invalidate_regs) - { - for (uint32_t idx = 0, reg = reg_info->invalidate_regs[0]; - reg != LLDB_INVALID_REGNUM; - reg = reg_info->invalidate_regs[++idx]) - { - SetRegisterIsValid(reg, false); - } - } - - return success; - } - } + SetAllRegisterValid(false); + return true; } - else - { - Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_THREAD | GDBR_LOG_PACKETS)); - if (log) - { - if (log->GetVerbose()) - { - StreamString strm; - gdb_comm.DumpHistory(strm); - log->Printf("error: failed to get packet sequence mutex, not sending write register for \"%s\":\n%s", reg_info->name, strm.GetData()); - } - else - log->Printf("error: failed to get packet sequence mutex, not sending write register for \"%s\"", reg_info->name); - } + } else { + bool success = true; + + if (reg_info->value_regs) { + // This register is part of another register. In this case we read the + // actual + // register data for any "value_regs", and once all that data is read, + // we will + // have enough data in our register context bytes for the value of + // this register + + // Invalidate this composite register first. + + for (uint32_t idx = 0; success; ++idx) { + const uint32_t reg = reg_info->value_regs[idx]; + if (reg == LLDB_INVALID_REGNUM) + break; + // We have a valid primordial register as our constituent. + // Grab the corresponding register info. + const RegisterInfo *value_reg_info = GetRegisterInfoAtIndex(reg); + if (value_reg_info == NULL) + success = false; + else + success = SetPrimordialRegister(value_reg_info, gdb_comm); + } + } else { + // This is an actual register, write it + success = SetPrimordialRegister(reg_info, gdb_comm); + } + + // Check if writing this register will invalidate any other register + // values? + // If so, invalidate them + if (reg_info->invalidate_regs) { + for (uint32_t idx = 0, reg = reg_info->invalidate_regs[0]; + reg != LLDB_INVALID_REGNUM; + reg = reg_info->invalidate_regs[++idx]) { + SetRegisterIsValid(reg, false); + } } + + return success; + } + } else { + Log *log(ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(GDBR_LOG_THREAD | + GDBR_LOG_PACKETS)); + if (log) { + if (log->GetVerbose()) { + StreamString strm; + gdb_comm.DumpHistory(strm); + log->Printf("error: failed to get packet sequence mutex, not sending " + "write register for \"%s\":\n%s", + reg_info->name, strm.GetData()); + } else + log->Printf("error: failed to get packet sequence mutex, not sending " + "write register for \"%s\"", + reg_info->name); + } } + } + return false; +} + +bool GDBRemoteRegisterContext::ReadAllRegisterValues( + RegisterCheckpoint ®_checkpoint) { + ExecutionContext exe_ctx(CalculateThread()); + + Process *process = exe_ctx.GetProcessPtr(); + Thread *thread = exe_ctx.GetThreadPtr(); + if (process == NULL || thread == NULL) return false; + + GDBRemoteCommunicationClient &gdb_comm( + ((ProcessGDBRemote *)process)->GetGDBRemote()); + + uint32_t save_id = 0; + if (gdb_comm.SaveRegisterState(thread->GetProtocolID(), save_id)) { + reg_checkpoint.SetID(save_id); + reg_checkpoint.GetData().reset(); + return true; + } else { + reg_checkpoint.SetID(0); // Invalid save ID is zero + return ReadAllRegisterValues(reg_checkpoint.GetData()); + } } -bool -GDBRemoteRegisterContext::ReadAllRegisterValues (RegisterCheckpoint ®_checkpoint) -{ - ExecutionContext exe_ctx (CalculateThread()); - +bool GDBRemoteRegisterContext::WriteAllRegisterValues( + const RegisterCheckpoint ®_checkpoint) { + uint32_t save_id = reg_checkpoint.GetID(); + if (save_id != 0) { + ExecutionContext exe_ctx(CalculateThread()); + Process *process = exe_ctx.GetProcessPtr(); Thread *thread = exe_ctx.GetThreadPtr(); if (process == NULL || thread == NULL) - return false; - - GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote()); - - uint32_t save_id = 0; - if (gdb_comm.SaveRegisterState(thread->GetProtocolID(), save_id)) - { - reg_checkpoint.SetID(save_id); - reg_checkpoint.GetData().reset(); - return true; - } - else - { - reg_checkpoint.SetID(0); // Invalid save ID is zero - return ReadAllRegisterValues(reg_checkpoint.GetData()); - } -} + return false; -bool -GDBRemoteRegisterContext::WriteAllRegisterValues (const RegisterCheckpoint ®_checkpoint) -{ - uint32_t save_id = reg_checkpoint.GetID(); - if (save_id != 0) - { - ExecutionContext exe_ctx (CalculateThread()); - - Process *process = exe_ctx.GetProcessPtr(); - Thread *thread = exe_ctx.GetThreadPtr(); - if (process == NULL || thread == NULL) - return false; - - GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote()); - - return gdb_comm.RestoreRegisterState(m_thread.GetProtocolID(), save_id); - } - else - { - return WriteAllRegisterValues(reg_checkpoint.GetData()); - } + GDBRemoteCommunicationClient &gdb_comm( + ((ProcessGDBRemote *)process)->GetGDBRemote()); + + return gdb_comm.RestoreRegisterState(m_thread.GetProtocolID(), save_id); + } else { + return WriteAllRegisterValues(reg_checkpoint.GetData()); + } } -bool -GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) -{ - ExecutionContext exe_ctx (CalculateThread()); +bool GDBRemoteRegisterContext::ReadAllRegisterValues( + lldb::DataBufferSP &data_sp) { + ExecutionContext exe_ctx(CalculateThread()); - Process *process = exe_ctx.GetProcessPtr(); - Thread *thread = exe_ctx.GetThreadPtr(); - if (process == NULL || thread == NULL) - return false; + Process *process = exe_ctx.GetProcessPtr(); + Thread *thread = exe_ctx.GetThreadPtr(); + if (process == NULL || thread == NULL) + return false; - GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote()); + GDBRemoteCommunicationClient &gdb_comm( + ((ProcessGDBRemote *)process)->GetGDBRemote()); - StringExtractorGDBRemote response; + const bool use_g_packet = + gdb_comm.AvoidGPackets((ProcessGDBRemote *)process) == false; - const bool use_g_packet = gdb_comm.AvoidGPackets ((ProcessGDBRemote *)process) == false; + GDBRemoteClientBase::Lock lock(gdb_comm, false); + if (lock) { + if (gdb_comm.SyncThreadState(m_thread.GetProtocolID())) + InvalidateAllRegisters(); - Mutex::Locker locker; - if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for read all registers.")) - { - SyncThreadState(process); - - char packet[32]; - const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported(); - ProcessSP process_sp (m_thread.GetProcess()); - if (thread_suffix_supported || static_cast<ProcessGDBRemote *>(process_sp.get())->GetGDBRemote().SetCurrentThread(m_thread.GetProtocolID())) - { - int packet_len = 0; - if (thread_suffix_supported) - packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4" PRIx64, m_thread.GetProtocolID()); - else - packet_len = ::snprintf (packet, sizeof(packet), "g"); - assert (packet_len < ((int)sizeof(packet) - 1)); - - if (use_g_packet && gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false) == GDBRemoteCommunication::PacketResult::Success) - { - int packet_len = 0; - if (thread_suffix_supported) - packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4" PRIx64, m_thread.GetProtocolID()); - else - packet_len = ::snprintf (packet, sizeof(packet), "g"); - assert (packet_len < ((int)sizeof(packet) - 1)); - - if (gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false) == GDBRemoteCommunication::PacketResult::Success) - { - if (response.IsErrorResponse()) - return false; - - std::string &response_str = response.GetStringRef(); - if (isxdigit(response_str[0])) - { - response_str.insert(0, 1, 'G'); - if (thread_suffix_supported) - { - char thread_id_cstr[64]; - ::snprintf (thread_id_cstr, sizeof(thread_id_cstr), ";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID()); - response_str.append (thread_id_cstr); - } - data_sp.reset (new DataBufferHeap (response_str.c_str(), response_str.size())); - return true; - } - } - } - else - { - // For the use_g_packet == false case, we're going to read each register - // individually and store them as binary data in a buffer instead of as ascii - // characters. - const RegisterInfo *reg_info; - - // data_sp will take ownership of this DataBufferHeap pointer soon. - DataBufferSP reg_ctx(new DataBufferHeap(m_reg_info.GetRegisterDataByteSize(), 0)); - - for (uint32_t i = 0; (reg_info = GetRegisterInfoAtIndex (i)) != NULL; i++) - { - if (reg_info->value_regs) // skip registers that are slices of real registers - continue; - ReadRegisterBytes (reg_info, m_reg_data); - // ReadRegisterBytes saves the contents of the register in to the m_reg_data buffer - } - memcpy (reg_ctx->GetBytes(), m_reg_data.GetDataStart(), m_reg_info.GetRegisterDataByteSize()); - - data_sp = reg_ctx; - return true; - } - } - } - else - { + if (use_g_packet && + (data_sp = gdb_comm.ReadAllRegisters(m_thread.GetProtocolID()))) + return true; - Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_THREAD | GDBR_LOG_PACKETS)); - if (log) - { - if (log->GetVerbose()) - { - StreamString strm; - gdb_comm.DumpHistory(strm); - log->Printf("error: failed to get packet sequence mutex, not sending read all registers:\n%s", strm.GetData()); - } - else - log->Printf("error: failed to get packet sequence mutex, not sending read all registers"); - } + // We're going to read each register + // individually and store them as binary data in a buffer. + const RegisterInfo *reg_info; + + for (uint32_t i = 0; (reg_info = GetRegisterInfoAtIndex(i)) != NULL; i++) { + if (reg_info + ->value_regs) // skip registers that are slices of real registers + continue; + ReadRegisterBytes(reg_info, m_reg_data); + // ReadRegisterBytes saves the contents of the register in to the + // m_reg_data buffer } + data_sp.reset(new DataBufferHeap(m_reg_data.GetDataStart(), + m_reg_info.GetRegisterDataByteSize())); + return true; + } else { + + Log *log(ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(GDBR_LOG_THREAD | + GDBR_LOG_PACKETS)); + if (log) { + if (log->GetVerbose()) { + StreamString strm; + gdb_comm.DumpHistory(strm); + log->Printf("error: failed to get packet sequence mutex, not sending " + "read all registers:\n%s", + strm.GetData()); + } else + log->Printf("error: failed to get packet sequence mutex, not sending " + "read all registers"); + } + } - data_sp.reset(); - return false; + data_sp.reset(); + return false; } -bool -GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) -{ - if (!data_sp || data_sp->GetBytes() == NULL || data_sp->GetByteSize() == 0) - return false; +bool GDBRemoteRegisterContext::WriteAllRegisterValues( + const lldb::DataBufferSP &data_sp) { + if (!data_sp || data_sp->GetBytes() == NULL || data_sp->GetByteSize() == 0) + return false; - ExecutionContext exe_ctx (CalculateThread()); + ExecutionContext exe_ctx(CalculateThread()); - Process *process = exe_ctx.GetProcessPtr(); - Thread *thread = exe_ctx.GetThreadPtr(); - if (process == NULL || thread == NULL) - return false; + Process *process = exe_ctx.GetProcessPtr(); + Thread *thread = exe_ctx.GetThreadPtr(); + if (process == NULL || thread == NULL) + return false; - GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote()); + GDBRemoteCommunicationClient &gdb_comm( + ((ProcessGDBRemote *)process)->GetGDBRemote()); - const bool use_g_packet = gdb_comm.AvoidGPackets ((ProcessGDBRemote *)process) == false; + const bool use_g_packet = + gdb_comm.AvoidGPackets((ProcessGDBRemote *)process) == false; - StringExtractorGDBRemote response; - Mutex::Locker locker; - if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for write all registers.")) - { - const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported(); - ProcessSP process_sp (m_thread.GetProcess()); - if (thread_suffix_supported || static_cast<ProcessGDBRemote *>(process_sp.get())->GetGDBRemote().SetCurrentThread(m_thread.GetProtocolID())) - { - // The data_sp contains the entire G response packet including the - // G, and if the thread suffix is supported, it has the thread suffix - // as well. - const char *G_packet = (const char *)data_sp->GetBytes(); - size_t G_packet_len = data_sp->GetByteSize(); - if (use_g_packet - && gdb_comm.SendPacketAndWaitForResponse (G_packet, - G_packet_len, - response, - false) == GDBRemoteCommunication::PacketResult::Success) - { - // The data_sp contains the entire G response packet including the - // G, and if the thread suffix is supported, it has the thread suffix - // as well. - const char *G_packet = (const char *)data_sp->GetBytes(); - size_t G_packet_len = data_sp->GetByteSize(); - if (gdb_comm.SendPacketAndWaitForResponse (G_packet, - G_packet_len, - response, - false) == GDBRemoteCommunication::PacketResult::Success) - { - if (response.IsOKResponse()) - return true; - else if (response.IsErrorResponse()) - { - uint32_t num_restored = 0; - // We need to manually go through all of the registers and - // restore them manually - - response.GetStringRef().assign (G_packet, G_packet_len); - response.SetFilePos(1); // Skip the leading 'G' - - // G_packet_len is hex-ascii characters plus prefix 'G' plus suffix thread specifier. - // This means buffer will be a little more than 2x larger than necessary but we resize - // it down once we've extracted all hex ascii chars from the packet. - DataBufferHeap buffer (G_packet_len, 0); - - const uint32_t bytes_extracted = response.GetHexBytes (buffer.GetBytes(), - buffer.GetByteSize(), - '\xcc'); - - DataExtractor restore_data (buffer.GetBytes(), - buffer.GetByteSize(), - m_reg_data.GetByteOrder(), - m_reg_data.GetAddressByteSize()); - - if (bytes_extracted < restore_data.GetByteSize()) - restore_data.SetData(restore_data.GetDataStart(), bytes_extracted, m_reg_data.GetByteOrder()); - - const RegisterInfo *reg_info; - - // The g packet contents may either include the slice registers (registers defined in - // terms of other registers, e.g. eax is a subset of rax) or not. The slice registers - // should NOT be in the g packet, but some implementations may incorrectly include them. - // - // If the slice registers are included in the packet, we must step over the slice registers - // when parsing the packet -- relying on the RegisterInfo byte_offset field would be incorrect. - // If the slice registers are not included, then using the byte_offset values into the - // data buffer is the best way to find individual register values. - - uint64_t size_including_slice_registers = 0; - uint64_t size_not_including_slice_registers = 0; - uint64_t size_by_highest_offset = 0; - - for (uint32_t reg_idx=0; (reg_info = GetRegisterInfoAtIndex (reg_idx)) != NULL; ++reg_idx) - { - size_including_slice_registers += reg_info->byte_size; - if (reg_info->value_regs == NULL) - size_not_including_slice_registers += reg_info->byte_size; - if (reg_info->byte_offset >= size_by_highest_offset) - size_by_highest_offset = reg_info->byte_offset + reg_info->byte_size; - } - - bool use_byte_offset_into_buffer; - if (size_by_highest_offset == restore_data.GetByteSize()) - { - // The size of the packet agrees with the highest offset: + size in the register file - use_byte_offset_into_buffer = true; - } - else if (size_not_including_slice_registers == restore_data.GetByteSize()) - { - // The size of the packet is the same as concatenating all of the registers sequentially, - // skipping the slice registers - use_byte_offset_into_buffer = true; - } - else if (size_including_slice_registers == restore_data.GetByteSize()) - { - // The slice registers are present in the packet (when they shouldn't be). - // Don't try to use the RegisterInfo byte_offset into the restore_data, it will - // point to the wrong place. - use_byte_offset_into_buffer = false; - } - else { - // None of our expected sizes match the actual g packet data we're looking at. - // The most conservative approach here is to use the running total byte offset. - use_byte_offset_into_buffer = false; - } - - // In case our register definitions don't include the correct offsets, - // keep track of the size of each reg & compute offset based on that. - uint32_t running_byte_offset = 0; - for (uint32_t reg_idx=0; (reg_info = GetRegisterInfoAtIndex (reg_idx)) != NULL; ++reg_idx, running_byte_offset += reg_info->byte_size) - { - // Skip composite aka slice registers (e.g. eax is a slice of rax). - if (reg_info->value_regs) - continue; - - const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - - uint32_t register_offset; - if (use_byte_offset_into_buffer) - { - register_offset = reg_info->byte_offset; - } - else - { - register_offset = running_byte_offset; - } - - // Only write down the registers that need to be written - // if we are going to be doing registers individually. - bool write_reg = true; - const uint32_t reg_byte_size = reg_info->byte_size; - - const char *restore_src = (const char *)restore_data.PeekData(register_offset, reg_byte_size); - if (restore_src) - { - StreamString packet; - packet.Printf ("P%x=", reg_info->kinds[eRegisterKindProcessPlugin]); - packet.PutBytesAsRawHex8 (restore_src, - reg_byte_size, - endian::InlHostByteOrder(), - endian::InlHostByteOrder()); - - if (thread_suffix_supported) - packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID()); - - SetRegisterIsValid(reg, false); - if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), - packet.GetString().size(), - response, - false) == GDBRemoteCommunication::PacketResult::Success) - { - const char *current_src = (const char *)m_reg_data.PeekData(register_offset, reg_byte_size); - if (current_src) - write_reg = memcmp (current_src, restore_src, reg_byte_size) != 0; - } - - if (write_reg) - { - StreamString packet; - packet.Printf ("P%x=", reg_info->kinds[eRegisterKindProcessPlugin]); - packet.PutBytesAsRawHex8 (restore_src, - reg_byte_size, - endian::InlHostByteOrder(), - endian::InlHostByteOrder()); - - if (thread_suffix_supported) - packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID()); - - SetRegisterIsValid(reg, false); - if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), - packet.GetString().size(), - response, - false) == GDBRemoteCommunication::PacketResult::Success) - { - if (response.IsOKResponse()) - ++num_restored; - } - } - } - } - return num_restored > 0; - } - } - } - else - { - // For the use_g_packet == false case, we're going to write each register - // individually. The data buffer is binary data in this case, instead of - // ascii characters. - - bool arm64_debugserver = false; - if (m_thread.GetProcess().get()) - { - const ArchSpec &arch = m_thread.GetProcess()->GetTarget().GetArchitecture(); - if (arch.IsValid() - && arch.GetMachine() == llvm::Triple::aarch64 - && arch.GetTriple().getVendor() == llvm::Triple::Apple - && arch.GetTriple().getOS() == llvm::Triple::IOS) - { - arm64_debugserver = true; - } - } - uint32_t num_restored = 0; - const RegisterInfo *reg_info; - for (uint32_t i = 0; (reg_info = GetRegisterInfoAtIndex (i)) != NULL; i++) - { - if (reg_info->value_regs) // skip registers that are slices of real registers - continue; - // Skip the fpsr and fpcr floating point status/control register writing to - // work around a bug in an older version of debugserver that would lead to - // register context corruption when writing fpsr/fpcr. - if (arm64_debugserver && - (strcmp (reg_info->name, "fpsr") == 0 || strcmp (reg_info->name, "fpcr") == 0)) - { - continue; - } - StreamString packet; - packet.Printf ("P%x=", reg_info->kinds[eRegisterKindProcessPlugin]); - packet.PutBytesAsRawHex8 (data_sp->GetBytes() + reg_info->byte_offset, reg_info->byte_size, endian::InlHostByteOrder(), endian::InlHostByteOrder()); - if (thread_suffix_supported) - packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID()); - - SetRegisterIsValid(reg_info, false); - if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), - packet.GetString().size(), - response, - false) == GDBRemoteCommunication::PacketResult::Success) - { - if (response.IsOKResponse()) - ++num_restored; - } - } - return num_restored > 0; - } + GDBRemoteClientBase::Lock lock(gdb_comm, false); + if (lock) { + // The data_sp contains the G response packet. + if (use_g_packet) { + if (gdb_comm.WriteAllRegisters( + m_thread.GetProtocolID(), + {data_sp->GetBytes(), size_t(data_sp->GetByteSize())})) + return true; + + uint32_t num_restored = 0; + // We need to manually go through all of the registers and + // restore them manually + DataExtractor restore_data(data_sp, m_reg_data.GetByteOrder(), + m_reg_data.GetAddressByteSize()); + + const RegisterInfo *reg_info; + + // The g packet contents may either include the slice registers (registers + // defined in + // terms of other registers, e.g. eax is a subset of rax) or not. The + // slice registers + // should NOT be in the g packet, but some implementations may incorrectly + // include them. + // + // If the slice registers are included in the packet, we must step over + // the slice registers + // when parsing the packet -- relying on the RegisterInfo byte_offset + // field would be incorrect. + // If the slice registers are not included, then using the byte_offset + // values into the + // data buffer is the best way to find individual register values. + + uint64_t size_including_slice_registers = 0; + uint64_t size_not_including_slice_registers = 0; + uint64_t size_by_highest_offset = 0; + + for (uint32_t reg_idx = 0; + (reg_info = GetRegisterInfoAtIndex(reg_idx)) != NULL; ++reg_idx) { + size_including_slice_registers += reg_info->byte_size; + if (reg_info->value_regs == NULL) + size_not_including_slice_registers += reg_info->byte_size; + if (reg_info->byte_offset >= size_by_highest_offset) + size_by_highest_offset = reg_info->byte_offset + reg_info->byte_size; + } + + bool use_byte_offset_into_buffer; + if (size_by_highest_offset == restore_data.GetByteSize()) { + // The size of the packet agrees with the highest offset: + size in the + // register file + use_byte_offset_into_buffer = true; + } else if (size_not_including_slice_registers == + restore_data.GetByteSize()) { + // The size of the packet is the same as concatenating all of the + // registers sequentially, + // skipping the slice registers + use_byte_offset_into_buffer = true; + } else if (size_including_slice_registers == restore_data.GetByteSize()) { + // The slice registers are present in the packet (when they shouldn't + // be). + // Don't try to use the RegisterInfo byte_offset into the restore_data, + // it will + // point to the wrong place. + use_byte_offset_into_buffer = false; + } else { + // None of our expected sizes match the actual g packet data we're + // looking at. + // The most conservative approach here is to use the running total byte + // offset. + use_byte_offset_into_buffer = false; + } + + // In case our register definitions don't include the correct offsets, + // keep track of the size of each reg & compute offset based on that. + uint32_t running_byte_offset = 0; + for (uint32_t reg_idx = 0; + (reg_info = GetRegisterInfoAtIndex(reg_idx)) != NULL; + ++reg_idx, running_byte_offset += reg_info->byte_size) { + // Skip composite aka slice registers (e.g. eax is a slice of rax). + if (reg_info->value_regs) + continue; + + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + + uint32_t register_offset; + if (use_byte_offset_into_buffer) { + register_offset = reg_info->byte_offset; + } else { + register_offset = running_byte_offset; } - } - else - { - Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_THREAD | GDBR_LOG_PACKETS)); - if (log) - { - if (log->GetVerbose()) - { - StreamString strm; - gdb_comm.DumpHistory(strm); - log->Printf("error: failed to get packet sequence mutex, not sending write all registers:\n%s", strm.GetData()); - } - else - log->Printf("error: failed to get packet sequence mutex, not sending write all registers"); + + const uint32_t reg_byte_size = reg_info->byte_size; + + const uint8_t *restore_src = + restore_data.PeekData(register_offset, reg_byte_size); + if (restore_src) { + SetRegisterIsValid(reg, false); + if (gdb_comm.WriteRegister( + m_thread.GetProtocolID(), + reg_info->kinds[eRegisterKindProcessPlugin], + {restore_src, reg_byte_size})) + ++num_restored; + } + } + return num_restored > 0; + } else { + // For the use_g_packet == false case, we're going to write each register + // individually. The data buffer is binary data in this case, instead of + // ascii characters. + + bool arm64_debugserver = false; + if (m_thread.GetProcess().get()) { + const ArchSpec &arch = + m_thread.GetProcess()->GetTarget().GetArchitecture(); + if (arch.IsValid() && arch.GetMachine() == llvm::Triple::aarch64 && + arch.GetTriple().getVendor() == llvm::Triple::Apple && + arch.GetTriple().getOS() == llvm::Triple::IOS) { + arm64_debugserver = true; } + } + uint32_t num_restored = 0; + const RegisterInfo *reg_info; + for (uint32_t i = 0; (reg_info = GetRegisterInfoAtIndex(i)) != NULL; + i++) { + if (reg_info->value_regs) // skip registers that are slices of real + // registers + continue; + // Skip the fpsr and fpcr floating point status/control register writing + // to + // work around a bug in an older version of debugserver that would lead + // to + // register context corruption when writing fpsr/fpcr. + if (arm64_debugserver && (strcmp(reg_info->name, "fpsr") == 0 || + strcmp(reg_info->name, "fpcr") == 0)) { + continue; + } + + SetRegisterIsValid(reg_info, false); + if (gdb_comm.WriteRegister(m_thread.GetProtocolID(), + reg_info->kinds[eRegisterKindProcessPlugin], + {data_sp->GetBytes() + reg_info->byte_offset, + reg_info->byte_size})) + ++num_restored; + } + return num_restored > 0; } - return false; + } else { + Log *log(ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(GDBR_LOG_THREAD | + GDBR_LOG_PACKETS)); + if (log) { + if (log->GetVerbose()) { + StreamString strm; + gdb_comm.DumpHistory(strm); + log->Printf("error: failed to get packet sequence mutex, not sending " + "write all registers:\n%s", + strm.GetData()); + } else + log->Printf("error: failed to get packet sequence mutex, not sending " + "write all registers"); + } + } + return false; } - -uint32_t -GDBRemoteRegisterContext::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num) -{ - return m_reg_info.ConvertRegisterKindToRegisterNumber (kind, num); +uint32_t GDBRemoteRegisterContext::ConvertRegisterKindToRegisterNumber( + lldb::RegisterKind kind, uint32_t num) { + return m_reg_info.ConvertRegisterKindToRegisterNumber(kind, num); } - -void -GDBRemoteDynamicRegisterInfo::HardcodeARMRegisters(bool from_scratch) -{ - // For Advanced SIMD and VFP register mapping. - static uint32_t g_d0_regs[] = { 26, 27, LLDB_INVALID_REGNUM }; // (s0, s1) - static uint32_t g_d1_regs[] = { 28, 29, LLDB_INVALID_REGNUM }; // (s2, s3) - static uint32_t g_d2_regs[] = { 30, 31, LLDB_INVALID_REGNUM }; // (s4, s5) - static uint32_t g_d3_regs[] = { 32, 33, LLDB_INVALID_REGNUM }; // (s6, s7) - static uint32_t g_d4_regs[] = { 34, 35, LLDB_INVALID_REGNUM }; // (s8, s9) - static uint32_t g_d5_regs[] = { 36, 37, LLDB_INVALID_REGNUM }; // (s10, s11) - static uint32_t g_d6_regs[] = { 38, 39, LLDB_INVALID_REGNUM }; // (s12, s13) - static uint32_t g_d7_regs[] = { 40, 41, LLDB_INVALID_REGNUM }; // (s14, s15) - static uint32_t g_d8_regs[] = { 42, 43, LLDB_INVALID_REGNUM }; // (s16, s17) - static uint32_t g_d9_regs[] = { 44, 45, LLDB_INVALID_REGNUM }; // (s18, s19) - static uint32_t g_d10_regs[] = { 46, 47, LLDB_INVALID_REGNUM }; // (s20, s21) - static uint32_t g_d11_regs[] = { 48, 49, LLDB_INVALID_REGNUM }; // (s22, s23) - static uint32_t g_d12_regs[] = { 50, 51, LLDB_INVALID_REGNUM }; // (s24, s25) - static uint32_t g_d13_regs[] = { 52, 53, LLDB_INVALID_REGNUM }; // (s26, s27) - static uint32_t g_d14_regs[] = { 54, 55, LLDB_INVALID_REGNUM }; // (s28, s29) - static uint32_t g_d15_regs[] = { 56, 57, LLDB_INVALID_REGNUM }; // (s30, s31) - static uint32_t g_q0_regs[] = { 26, 27, 28, 29, LLDB_INVALID_REGNUM }; // (d0, d1) -> (s0, s1, s2, s3) - static uint32_t g_q1_regs[] = { 30, 31, 32, 33, LLDB_INVALID_REGNUM }; // (d2, d3) -> (s4, s5, s6, s7) - static uint32_t g_q2_regs[] = { 34, 35, 36, 37, LLDB_INVALID_REGNUM }; // (d4, d5) -> (s8, s9, s10, s11) - static uint32_t g_q3_regs[] = { 38, 39, 40, 41, LLDB_INVALID_REGNUM }; // (d6, d7) -> (s12, s13, s14, s15) - static uint32_t g_q4_regs[] = { 42, 43, 44, 45, LLDB_INVALID_REGNUM }; // (d8, d9) -> (s16, s17, s18, s19) - static uint32_t g_q5_regs[] = { 46, 47, 48, 49, LLDB_INVALID_REGNUM }; // (d10, d11) -> (s20, s21, s22, s23) - static uint32_t g_q6_regs[] = { 50, 51, 52, 53, LLDB_INVALID_REGNUM }; // (d12, d13) -> (s24, s25, s26, s27) - static uint32_t g_q7_regs[] = { 54, 55, 56, 57, LLDB_INVALID_REGNUM }; // (d14, d15) -> (s28, s29, s30, s31) - static uint32_t g_q8_regs[] = { 59, 60, LLDB_INVALID_REGNUM }; // (d16, d17) - static uint32_t g_q9_regs[] = { 61, 62, LLDB_INVALID_REGNUM }; // (d18, d19) - static uint32_t g_q10_regs[] = { 63, 64, LLDB_INVALID_REGNUM }; // (d20, d21) - static uint32_t g_q11_regs[] = { 65, 66, LLDB_INVALID_REGNUM }; // (d22, d23) - static uint32_t g_q12_regs[] = { 67, 68, LLDB_INVALID_REGNUM }; // (d24, d25) - static uint32_t g_q13_regs[] = { 69, 70, LLDB_INVALID_REGNUM }; // (d26, d27) - static uint32_t g_q14_regs[] = { 71, 72, LLDB_INVALID_REGNUM }; // (d28, d29) - static uint32_t g_q15_regs[] = { 73, 74, LLDB_INVALID_REGNUM }; // (d30, d31) - - // This is our array of composite registers, with each element coming from the above register mappings. - static uint32_t *g_composites[] = { - g_d0_regs, g_d1_regs, g_d2_regs, g_d3_regs, g_d4_regs, g_d5_regs, g_d6_regs, g_d7_regs, - g_d8_regs, g_d9_regs, g_d10_regs, g_d11_regs, g_d12_regs, g_d13_regs, g_d14_regs, g_d15_regs, - g_q0_regs, g_q1_regs, g_q2_regs, g_q3_regs, g_q4_regs, g_q5_regs, g_q6_regs, g_q7_regs, - g_q8_regs, g_q9_regs, g_q10_regs, g_q11_regs, g_q12_regs, g_q13_regs, g_q14_regs, g_q15_regs - }; - +void GDBRemoteDynamicRegisterInfo::HardcodeARMRegisters(bool from_scratch) { + // For Advanced SIMD and VFP register mapping. + static uint32_t g_d0_regs[] = {26, 27, LLDB_INVALID_REGNUM}; // (s0, s1) + static uint32_t g_d1_regs[] = {28, 29, LLDB_INVALID_REGNUM}; // (s2, s3) + static uint32_t g_d2_regs[] = {30, 31, LLDB_INVALID_REGNUM}; // (s4, s5) + static uint32_t g_d3_regs[] = {32, 33, LLDB_INVALID_REGNUM}; // (s6, s7) + static uint32_t g_d4_regs[] = {34, 35, LLDB_INVALID_REGNUM}; // (s8, s9) + static uint32_t g_d5_regs[] = {36, 37, LLDB_INVALID_REGNUM}; // (s10, s11) + static uint32_t g_d6_regs[] = {38, 39, LLDB_INVALID_REGNUM}; // (s12, s13) + static uint32_t g_d7_regs[] = {40, 41, LLDB_INVALID_REGNUM}; // (s14, s15) + static uint32_t g_d8_regs[] = {42, 43, LLDB_INVALID_REGNUM}; // (s16, s17) + static uint32_t g_d9_regs[] = {44, 45, LLDB_INVALID_REGNUM}; // (s18, s19) + static uint32_t g_d10_regs[] = {46, 47, LLDB_INVALID_REGNUM}; // (s20, s21) + static uint32_t g_d11_regs[] = {48, 49, LLDB_INVALID_REGNUM}; // (s22, s23) + static uint32_t g_d12_regs[] = {50, 51, LLDB_INVALID_REGNUM}; // (s24, s25) + static uint32_t g_d13_regs[] = {52, 53, LLDB_INVALID_REGNUM}; // (s26, s27) + static uint32_t g_d14_regs[] = {54, 55, LLDB_INVALID_REGNUM}; // (s28, s29) + static uint32_t g_d15_regs[] = {56, 57, LLDB_INVALID_REGNUM}; // (s30, s31) + static uint32_t g_q0_regs[] = { + 26, 27, 28, 29, LLDB_INVALID_REGNUM}; // (d0, d1) -> (s0, s1, s2, s3) + static uint32_t g_q1_regs[] = { + 30, 31, 32, 33, LLDB_INVALID_REGNUM}; // (d2, d3) -> (s4, s5, s6, s7) + static uint32_t g_q2_regs[] = { + 34, 35, 36, 37, LLDB_INVALID_REGNUM}; // (d4, d5) -> (s8, s9, s10, s11) + static uint32_t g_q3_regs[] = { + 38, 39, 40, 41, LLDB_INVALID_REGNUM}; // (d6, d7) -> (s12, s13, s14, s15) + static uint32_t g_q4_regs[] = { + 42, 43, 44, 45, LLDB_INVALID_REGNUM}; // (d8, d9) -> (s16, s17, s18, s19) + static uint32_t g_q5_regs[] = { + 46, 47, 48, 49, + LLDB_INVALID_REGNUM}; // (d10, d11) -> (s20, s21, s22, s23) + static uint32_t g_q6_regs[] = { + 50, 51, 52, 53, + LLDB_INVALID_REGNUM}; // (d12, d13) -> (s24, s25, s26, s27) + static uint32_t g_q7_regs[] = { + 54, 55, 56, 57, + LLDB_INVALID_REGNUM}; // (d14, d15) -> (s28, s29, s30, s31) + static uint32_t g_q8_regs[] = {59, 60, LLDB_INVALID_REGNUM}; // (d16, d17) + static uint32_t g_q9_regs[] = {61, 62, LLDB_INVALID_REGNUM}; // (d18, d19) + static uint32_t g_q10_regs[] = {63, 64, LLDB_INVALID_REGNUM}; // (d20, d21) + static uint32_t g_q11_regs[] = {65, 66, LLDB_INVALID_REGNUM}; // (d22, d23) + static uint32_t g_q12_regs[] = {67, 68, LLDB_INVALID_REGNUM}; // (d24, d25) + static uint32_t g_q13_regs[] = {69, 70, LLDB_INVALID_REGNUM}; // (d26, d27) + static uint32_t g_q14_regs[] = {71, 72, LLDB_INVALID_REGNUM}; // (d28, d29) + static uint32_t g_q15_regs[] = {73, 74, LLDB_INVALID_REGNUM}; // (d30, d31) + + // This is our array of composite registers, with each element coming from the + // above register mappings. + static uint32_t *g_composites[] = { + g_d0_regs, g_d1_regs, g_d2_regs, g_d3_regs, g_d4_regs, g_d5_regs, + g_d6_regs, g_d7_regs, g_d8_regs, g_d9_regs, g_d10_regs, g_d11_regs, + g_d12_regs, g_d13_regs, g_d14_regs, g_d15_regs, g_q0_regs, g_q1_regs, + g_q2_regs, g_q3_regs, g_q4_regs, g_q5_regs, g_q6_regs, g_q7_regs, + g_q8_regs, g_q9_regs, g_q10_regs, g_q11_regs, g_q12_regs, g_q13_regs, + g_q14_regs, g_q15_regs}; + + // clang-format off static RegisterInfo g_register_infos[] = { -// NAME ALT SZ OFF ENCODING FORMAT EH_FRAME DWARF GENERIC PROCESS PLUGIN LLDB VALUE REGS INVALIDATE REGS -// ====== ====== === === ============= ============ =================== =================== ====================== ============= ==== ========== =============== - { "r0", "arg1", 4, 0, eEncodingUint, eFormatHex, { ehframe_r0, dwarf_r0, LLDB_REGNUM_GENERIC_ARG1,0, 0 }, NULL, NULL}, - { "r1", "arg2", 4, 0, eEncodingUint, eFormatHex, { ehframe_r1, dwarf_r1, LLDB_REGNUM_GENERIC_ARG2,1, 1 }, NULL, NULL}, - { "r2", "arg3", 4, 0, eEncodingUint, eFormatHex, { ehframe_r2, dwarf_r2, LLDB_REGNUM_GENERIC_ARG3,2, 2 }, NULL, NULL}, - { "r3", "arg4", 4, 0, eEncodingUint, eFormatHex, { ehframe_r3, dwarf_r3, LLDB_REGNUM_GENERIC_ARG4,3, 3 }, NULL, NULL}, - { "r4", NULL, 4, 0, eEncodingUint, eFormatHex, { ehframe_r4, dwarf_r4, LLDB_INVALID_REGNUM, 4, 4 }, NULL, NULL}, - { "r5", NULL, 4, 0, eEncodingUint, eFormatHex, { ehframe_r5, dwarf_r5, LLDB_INVALID_REGNUM, 5, 5 }, NULL, NULL}, - { "r6", NULL, 4, 0, eEncodingUint, eFormatHex, { ehframe_r6, dwarf_r6, LLDB_INVALID_REGNUM, 6, 6 }, NULL, NULL}, - { "r7", "fp", 4, 0, eEncodingUint, eFormatHex, { ehframe_r7, dwarf_r7, LLDB_REGNUM_GENERIC_FP, 7, 7 }, NULL, NULL}, - { "r8", NULL, 4, 0, eEncodingUint, eFormatHex, { ehframe_r8, dwarf_r8, LLDB_INVALID_REGNUM, 8, 8 }, NULL, NULL}, - { "r9", NULL, 4, 0, eEncodingUint, eFormatHex, { ehframe_r9, dwarf_r9, LLDB_INVALID_REGNUM, 9, 9 }, NULL, NULL}, - { "r10", NULL, 4, 0, eEncodingUint, eFormatHex, { ehframe_r10, dwarf_r10, LLDB_INVALID_REGNUM, 10, 10 }, NULL, NULL}, - { "r11", NULL, 4, 0, eEncodingUint, eFormatHex, { ehframe_r11, dwarf_r11, LLDB_INVALID_REGNUM, 11, 11 }, NULL, NULL}, - { "r12", NULL, 4, 0, eEncodingUint, eFormatHex, { ehframe_r12, dwarf_r12, LLDB_INVALID_REGNUM, 12, 12 }, NULL, NULL}, - { "sp", "r13", 4, 0, eEncodingUint, eFormatHex, { ehframe_sp, dwarf_sp, LLDB_REGNUM_GENERIC_SP, 13, 13 }, NULL, NULL}, - { "lr", "r14", 4, 0, eEncodingUint, eFormatHex, { ehframe_lr, dwarf_lr, LLDB_REGNUM_GENERIC_RA, 14, 14 }, NULL, NULL}, - { "pc", "r15", 4, 0, eEncodingUint, eFormatHex, { ehframe_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, 15, 15 }, NULL, NULL}, - { "f0", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 16, 16 }, NULL, NULL}, - { "f1", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 17, 17 }, NULL, NULL}, - { "f2", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 18, 18 }, NULL, NULL}, - { "f3", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 19, 19 }, NULL, NULL}, - { "f4", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 20, 20 }, NULL, NULL}, - { "f5", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 21, 21 }, NULL, NULL}, - { "f6", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 22, 22 }, NULL, NULL}, - { "f7", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 23, 23 }, NULL, NULL}, - { "fps", NULL, 4, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 24, 24 }, NULL, NULL}, - { "cpsr","flags", 4, 0, eEncodingUint, eFormatHex, { ehframe_cpsr, dwarf_cpsr, LLDB_INVALID_REGNUM, 25, 25 }, NULL, NULL}, - { "s0", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s0, LLDB_INVALID_REGNUM, 26, 26 }, NULL, NULL}, - { "s1", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s1, LLDB_INVALID_REGNUM, 27, 27 }, NULL, NULL}, - { "s2", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s2, LLDB_INVALID_REGNUM, 28, 28 }, NULL, NULL}, - { "s3", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s3, LLDB_INVALID_REGNUM, 29, 29 }, NULL, NULL}, - { "s4", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s4, LLDB_INVALID_REGNUM, 30, 30 }, NULL, NULL}, - { "s5", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s5, LLDB_INVALID_REGNUM, 31, 31 }, NULL, NULL}, - { "s6", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s6, LLDB_INVALID_REGNUM, 32, 32 }, NULL, NULL}, - { "s7", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s7, LLDB_INVALID_REGNUM, 33, 33 }, NULL, NULL}, - { "s8", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s8, LLDB_INVALID_REGNUM, 34, 34 }, NULL, NULL}, - { "s9", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s9, LLDB_INVALID_REGNUM, 35, 35 }, NULL, NULL}, - { "s10", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s10, LLDB_INVALID_REGNUM, 36, 36 }, NULL, NULL}, - { "s11", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s11, LLDB_INVALID_REGNUM, 37, 37 }, NULL, NULL}, - { "s12", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s12, LLDB_INVALID_REGNUM, 38, 38 }, NULL, NULL}, - { "s13", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s13, LLDB_INVALID_REGNUM, 39, 39 }, NULL, NULL}, - { "s14", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s14, LLDB_INVALID_REGNUM, 40, 40 }, NULL, NULL}, - { "s15", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s15, LLDB_INVALID_REGNUM, 41, 41 }, NULL, NULL}, - { "s16", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s16, LLDB_INVALID_REGNUM, 42, 42 }, NULL, NULL}, - { "s17", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s17, LLDB_INVALID_REGNUM, 43, 43 }, NULL, NULL}, - { "s18", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s18, LLDB_INVALID_REGNUM, 44, 44 }, NULL, NULL}, - { "s19", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s19, LLDB_INVALID_REGNUM, 45, 45 }, NULL, NULL}, - { "s20", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s20, LLDB_INVALID_REGNUM, 46, 46 }, NULL, NULL}, - { "s21", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s21, LLDB_INVALID_REGNUM, 47, 47 }, NULL, NULL}, - { "s22", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s22, LLDB_INVALID_REGNUM, 48, 48 }, NULL, NULL}, - { "s23", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s23, LLDB_INVALID_REGNUM, 49, 49 }, NULL, NULL}, - { "s24", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s24, LLDB_INVALID_REGNUM, 50, 50 }, NULL, NULL}, - { "s25", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s25, LLDB_INVALID_REGNUM, 51, 51 }, NULL, NULL}, - { "s26", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s26, LLDB_INVALID_REGNUM, 52, 52 }, NULL, NULL}, - { "s27", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s27, LLDB_INVALID_REGNUM, 53, 53 }, NULL, NULL}, - { "s28", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s28, LLDB_INVALID_REGNUM, 54, 54 }, NULL, NULL}, - { "s29", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s29, LLDB_INVALID_REGNUM, 55, 55 }, NULL, NULL}, - { "s30", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s30, LLDB_INVALID_REGNUM, 56, 56 }, NULL, NULL}, - { "s31", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s31, LLDB_INVALID_REGNUM, 57, 57 }, NULL, NULL}, - { "fpscr",NULL, 4, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 58, 58 }, NULL, NULL}, - { "d16", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d16, LLDB_INVALID_REGNUM, 59, 59 }, NULL, NULL}, - { "d17", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d17, LLDB_INVALID_REGNUM, 60, 60 }, NULL, NULL}, - { "d18", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d18, LLDB_INVALID_REGNUM, 61, 61 }, NULL, NULL}, - { "d19", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d19, LLDB_INVALID_REGNUM, 62, 62 }, NULL, NULL}, - { "d20", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d20, LLDB_INVALID_REGNUM, 63, 63 }, NULL, NULL}, - { "d21", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d21, LLDB_INVALID_REGNUM, 64, 64 }, NULL, NULL}, - { "d22", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d22, LLDB_INVALID_REGNUM, 65, 65 }, NULL, NULL}, - { "d23", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d23, LLDB_INVALID_REGNUM, 66, 66 }, NULL, NULL}, - { "d24", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d24, LLDB_INVALID_REGNUM, 67, 67 }, NULL, NULL}, - { "d25", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d25, LLDB_INVALID_REGNUM, 68, 68 }, NULL, NULL}, - { "d26", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d26, LLDB_INVALID_REGNUM, 69, 69 }, NULL, NULL}, - { "d27", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d27, LLDB_INVALID_REGNUM, 70, 70 }, NULL, NULL}, - { "d28", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d28, LLDB_INVALID_REGNUM, 71, 71 }, NULL, NULL}, - { "d29", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d29, LLDB_INVALID_REGNUM, 72, 72 }, NULL, NULL}, - { "d30", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d30, LLDB_INVALID_REGNUM, 73, 73 }, NULL, NULL}, - { "d31", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d31, LLDB_INVALID_REGNUM, 74, 74 }, NULL, NULL}, - { "d0", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d0, LLDB_INVALID_REGNUM, 75, 75 }, g_d0_regs, NULL}, - { "d1", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d1, LLDB_INVALID_REGNUM, 76, 76 }, g_d1_regs, NULL}, - { "d2", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d2, LLDB_INVALID_REGNUM, 77, 77 }, g_d2_regs, NULL}, - { "d3", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d3, LLDB_INVALID_REGNUM, 78, 78 }, g_d3_regs, NULL}, - { "d4", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d4, LLDB_INVALID_REGNUM, 79, 79 }, g_d4_regs, NULL}, - { "d5", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d5, LLDB_INVALID_REGNUM, 80, 80 }, g_d5_regs, NULL}, - { "d6", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d6, LLDB_INVALID_REGNUM, 81, 81 }, g_d6_regs, NULL}, - { "d7", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d7, LLDB_INVALID_REGNUM, 82, 82 }, g_d7_regs, NULL}, - { "d8", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d8, LLDB_INVALID_REGNUM, 83, 83 }, g_d8_regs, NULL}, - { "d9", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d9, LLDB_INVALID_REGNUM, 84, 84 }, g_d9_regs, NULL}, - { "d10", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d10, LLDB_INVALID_REGNUM, 85, 85 }, g_d10_regs, NULL}, - { "d11", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d11, LLDB_INVALID_REGNUM, 86, 86 }, g_d11_regs, NULL}, - { "d12", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d12, LLDB_INVALID_REGNUM, 87, 87 }, g_d12_regs, NULL}, - { "d13", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d13, LLDB_INVALID_REGNUM, 88, 88 }, g_d13_regs, NULL}, - { "d14", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d14, LLDB_INVALID_REGNUM, 89, 89 }, g_d14_regs, NULL}, - { "d15", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d15, LLDB_INVALID_REGNUM, 90, 90 }, g_d15_regs, NULL}, - { "q0", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q0, LLDB_INVALID_REGNUM, 91, 91 }, g_q0_regs, NULL}, - { "q1", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q1, LLDB_INVALID_REGNUM, 92, 92 }, g_q1_regs, NULL}, - { "q2", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q2, LLDB_INVALID_REGNUM, 93, 93 }, g_q2_regs, NULL}, - { "q3", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q3, LLDB_INVALID_REGNUM, 94, 94 }, g_q3_regs, NULL}, - { "q4", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q4, LLDB_INVALID_REGNUM, 95, 95 }, g_q4_regs, NULL}, - { "q5", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q5, LLDB_INVALID_REGNUM, 96, 96 }, g_q5_regs, NULL}, - { "q6", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q6, LLDB_INVALID_REGNUM, 97, 97 }, g_q6_regs, NULL}, - { "q7", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q7, LLDB_INVALID_REGNUM, 98, 98 }, g_q7_regs, NULL}, - { "q8", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q8, LLDB_INVALID_REGNUM, 99, 99 }, g_q8_regs, NULL}, - { "q9", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q9, LLDB_INVALID_REGNUM, 100, 100 }, g_q9_regs, NULL}, - { "q10", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q10, LLDB_INVALID_REGNUM, 101, 101 }, g_q10_regs, NULL}, - { "q11", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q11, LLDB_INVALID_REGNUM, 102, 102 }, g_q11_regs, NULL}, - { "q12", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q12, LLDB_INVALID_REGNUM, 103, 103 }, g_q12_regs, NULL}, - { "q13", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q13, LLDB_INVALID_REGNUM, 104, 104 }, g_q13_regs, NULL}, - { "q14", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q14, LLDB_INVALID_REGNUM, 105, 105 }, g_q14_regs, NULL}, - { "q15", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q15, LLDB_INVALID_REGNUM, 106, 106 }, g_q15_regs, NULL} +// NAME ALT SZ OFF ENCODING FORMAT EH_FRAME DWARF GENERIC PROCESS PLUGIN LLDB VALUE REGS INVALIDATE REGS SIZE EXPR SIZE LEN +// ====== ====== === === ============= ========== =================== =================== ====================== ============= ==== ========== =============== ========= ======== + { "r0", "arg1", 4, 0, eEncodingUint, eFormatHex, { ehframe_r0, dwarf_r0, LLDB_REGNUM_GENERIC_ARG1,0, 0 }, nullptr, nullptr, nullptr, 0 }, + { "r1", "arg2", 4, 0, eEncodingUint, eFormatHex, { ehframe_r1, dwarf_r1, LLDB_REGNUM_GENERIC_ARG2,1, 1 }, nullptr, nullptr, nullptr, 0 }, + { "r2", "arg3", 4, 0, eEncodingUint, eFormatHex, { ehframe_r2, dwarf_r2, LLDB_REGNUM_GENERIC_ARG3,2, 2 }, nullptr, nullptr, nullptr, 0 }, + { "r3", "arg4", 4, 0, eEncodingUint, eFormatHex, { ehframe_r3, dwarf_r3, LLDB_REGNUM_GENERIC_ARG4,3, 3 }, nullptr, nullptr, nullptr, 0 }, + { "r4", nullptr, 4, 0, eEncodingUint, eFormatHex, { ehframe_r4, dwarf_r4, LLDB_INVALID_REGNUM, 4, 4 }, nullptr, nullptr, nullptr, 0 }, + { "r5", nullptr, 4, 0, eEncodingUint, eFormatHex, { ehframe_r5, dwarf_r5, LLDB_INVALID_REGNUM, 5, 5 }, nullptr, nullptr, nullptr, 0 }, + { "r6", nullptr, 4, 0, eEncodingUint, eFormatHex, { ehframe_r6, dwarf_r6, LLDB_INVALID_REGNUM, 6, 6 }, nullptr, nullptr, nullptr, 0 }, + { "r7", "fp", 4, 0, eEncodingUint, eFormatHex, { ehframe_r7, dwarf_r7, LLDB_REGNUM_GENERIC_FP, 7, 7 }, nullptr, nullptr, nullptr, 0 }, + { "r8", nullptr, 4, 0, eEncodingUint, eFormatHex, { ehframe_r8, dwarf_r8, LLDB_INVALID_REGNUM, 8, 8 }, nullptr, nullptr, nullptr, 0 }, + { "r9", nullptr, 4, 0, eEncodingUint, eFormatHex, { ehframe_r9, dwarf_r9, LLDB_INVALID_REGNUM, 9, 9 }, nullptr, nullptr, nullptr, 0 }, + { "r10", nullptr, 4, 0, eEncodingUint, eFormatHex, { ehframe_r10, dwarf_r10, LLDB_INVALID_REGNUM, 10, 10 }, nullptr, nullptr, nullptr, 0 }, + { "r11", nullptr, 4, 0, eEncodingUint, eFormatHex, { ehframe_r11, dwarf_r11, LLDB_INVALID_REGNUM, 11, 11 }, nullptr, nullptr, nullptr, 0 }, + { "r12", nullptr, 4, 0, eEncodingUint, eFormatHex, { ehframe_r12, dwarf_r12, LLDB_INVALID_REGNUM, 12, 12 }, nullptr, nullptr, nullptr, 0 }, + { "sp", "r13", 4, 0, eEncodingUint, eFormatHex, { ehframe_sp, dwarf_sp, LLDB_REGNUM_GENERIC_SP, 13, 13 }, nullptr, nullptr, nullptr, 0 }, + { "lr", "r14", 4, 0, eEncodingUint, eFormatHex, { ehframe_lr, dwarf_lr, LLDB_REGNUM_GENERIC_RA, 14, 14 }, nullptr, nullptr, nullptr, 0 }, + { "pc", "r15", 4, 0, eEncodingUint, eFormatHex, { ehframe_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, 15, 15 }, nullptr, nullptr, nullptr, 0 }, + { "f0", nullptr, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 16, 16 }, nullptr, nullptr, nullptr, 0 }, + { "f1", nullptr, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 17, 17 }, nullptr, nullptr, nullptr, 0 }, + { "f2", nullptr, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 18, 18 }, nullptr, nullptr, nullptr, 0 }, + { "f3", nullptr, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 19, 19 }, nullptr, nullptr, nullptr, 0 }, + { "f4", nullptr, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 20, 20 }, nullptr, nullptr, nullptr, 0 }, + { "f5", nullptr, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 21, 21 }, nullptr, nullptr, nullptr, 0 }, + { "f6", nullptr, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 22, 22 }, nullptr, nullptr, nullptr, 0 }, + { "f7", nullptr, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 23, 23 }, nullptr, nullptr, nullptr, 0 }, + { "fps", nullptr, 4, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 24, 24 }, nullptr, nullptr, nullptr, 0 }, + { "cpsr","flags", 4, 0, eEncodingUint, eFormatHex, { ehframe_cpsr, dwarf_cpsr, LLDB_INVALID_REGNUM, 25, 25 }, nullptr, nullptr, nullptr, 0 }, + { "s0", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s0, LLDB_INVALID_REGNUM, 26, 26 }, nullptr, nullptr, nullptr, 0 }, + { "s1", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s1, LLDB_INVALID_REGNUM, 27, 27 }, nullptr, nullptr, nullptr, 0 }, + { "s2", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s2, LLDB_INVALID_REGNUM, 28, 28 }, nullptr, nullptr, nullptr, 0 }, + { "s3", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s3, LLDB_INVALID_REGNUM, 29, 29 }, nullptr, nullptr, nullptr, 0 }, + { "s4", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s4, LLDB_INVALID_REGNUM, 30, 30 }, nullptr, nullptr, nullptr, 0 }, + { "s5", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s5, LLDB_INVALID_REGNUM, 31, 31 }, nullptr, nullptr, nullptr, 0 }, + { "s6", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s6, LLDB_INVALID_REGNUM, 32, 32 }, nullptr, nullptr, nullptr, 0 }, + { "s7", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s7, LLDB_INVALID_REGNUM, 33, 33 }, nullptr, nullptr, nullptr, 0 }, + { "s8", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s8, LLDB_INVALID_REGNUM, 34, 34 }, nullptr, nullptr, nullptr, 0 }, + { "s9", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s9, LLDB_INVALID_REGNUM, 35, 35 }, nullptr, nullptr, nullptr, 0 }, + { "s10", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s10, LLDB_INVALID_REGNUM, 36, 36 }, nullptr, nullptr, nullptr, 0 }, + { "s11", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s11, LLDB_INVALID_REGNUM, 37, 37 }, nullptr, nullptr, nullptr, 0 }, + { "s12", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s12, LLDB_INVALID_REGNUM, 38, 38 }, nullptr, nullptr, nullptr, 0 }, + { "s13", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s13, LLDB_INVALID_REGNUM, 39, 39 }, nullptr, nullptr, nullptr, 0 }, + { "s14", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s14, LLDB_INVALID_REGNUM, 40, 40 }, nullptr, nullptr, nullptr, 0 }, + { "s15", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s15, LLDB_INVALID_REGNUM, 41, 41 }, nullptr, nullptr, nullptr, 0 }, + { "s16", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s16, LLDB_INVALID_REGNUM, 42, 42 }, nullptr, nullptr, nullptr, 0 }, + { "s17", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s17, LLDB_INVALID_REGNUM, 43, 43 }, nullptr, nullptr, nullptr, 0 }, + { "s18", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s18, LLDB_INVALID_REGNUM, 44, 44 }, nullptr, nullptr, nullptr, 0 }, + { "s19", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s19, LLDB_INVALID_REGNUM, 45, 45 }, nullptr, nullptr, nullptr, 0 }, + { "s20", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s20, LLDB_INVALID_REGNUM, 46, 46 }, nullptr, nullptr, nullptr, 0 }, + { "s21", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s21, LLDB_INVALID_REGNUM, 47, 47 }, nullptr, nullptr, nullptr, 0 }, + { "s22", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s22, LLDB_INVALID_REGNUM, 48, 48 }, nullptr, nullptr, nullptr, 0 }, + { "s23", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s23, LLDB_INVALID_REGNUM, 49, 49 }, nullptr, nullptr, nullptr, 0 }, + { "s24", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s24, LLDB_INVALID_REGNUM, 50, 50 }, nullptr, nullptr, nullptr, 0 }, + { "s25", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s25, LLDB_INVALID_REGNUM, 51, 51 }, nullptr, nullptr, nullptr, 0 }, + { "s26", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s26, LLDB_INVALID_REGNUM, 52, 52 }, nullptr, nullptr, nullptr, 0 }, + { "s27", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s27, LLDB_INVALID_REGNUM, 53, 53 }, nullptr, nullptr, nullptr, 0 }, + { "s28", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s28, LLDB_INVALID_REGNUM, 54, 54 }, nullptr, nullptr, nullptr, 0 }, + { "s29", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s29, LLDB_INVALID_REGNUM, 55, 55 }, nullptr, nullptr, nullptr, 0 }, + { "s30", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s30, LLDB_INVALID_REGNUM, 56, 56 }, nullptr, nullptr, nullptr, 0 }, + { "s31", nullptr, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s31, LLDB_INVALID_REGNUM, 57, 57 }, nullptr, nullptr, nullptr, 0 }, + { "fpscr",nullptr, 4, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 58, 58 }, nullptr, nullptr, nullptr, 0 }, + { "d16", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d16, LLDB_INVALID_REGNUM, 59, 59 }, nullptr, nullptr, nullptr, 0 }, + { "d17", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d17, LLDB_INVALID_REGNUM, 60, 60 }, nullptr, nullptr, nullptr, 0 }, + { "d18", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d18, LLDB_INVALID_REGNUM, 61, 61 }, nullptr, nullptr, nullptr, 0 }, + { "d19", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d19, LLDB_INVALID_REGNUM, 62, 62 }, nullptr, nullptr, nullptr, 0 }, + { "d20", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d20, LLDB_INVALID_REGNUM, 63, 63 }, nullptr, nullptr, nullptr, 0 }, + { "d21", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d21, LLDB_INVALID_REGNUM, 64, 64 }, nullptr, nullptr, nullptr, 0 }, + { "d22", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d22, LLDB_INVALID_REGNUM, 65, 65 }, nullptr, nullptr, nullptr, 0 }, + { "d23", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d23, LLDB_INVALID_REGNUM, 66, 66 }, nullptr, nullptr, nullptr, 0 }, + { "d24", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d24, LLDB_INVALID_REGNUM, 67, 67 }, nullptr, nullptr, nullptr, 0 }, + { "d25", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d25, LLDB_INVALID_REGNUM, 68, 68 }, nullptr, nullptr, nullptr, 0 }, + { "d26", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d26, LLDB_INVALID_REGNUM, 69, 69 }, nullptr, nullptr, nullptr, 0 }, + { "d27", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d27, LLDB_INVALID_REGNUM, 70, 70 }, nullptr, nullptr, nullptr, 0 }, + { "d28", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d28, LLDB_INVALID_REGNUM, 71, 71 }, nullptr, nullptr, nullptr, 0 }, + { "d29", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d29, LLDB_INVALID_REGNUM, 72, 72 }, nullptr, nullptr, nullptr, 0 }, + { "d30", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d30, LLDB_INVALID_REGNUM, 73, 73 }, nullptr, nullptr, nullptr, 0 }, + { "d31", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d31, LLDB_INVALID_REGNUM, 74, 74 }, nullptr, nullptr, nullptr, 0 }, + { "d0", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d0, LLDB_INVALID_REGNUM, 75, 75 }, g_d0_regs, nullptr, nullptr, 0 }, + { "d1", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d1, LLDB_INVALID_REGNUM, 76, 76 }, g_d1_regs, nullptr, nullptr, 0 }, + { "d2", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d2, LLDB_INVALID_REGNUM, 77, 77 }, g_d2_regs, nullptr, nullptr, 0 }, + { "d3", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d3, LLDB_INVALID_REGNUM, 78, 78 }, g_d3_regs, nullptr, nullptr, 0 }, + { "d4", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d4, LLDB_INVALID_REGNUM, 79, 79 }, g_d4_regs, nullptr, nullptr, 0 }, + { "d5", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d5, LLDB_INVALID_REGNUM, 80, 80 }, g_d5_regs, nullptr, nullptr, 0 }, + { "d6", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d6, LLDB_INVALID_REGNUM, 81, 81 }, g_d6_regs, nullptr, nullptr, 0 }, + { "d7", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d7, LLDB_INVALID_REGNUM, 82, 82 }, g_d7_regs, nullptr, nullptr, 0 }, + { "d8", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d8, LLDB_INVALID_REGNUM, 83, 83 }, g_d8_regs, nullptr, nullptr, 0 }, + { "d9", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d9, LLDB_INVALID_REGNUM, 84, 84 }, g_d9_regs, nullptr, nullptr, 0 }, + { "d10", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d10, LLDB_INVALID_REGNUM, 85, 85 }, g_d10_regs, nullptr, nullptr, 0 }, + { "d11", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d11, LLDB_INVALID_REGNUM, 86, 86 }, g_d11_regs, nullptr, nullptr, 0 }, + { "d12", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d12, LLDB_INVALID_REGNUM, 87, 87 }, g_d12_regs, nullptr, nullptr, 0 }, + { "d13", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d13, LLDB_INVALID_REGNUM, 88, 88 }, g_d13_regs, nullptr, nullptr, 0 }, + { "d14", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d14, LLDB_INVALID_REGNUM, 89, 89 }, g_d14_regs, nullptr, nullptr, 0 }, + { "d15", nullptr, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d15, LLDB_INVALID_REGNUM, 90, 90 }, g_d15_regs, nullptr, nullptr, 0 }, + { "q0", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q0, LLDB_INVALID_REGNUM, 91, 91 }, g_q0_regs, nullptr, nullptr, 0 }, + { "q1", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q1, LLDB_INVALID_REGNUM, 92, 92 }, g_q1_regs, nullptr, nullptr, 0 }, + { "q2", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q2, LLDB_INVALID_REGNUM, 93, 93 }, g_q2_regs, nullptr, nullptr, 0 }, + { "q3", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q3, LLDB_INVALID_REGNUM, 94, 94 }, g_q3_regs, nullptr, nullptr, 0 }, + { "q4", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q4, LLDB_INVALID_REGNUM, 95, 95 }, g_q4_regs, nullptr, nullptr, 0 }, + { "q5", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q5, LLDB_INVALID_REGNUM, 96, 96 }, g_q5_regs, nullptr, nullptr, 0 }, + { "q6", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q6, LLDB_INVALID_REGNUM, 97, 97 }, g_q6_regs, nullptr, nullptr, 0 }, + { "q7", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q7, LLDB_INVALID_REGNUM, 98, 98 }, g_q7_regs, nullptr, nullptr, 0 }, + { "q8", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q8, LLDB_INVALID_REGNUM, 99, 99 }, g_q8_regs, nullptr, nullptr, 0 }, + { "q9", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q9, LLDB_INVALID_REGNUM, 100, 100 }, g_q9_regs, nullptr, nullptr, 0 }, + { "q10", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q10, LLDB_INVALID_REGNUM, 101, 101 }, g_q10_regs, nullptr, nullptr, 0 }, + { "q11", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q11, LLDB_INVALID_REGNUM, 102, 102 }, g_q11_regs, nullptr, nullptr, 0 }, + { "q12", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q12, LLDB_INVALID_REGNUM, 103, 103 }, g_q12_regs, nullptr, nullptr, 0 }, + { "q13", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q13, LLDB_INVALID_REGNUM, 104, 104 }, g_q13_regs, nullptr, nullptr, 0 }, + { "q14", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q14, LLDB_INVALID_REGNUM, 105, 105 }, g_q14_regs, nullptr, nullptr, 0 }, + { "q15", nullptr, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q15, LLDB_INVALID_REGNUM, 106, 106 }, g_q15_regs, nullptr, nullptr, 0 } }; - - static const uint32_t num_registers = llvm::array_lengthof(g_register_infos); - static ConstString gpr_reg_set ("General Purpose Registers"); - static ConstString sfp_reg_set ("Software Floating Point Registers"); - static ConstString vfp_reg_set ("Floating Point Registers"); - size_t i; - if (from_scratch) - { - // Calculate the offsets of the registers - // Note that the layout of the "composite" registers (d0-d15 and q0-q15) which comes after the - // "primordial" registers is important. This enables us to calculate the offset of the composite - // register by using the offset of its first primordial register. For example, to calculate the - // offset of q0, use s0's offset. - if (g_register_infos[2].byte_offset == 0) - { - uint32_t byte_offset = 0; - for (i=0; i<num_registers; ++i) - { - // For primordial registers, increment the byte_offset by the byte_size to arrive at the - // byte_offset for the next register. Otherwise, we have a composite register whose - // offset can be calculated by consulting the offset of its first primordial register. - if (!g_register_infos[i].value_regs) - { - g_register_infos[i].byte_offset = byte_offset; - byte_offset += g_register_infos[i].byte_size; - } - else - { - const uint32_t first_primordial_reg = g_register_infos[i].value_regs[0]; - g_register_infos[i].byte_offset = g_register_infos[first_primordial_reg].byte_offset; - } - } - } - for (i=0; i<num_registers; ++i) - { - ConstString name; - ConstString alt_name; - if (g_register_infos[i].name && g_register_infos[i].name[0]) - name.SetCString(g_register_infos[i].name); - if (g_register_infos[i].alt_name && g_register_infos[i].alt_name[0]) - alt_name.SetCString(g_register_infos[i].alt_name); - - if (i <= 15 || i == 25) - AddRegister (g_register_infos[i], name, alt_name, gpr_reg_set); - else if (i <= 24) - AddRegister (g_register_infos[i], name, alt_name, sfp_reg_set); - else - AddRegister (g_register_infos[i], name, alt_name, vfp_reg_set); + // clang-format on + + static const uint32_t num_registers = llvm::array_lengthof(g_register_infos); + static ConstString gpr_reg_set("General Purpose Registers"); + static ConstString sfp_reg_set("Software Floating Point Registers"); + static ConstString vfp_reg_set("Floating Point Registers"); + size_t i; + if (from_scratch) { + // Calculate the offsets of the registers + // Note that the layout of the "composite" registers (d0-d15 and q0-q15) + // which comes after the + // "primordial" registers is important. This enables us to calculate the + // offset of the composite + // register by using the offset of its first primordial register. For + // example, to calculate the + // offset of q0, use s0's offset. + if (g_register_infos[2].byte_offset == 0) { + uint32_t byte_offset = 0; + for (i = 0; i < num_registers; ++i) { + // For primordial registers, increment the byte_offset by the byte_size + // to arrive at the + // byte_offset for the next register. Otherwise, we have a composite + // register whose + // offset can be calculated by consulting the offset of its first + // primordial register. + if (!g_register_infos[i].value_regs) { + g_register_infos[i].byte_offset = byte_offset; + byte_offset += g_register_infos[i].byte_size; + } else { + const uint32_t first_primordial_reg = + g_register_infos[i].value_regs[0]; + g_register_infos[i].byte_offset = + g_register_infos[first_primordial_reg].byte_offset; } + } } - else - { - // Add composite registers to our primordial registers, then. - const size_t num_composites = llvm::array_lengthof(g_composites); - const size_t num_dynamic_regs = GetNumRegisters(); - const size_t num_common_regs = num_registers - num_composites; - RegisterInfo *g_comp_register_infos = g_register_infos + num_common_regs; - - // First we need to validate that all registers that we already have match the non composite regs. - // If so, then we can add the registers, else we need to bail - bool match = true; - if (num_dynamic_regs == num_common_regs) - { - for (i=0; match && i<num_dynamic_regs; ++i) - { - // Make sure all register names match - if (m_regs[i].name && g_register_infos[i].name) - { - if (strcmp(m_regs[i].name, g_register_infos[i].name)) - { - match = false; - break; - } - } - - // Make sure all register byte sizes match - if (m_regs[i].byte_size != g_register_infos[i].byte_size) - { - match = false; - break; - } - } - } - else - { - // Wrong number of registers. + for (i = 0; i < num_registers; ++i) { + ConstString name; + ConstString alt_name; + if (g_register_infos[i].name && g_register_infos[i].name[0]) + name.SetCString(g_register_infos[i].name); + if (g_register_infos[i].alt_name && g_register_infos[i].alt_name[0]) + alt_name.SetCString(g_register_infos[i].alt_name); + + if (i <= 15 || i == 25) + AddRegister(g_register_infos[i], name, alt_name, gpr_reg_set); + else if (i <= 24) + AddRegister(g_register_infos[i], name, alt_name, sfp_reg_set); + else + AddRegister(g_register_infos[i], name, alt_name, vfp_reg_set); + } + } else { + // Add composite registers to our primordial registers, then. + const size_t num_composites = llvm::array_lengthof(g_composites); + const size_t num_dynamic_regs = GetNumRegisters(); + const size_t num_common_regs = num_registers - num_composites; + RegisterInfo *g_comp_register_infos = g_register_infos + num_common_regs; + + // First we need to validate that all registers that we already have match + // the non composite regs. + // If so, then we can add the registers, else we need to bail + bool match = true; + if (num_dynamic_regs == num_common_regs) { + for (i = 0; match && i < num_dynamic_regs; ++i) { + // Make sure all register names match + if (m_regs[i].name && g_register_infos[i].name) { + if (strcmp(m_regs[i].name, g_register_infos[i].name)) { match = false; + break; + } } - // If "match" is true, then we can add extra registers. - if (match) - { - for (i=0; i<num_composites; ++i) - { - ConstString name; - ConstString alt_name; - const uint32_t first_primordial_reg = g_comp_register_infos[i].value_regs[0]; - const char *reg_name = g_register_infos[first_primordial_reg].name; - if (reg_name && reg_name[0]) - { - for (uint32_t j = 0; j < num_dynamic_regs; ++j) - { - const RegisterInfo *reg_info = GetRegisterInfoAtIndex(j); - // Find a matching primordial register info entry. - if (reg_info && reg_info->name && ::strcasecmp(reg_info->name, reg_name) == 0) - { - // The name matches the existing primordial entry. - // Find and assign the offset, and then add this composite register entry. - g_comp_register_infos[i].byte_offset = reg_info->byte_offset; - name.SetCString(g_comp_register_infos[i].name); - AddRegister(g_comp_register_infos[i], name, alt_name, vfp_reg_set); - } - } - } + + // Make sure all register byte sizes match + if (m_regs[i].byte_size != g_register_infos[i].byte_size) { + match = false; + break; + } + } + } else { + // Wrong number of registers. + match = false; + } + // If "match" is true, then we can add extra registers. + if (match) { + for (i = 0; i < num_composites; ++i) { + ConstString name; + ConstString alt_name; + const uint32_t first_primordial_reg = + g_comp_register_infos[i].value_regs[0]; + const char *reg_name = g_register_infos[first_primordial_reg].name; + if (reg_name && reg_name[0]) { + for (uint32_t j = 0; j < num_dynamic_regs; ++j) { + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(j); + // Find a matching primordial register info entry. + if (reg_info && reg_info->name && + ::strcasecmp(reg_info->name, reg_name) == 0) { + // The name matches the existing primordial entry. + // Find and assign the offset, and then add this composite + // register entry. + g_comp_register_infos[i].byte_offset = reg_info->byte_offset; + name.SetCString(g_comp_register_infos[i].name); + AddRegister(g_comp_register_infos[i], name, alt_name, + vfp_reg_set); } + } } + } } + } } diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h index 0e26c69..5b3e04e 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h @@ -16,12 +16,12 @@ // Other libraries and framework includes // Project includes -#include "lldb/lldb-private.h" -#include "lldb/lldb-enumerations.h" +#include "Plugins/Process/Utility/DynamicRegisterInfo.h" #include "lldb/Core/ConstString.h" #include "lldb/Core/DataExtractor.h" #include "lldb/Target/RegisterContext.h" -#include "Plugins/Process/Utility/DynamicRegisterInfo.h" +#include "lldb/lldb-enumerations.h" +#include "lldb/lldb-private.h" #include "GDBRemoteCommunicationClient.h" @@ -33,133 +33,102 @@ namespace process_gdb_remote { class ThreadGDBRemote; class ProcessGDBRemote; -class GDBRemoteDynamicRegisterInfo : - public DynamicRegisterInfo -{ +class GDBRemoteDynamicRegisterInfo : public DynamicRegisterInfo { public: - GDBRemoteDynamicRegisterInfo () : - DynamicRegisterInfo() - { - } + GDBRemoteDynamicRegisterInfo() : DynamicRegisterInfo() {} - ~GDBRemoteDynamicRegisterInfo() override = default; + ~GDBRemoteDynamicRegisterInfo() override = default; - void - HardcodeARMRegisters(bool from_scratch); + void HardcodeARMRegisters(bool from_scratch); }; -class GDBRemoteRegisterContext : public RegisterContext -{ +class GDBRemoteRegisterContext : public RegisterContext { public: - GDBRemoteRegisterContext (ThreadGDBRemote &thread, - uint32_t concrete_frame_idx, - GDBRemoteDynamicRegisterInfo ®_info, - bool read_all_at_once); + GDBRemoteRegisterContext(ThreadGDBRemote &thread, uint32_t concrete_frame_idx, + GDBRemoteDynamicRegisterInfo ®_info, + bool read_all_at_once); + + ~GDBRemoteRegisterContext() override; - ~GDBRemoteRegisterContext() override; + void InvalidateAllRegisters() override; - void - InvalidateAllRegisters () override; + size_t GetRegisterCount() override; - size_t - GetRegisterCount () override; + const RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override; - const RegisterInfo * - GetRegisterInfoAtIndex (size_t reg) override; + size_t GetRegisterSetCount() override; - size_t - GetRegisterSetCount () override; + const RegisterSet *GetRegisterSet(size_t reg_set) override; - const RegisterSet * - GetRegisterSet (size_t reg_set) override; + bool ReadRegister(const RegisterInfo *reg_info, + RegisterValue &value) override; - bool - ReadRegister (const RegisterInfo *reg_info, RegisterValue &value) override; + bool WriteRegister(const RegisterInfo *reg_info, + const RegisterValue &value) override; - bool - WriteRegister (const RegisterInfo *reg_info, const RegisterValue &value) override; - - bool - ReadAllRegisterValues (lldb::DataBufferSP &data_sp) override; + bool ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override; - bool - WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) override; + bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override; - bool - ReadAllRegisterValues (RegisterCheckpoint ®_checkpoint) override; + bool ReadAllRegisterValues(RegisterCheckpoint ®_checkpoint) override; - bool - WriteAllRegisterValues (const RegisterCheckpoint ®_checkpoint) override; + bool + WriteAllRegisterValues(const RegisterCheckpoint ®_checkpoint) override; - uint32_t - ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num) override; + uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, + uint32_t num) override; protected: - friend class ThreadGDBRemote; - - bool - ReadRegisterBytes (const RegisterInfo *reg_info, - DataExtractor &data); - - bool - WriteRegisterBytes (const RegisterInfo *reg_info, - DataExtractor &data, - uint32_t data_offset); - - bool - PrivateSetRegisterValue (uint32_t reg, StringExtractor &response); - - bool - PrivateSetRegisterValue (uint32_t reg, uint64_t val); - - void - SetAllRegisterValid (bool b); - - bool - GetRegisterIsValid (uint32_t reg) const - { -#if defined (LLDB_CONFIGURATION_DEBUG) - assert (reg < m_reg_valid.size()); + friend class ThreadGDBRemote; + + bool ReadRegisterBytes(const RegisterInfo *reg_info, DataExtractor &data); + + bool WriteRegisterBytes(const RegisterInfo *reg_info, DataExtractor &data, + uint32_t data_offset); + + bool PrivateSetRegisterValue(uint32_t reg, llvm::ArrayRef<uint8_t> data); + + bool PrivateSetRegisterValue(uint32_t reg, uint64_t val); + + void SetAllRegisterValid(bool b); + + bool GetRegisterIsValid(uint32_t reg) const { +#if defined(LLDB_CONFIGURATION_DEBUG) + assert(reg < m_reg_valid.size()); #endif - if (reg < m_reg_valid.size()) - return m_reg_valid[reg]; - return false; - } - - void - SetRegisterIsValid (const RegisterInfo *reg_info, bool valid) - { - if (reg_info) - return SetRegisterIsValid (reg_info->kinds[lldb::eRegisterKindLLDB], valid); - } - - void - SetRegisterIsValid (uint32_t reg, bool valid) - { -#if defined (LLDB_CONFIGURATION_DEBUG) - assert (reg < m_reg_valid.size()); + if (reg < m_reg_valid.size()) + return m_reg_valid[reg]; + return false; + } + + void SetRegisterIsValid(const RegisterInfo *reg_info, bool valid) { + if (reg_info) + return SetRegisterIsValid(reg_info->kinds[lldb::eRegisterKindLLDB], + valid); + } + + void SetRegisterIsValid(uint32_t reg, bool valid) { +#if defined(LLDB_CONFIGURATION_DEBUG) + assert(reg < m_reg_valid.size()); #endif - if (reg < m_reg_valid.size()) - m_reg_valid[reg] = valid; - } - - void - SyncThreadState(Process *process); // Assumes the sequence mutex has already been acquired. - - GDBRemoteDynamicRegisterInfo &m_reg_info; - std::vector<bool> m_reg_valid; - DataExtractor m_reg_data; - bool m_read_all_at_once; + if (reg < m_reg_valid.size()) + m_reg_valid[reg] = valid; + } + + GDBRemoteDynamicRegisterInfo &m_reg_info; + std::vector<bool> m_reg_valid; + DataExtractor m_reg_data; + bool m_read_all_at_once; private: - // Helper function for ReadRegisterBytes(). - bool GetPrimordialRegister(const RegisterInfo *reg_info, - GDBRemoteCommunicationClient &gdb_comm); - // Helper function for WriteRegisterBytes(). - bool SetPrimordialRegister(const RegisterInfo *reg_info, - GDBRemoteCommunicationClient &gdb_comm); - - DISALLOW_COPY_AND_ASSIGN (GDBRemoteRegisterContext); + // Helper function for ReadRegisterBytes(). + bool GetPrimordialRegister(const RegisterInfo *reg_info, + GDBRemoteCommunicationClient &gdb_comm); + // Helper function for WriteRegisterBytes(). + bool SetPrimordialRegister(const RegisterInfo *reg_info, + GDBRemoteCommunicationClient &gdb_comm); + + DISALLOW_COPY_AND_ASSIGN(GDBRemoteRegisterContext); }; } // namespace process_gdb_remote diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index f53d4c6..4b4d62d 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -14,7 +14,8 @@ #include <stdlib.h> #ifndef LLDB_DISABLE_POSIX #include <netinet/in.h> -#include <sys/mman.h> // for mmap +#include <sys/mman.h> // for mmap +#include <sys/socket.h> #endif #include <sys/stat.h> #include <sys/types.h> @@ -24,13 +25,11 @@ #include <algorithm> #include <map> #include <mutex> +#include <sstream> #include "lldb/Breakpoint/Watchpoint.h" -#include "lldb/Interpreter/Args.h" #include "lldb/Core/ArchSpec.h" #include "lldb/Core/Debugger.h" -#include "lldb/Host/ConnectionFileDescriptor.h" -#include "lldb/Host/FileSpec.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" @@ -40,136 +39,119 @@ #include "lldb/Core/Timer.h" #include "lldb/Core/Value.h" #include "lldb/DataFormatters/FormatManager.h" +#include "lldb/Host/ConnectionFileDescriptor.h" +#include "lldb/Host/FileSpec.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/HostThread.h" #include "lldb/Host/StringConvert.h" #include "lldb/Host/Symbols.h" #include "lldb/Host/ThreadLauncher.h" -#include "lldb/Host/TimeValue.h" #include "lldb/Host/XML.h" +#include "lldb/Interpreter/Args.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandObject.h" #include "lldb/Interpreter/CommandObjectMultiword.h" #include "lldb/Interpreter/CommandReturnObject.h" -#include "lldb/Interpreter/OptionValueProperties.h" -#include "lldb/Interpreter/Options.h" #include "lldb/Interpreter/OptionGroupBoolean.h" #include "lldb/Interpreter/OptionGroupUInt64.h" +#include "lldb/Interpreter/OptionValueProperties.h" +#include "lldb/Interpreter/Options.h" #include "lldb/Interpreter/Property.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/ABI.h" #include "lldb/Target/DynamicLoader.h" +#include "lldb/Target/SystemRuntime.h" #include "lldb/Target/Target.h" #include "lldb/Target/TargetList.h" #include "lldb/Target/ThreadPlanCallFunction.h" -#include "lldb/Target/SystemRuntime.h" +#include "lldb/Utility/CleanUp.h" #include "lldb/Utility/PseudoTerminal.h" // Project includes -#include "lldb/Host/Host.h" +#include "GDBRemoteRegisterContext.h" +//#include "Plugins/Platform/MacOSX/PlatformRemoteiOS.h" #include "Plugins/Process/Utility/GDBRemoteSignals.h" #include "Plugins/Process/Utility/InferiorCallPOSIX.h" #include "Plugins/Process/Utility/StopInfoMachException.h" -//#include "Plugins/Platform/MacOSX/PlatformRemoteiOS.h" -#include "Utility/StringExtractorGDBRemote.h" -#include "GDBRemoteRegisterContext.h" #include "ProcessGDBRemote.h" #include "ProcessGDBRemoteLog.h" #include "ThreadGDBRemote.h" +#include "Utility/StringExtractorGDBRemote.h" +#include "lldb/Host/Host.h" -#define DEBUGSERVER_BASENAME "debugserver" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/raw_ostream.h" + +#define DEBUGSERVER_BASENAME "debugserver" using namespace lldb; using namespace lldb_private; using namespace lldb_private::process_gdb_remote; -namespace lldb -{ - // Provide a function that can easily dump the packet history if we know a - // ProcessGDBRemote * value (which we can get from logs or from debugging). - // We need the function in the lldb namespace so it makes it into the final - // executable since the LLDB shared library only exports stuff in the lldb - // namespace. This allows you to attach with a debugger and call this - // function and get the packet history dumped to a file. - void - DumpProcessGDBRemotePacketHistory (void *p, const char *path) - { - StreamFile strm; - Error error (strm.GetFile().Open(path, File::eOpenOptionWrite | File::eOpenOptionCanCreate)); - if (error.Success()) - ((ProcessGDBRemote *)p)->GetGDBRemote().DumpHistory (strm); - } +namespace lldb { +// Provide a function that can easily dump the packet history if we know a +// ProcessGDBRemote * value (which we can get from logs or from debugging). +// We need the function in the lldb namespace so it makes it into the final +// executable since the LLDB shared library only exports stuff in the lldb +// namespace. This allows you to attach with a debugger and call this +// function and get the packet history dumped to a file. +void DumpProcessGDBRemotePacketHistory(void *p, const char *path) { + StreamFile strm; + Error error(strm.GetFile().Open(path, File::eOpenOptionWrite | + File::eOpenOptionCanCreate)); + if (error.Success()) + ((ProcessGDBRemote *)p)->GetGDBRemote().DumpHistory(strm); +} } namespace { - static PropertyDefinition - g_properties[] = - { - { "packet-timeout" , OptionValue::eTypeUInt64 , true , 1, NULL, NULL, "Specify the default packet timeout in seconds." }, - { "target-definition-file" , OptionValue::eTypeFileSpec , true, 0 , NULL, NULL, "The file that provides the description for remote target registers." }, - { NULL , OptionValue::eTypeInvalid, false, 0, NULL, NULL, NULL } - }; - - enum - { - ePropertyPacketTimeout, - ePropertyTargetDefinitionFile - }; +static PropertyDefinition g_properties[] = { + {"packet-timeout", OptionValue::eTypeUInt64, true, 1, NULL, NULL, + "Specify the default packet timeout in seconds."}, + {"target-definition-file", OptionValue::eTypeFileSpec, true, 0, NULL, NULL, + "The file that provides the description for remote target registers."}, + {NULL, OptionValue::eTypeInvalid, false, 0, NULL, NULL, NULL}}; - class PluginProperties : public Properties - { - public: - - static ConstString - GetSettingName () - { - return ProcessGDBRemote::GetPluginNameStatic(); - } - - PluginProperties() : - Properties () - { - m_collection_sp.reset (new OptionValueProperties(GetSettingName())); - m_collection_sp->Initialize(g_properties); - } - - virtual - ~PluginProperties() - { - } - - uint64_t - GetPacketTimeout() - { - const uint32_t idx = ePropertyPacketTimeout; - return m_collection_sp->GetPropertyAtIndexAsUInt64(NULL, idx, g_properties[idx].default_uint_value); - } - - bool - SetPacketTimeout(uint64_t timeout) - { - const uint32_t idx = ePropertyPacketTimeout; - return m_collection_sp->SetPropertyAtIndexAsUInt64(NULL, idx, timeout); - } +enum { ePropertyPacketTimeout, ePropertyTargetDefinitionFile }; - FileSpec - GetTargetDefinitionFile () const - { - const uint32_t idx = ePropertyTargetDefinitionFile; - return m_collection_sp->GetPropertyAtIndexAsFileSpec (NULL, idx); - } - }; +class PluginProperties : public Properties { +public: + static ConstString GetSettingName() { + return ProcessGDBRemote::GetPluginNameStatic(); + } + + PluginProperties() : Properties() { + m_collection_sp.reset(new OptionValueProperties(GetSettingName())); + m_collection_sp->Initialize(g_properties); + } + + virtual ~PluginProperties() {} + + uint64_t GetPacketTimeout() { + const uint32_t idx = ePropertyPacketTimeout; + return m_collection_sp->GetPropertyAtIndexAsUInt64( + NULL, idx, g_properties[idx].default_uint_value); + } + + bool SetPacketTimeout(uint64_t timeout) { + const uint32_t idx = ePropertyPacketTimeout; + return m_collection_sp->SetPropertyAtIndexAsUInt64(NULL, idx, timeout); + } + + FileSpec GetTargetDefinitionFile() const { + const uint32_t idx = ePropertyTargetDefinitionFile; + return m_collection_sp->GetPropertyAtIndexAsFileSpec(NULL, idx); + } +}; - typedef std::shared_ptr<PluginProperties> ProcessKDPPropertiesSP; +typedef std::shared_ptr<PluginProperties> ProcessKDPPropertiesSP; - static const ProcessKDPPropertiesSP & - GetGlobalPluginProperties() - { - static ProcessKDPPropertiesSP g_settings_sp; - if (!g_settings_sp) - g_settings_sp.reset (new PluginProperties ()); - return g_settings_sp; - } +static const ProcessKDPPropertiesSP &GetGlobalPluginProperties() { + static ProcessKDPPropertiesSP g_settings_sp; + if (!g_settings_sp) + g_settings_sp.reset(new PluginProperties()); + return g_settings_sp; +} } // anonymous namespace end @@ -177,3887 +159,3564 @@ namespace { // ephemeral port from the kernel and make sure we reserve it before passing // it to debugserver. -#if defined (__APPLE__) -#define LOW_PORT (IPPORT_RESERVED) -#define HIGH_PORT (IPPORT_HIFIRSTAUTO) +#if defined(__APPLE__) +#define LOW_PORT (IPPORT_RESERVED) +#define HIGH_PORT (IPPORT_HIFIRSTAUTO) #else -#define LOW_PORT (1024u) -#define HIGH_PORT (49151u) +#define LOW_PORT (1024u) +#define HIGH_PORT (49151u) #endif -#if defined(__APPLE__) && (defined(__arm__) || defined(__arm64__) || defined(__aarch64__)) +#if defined(__APPLE__) && \ + (defined(__arm__) || defined(__arm64__) || defined(__aarch64__)) static bool rand_initialized = false; -static inline uint16_t -get_random_port () -{ - if (!rand_initialized) - { - time_t seed = time(NULL); +static inline uint16_t get_random_port() { + if (!rand_initialized) { + time_t seed = time(NULL); - rand_initialized = true; - srand(seed); - } - return (rand() % (HIGH_PORT - LOW_PORT)) + LOW_PORT; + rand_initialized = true; + srand(seed); + } + return (rand() % (HIGH_PORT - LOW_PORT)) + LOW_PORT; } #endif -ConstString -ProcessGDBRemote::GetPluginNameStatic() -{ - static ConstString g_name("gdb-remote"); - return g_name; +ConstString ProcessGDBRemote::GetPluginNameStatic() { + static ConstString g_name("gdb-remote"); + return g_name; } -const char * -ProcessGDBRemote::GetPluginDescriptionStatic() -{ - return "GDB Remote protocol based debugging plug-in."; +const char *ProcessGDBRemote::GetPluginDescriptionStatic() { + return "GDB Remote protocol based debugging plug-in."; } -void -ProcessGDBRemote::Terminate() -{ - PluginManager::UnregisterPlugin (ProcessGDBRemote::CreateInstance); +void ProcessGDBRemote::Terminate() { + PluginManager::UnregisterPlugin(ProcessGDBRemote::CreateInstance); } - lldb::ProcessSP -ProcessGDBRemote::CreateInstance (lldb::TargetSP target_sp, ListenerSP listener_sp, const FileSpec *crash_file_path) -{ - lldb::ProcessSP process_sp; - if (crash_file_path == NULL) - process_sp.reset (new ProcessGDBRemote (target_sp, listener_sp)); - return process_sp; +ProcessGDBRemote::CreateInstance(lldb::TargetSP target_sp, + ListenerSP listener_sp, + const FileSpec *crash_file_path) { + lldb::ProcessSP process_sp; + if (crash_file_path == NULL) + process_sp.reset(new ProcessGDBRemote(target_sp, listener_sp)); + return process_sp; } -bool -ProcessGDBRemote::CanDebug (lldb::TargetSP target_sp, bool plugin_specified_by_name) -{ - if (plugin_specified_by_name) - return true; - - // For now we are just making sure the file exists for a given module - Module *exe_module = target_sp->GetExecutableModulePointer(); - if (exe_module) - { - ObjectFile *exe_objfile = exe_module->GetObjectFile(); - // We can't debug core files... - switch (exe_objfile->GetType()) - { - case ObjectFile::eTypeInvalid: - case ObjectFile::eTypeCoreFile: - case ObjectFile::eTypeDebugInfo: - case ObjectFile::eTypeObjectFile: - case ObjectFile::eTypeSharedLibrary: - case ObjectFile::eTypeStubLibrary: - case ObjectFile::eTypeJIT: - return false; - case ObjectFile::eTypeExecutable: - case ObjectFile::eTypeDynamicLinker: - case ObjectFile::eTypeUnknown: - break; - } - return exe_module->GetFileSpec().Exists(); - } - // However, if there is no executable module, we return true since we might be preparing to attach. +bool ProcessGDBRemote::CanDebug(lldb::TargetSP target_sp, + bool plugin_specified_by_name) { + if (plugin_specified_by_name) return true; + + // For now we are just making sure the file exists for a given module + Module *exe_module = target_sp->GetExecutableModulePointer(); + if (exe_module) { + ObjectFile *exe_objfile = exe_module->GetObjectFile(); + // We can't debug core files... + switch (exe_objfile->GetType()) { + case ObjectFile::eTypeInvalid: + case ObjectFile::eTypeCoreFile: + case ObjectFile::eTypeDebugInfo: + case ObjectFile::eTypeObjectFile: + case ObjectFile::eTypeSharedLibrary: + case ObjectFile::eTypeStubLibrary: + case ObjectFile::eTypeJIT: + return false; + case ObjectFile::eTypeExecutable: + case ObjectFile::eTypeDynamicLinker: + case ObjectFile::eTypeUnknown: + break; + } + return exe_module->GetFileSpec().Exists(); + } + // However, if there is no executable module, we return true since we might be + // preparing to attach. + return true; } //---------------------------------------------------------------------- // ProcessGDBRemote constructor //---------------------------------------------------------------------- -ProcessGDBRemote::ProcessGDBRemote(lldb::TargetSP target_sp, ListenerSP listener_sp) - : Process(target_sp, listener_sp), - m_flags(0), - m_gdb_comm(), - m_debugserver_pid(LLDB_INVALID_PROCESS_ID), - m_last_stop_packet_mutex(), +ProcessGDBRemote::ProcessGDBRemote(lldb::TargetSP target_sp, + ListenerSP listener_sp) + : Process(target_sp, listener_sp), m_flags(0), m_gdb_comm(), + m_debugserver_pid(LLDB_INVALID_PROCESS_ID), m_last_stop_packet_mutex(), m_register_info(), m_async_broadcaster(NULL, "lldb.process.gdb-remote.async-broadcaster"), - m_async_listener_sp(Listener::MakeListener("lldb.process.gdb-remote.async-listener")), - m_async_thread_state_mutex(), - m_thread_ids(), - m_thread_pcs(), - m_jstopinfo_sp(), - m_jthreadsinfo_sp(), - m_continue_c_tids(), - m_continue_C_tids(), - m_continue_s_tids(), - m_continue_S_tids(), - m_max_memory_size(0), - m_remote_stub_max_memory_size(0), - m_addr_to_mmap_size(), - m_thread_create_bp_sp(), - m_waiting_for_attach(false), - m_destroy_tried_resuming(false), - m_command_sp(), - m_breakpoint_pc_offset(0), - m_initial_tid(LLDB_INVALID_THREAD_ID) -{ - m_async_broadcaster.SetEventName(eBroadcastBitAsyncThreadShouldExit, "async thread should exit"); - m_async_broadcaster.SetEventName(eBroadcastBitAsyncContinue, "async thread continue"); - m_async_broadcaster.SetEventName(eBroadcastBitAsyncThreadDidExit, "async thread did exit"); - - Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_ASYNC)); - - const uint32_t async_event_mask = eBroadcastBitAsyncContinue | eBroadcastBitAsyncThreadShouldExit; - - if (m_async_listener_sp->StartListeningForEvents(&m_async_broadcaster, async_event_mask) != async_event_mask) - { - if (log) - log->Printf("ProcessGDBRemote::%s failed to listen for m_async_broadcaster events", __FUNCTION__); - } - - const uint32_t gdb_event_mask = - Communication::eBroadcastBitReadThreadDidExit | GDBRemoteCommunication::eBroadcastBitGdbReadThreadGotNotify; - if (m_async_listener_sp->StartListeningForEvents(&m_gdb_comm, gdb_event_mask) != gdb_event_mask) - { - if (log) - log->Printf("ProcessGDBRemote::%s failed to listen for m_gdb_comm events", __FUNCTION__); - } - - const uint64_t timeout_seconds = GetGlobalPluginProperties()->GetPacketTimeout(); - if (timeout_seconds > 0) - m_gdb_comm.SetPacketTimeout(timeout_seconds); + m_async_listener_sp( + Listener::MakeListener("lldb.process.gdb-remote.async-listener")), + m_async_thread_state_mutex(), m_thread_ids(), m_thread_pcs(), + m_jstopinfo_sp(), m_jthreadsinfo_sp(), m_continue_c_tids(), + m_continue_C_tids(), m_continue_s_tids(), m_continue_S_tids(), + m_max_memory_size(0), m_remote_stub_max_memory_size(0), + m_addr_to_mmap_size(), m_thread_create_bp_sp(), + m_waiting_for_attach(false), m_destroy_tried_resuming(false), + m_command_sp(), m_breakpoint_pc_offset(0), + m_initial_tid(LLDB_INVALID_THREAD_ID) { + m_async_broadcaster.SetEventName(eBroadcastBitAsyncThreadShouldExit, + "async thread should exit"); + m_async_broadcaster.SetEventName(eBroadcastBitAsyncContinue, + "async thread continue"); + m_async_broadcaster.SetEventName(eBroadcastBitAsyncThreadDidExit, + "async thread did exit"); + + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_ASYNC)); + + const uint32_t async_event_mask = + eBroadcastBitAsyncContinue | eBroadcastBitAsyncThreadShouldExit; + + if (m_async_listener_sp->StartListeningForEvents( + &m_async_broadcaster, async_event_mask) != async_event_mask) { + if (log) + log->Printf("ProcessGDBRemote::%s failed to listen for " + "m_async_broadcaster events", + __FUNCTION__); + } + + const uint32_t gdb_event_mask = + Communication::eBroadcastBitReadThreadDidExit | + GDBRemoteCommunication::eBroadcastBitGdbReadThreadGotNotify; + if (m_async_listener_sp->StartListeningForEvents( + &m_gdb_comm, gdb_event_mask) != gdb_event_mask) { + if (log) + log->Printf("ProcessGDBRemote::%s failed to listen for m_gdb_comm events", + __FUNCTION__); + } + + const uint64_t timeout_seconds = + GetGlobalPluginProperties()->GetPacketTimeout(); + if (timeout_seconds > 0) + m_gdb_comm.SetPacketTimeout(std::chrono::seconds(timeout_seconds)); } //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- -ProcessGDBRemote::~ProcessGDBRemote() -{ - // m_mach_process.UnregisterNotificationCallbacks (this); - Clear(); - // We need to call finalize on the process before destroying ourselves - // to make sure all of the broadcaster cleanup goes as planned. If we - // destruct this class, then Process::~Process() might have problems - // trying to fully destroy the broadcaster. - Finalize(); - - // The general Finalize is going to try to destroy the process and that SHOULD - // shut down the async thread. However, if we don't kill it it will get stranded and - // its connection will go away so when it wakes up it will crash. So kill it for sure here. - StopAsyncThread(); - KillDebugserverProcess(); +ProcessGDBRemote::~ProcessGDBRemote() { + // m_mach_process.UnregisterNotificationCallbacks (this); + Clear(); + // We need to call finalize on the process before destroying ourselves + // to make sure all of the broadcaster cleanup goes as planned. If we + // destruct this class, then Process::~Process() might have problems + // trying to fully destroy the broadcaster. + Finalize(); + + // The general Finalize is going to try to destroy the process and that SHOULD + // shut down the async thread. However, if we don't kill it it will get + // stranded and + // its connection will go away so when it wakes up it will crash. So kill it + // for sure here. + StopAsyncThread(); + KillDebugserverProcess(); } //---------------------------------------------------------------------- // PluginInterface //---------------------------------------------------------------------- -ConstString -ProcessGDBRemote::GetPluginName() -{ - return GetPluginNameStatic(); -} - -uint32_t -ProcessGDBRemote::GetPluginVersion() -{ - return 1; -} - -bool -ProcessGDBRemote::ParsePythonTargetDefinition(const FileSpec &target_definition_fspec) -{ - ScriptInterpreter *interpreter = GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); - Error error; - StructuredData::ObjectSP module_object_sp(interpreter->LoadPluginModule(target_definition_fspec, error)); - if (module_object_sp) - { - StructuredData::DictionarySP target_definition_sp( - interpreter->GetDynamicSettings(module_object_sp, &GetTarget(), "gdb-server-target-definition", error)); - - if (target_definition_sp) - { - StructuredData::ObjectSP target_object(target_definition_sp->GetValueForKey("host-info")); - if (target_object) - { - if (auto host_info_dict = target_object->GetAsDictionary()) - { - StructuredData::ObjectSP triple_value = host_info_dict->GetValueForKey("triple"); - if (auto triple_string_value = triple_value->GetAsString()) - { - std::string triple_string = triple_string_value->GetValue(); - ArchSpec host_arch(triple_string.c_str()); - if (!host_arch.IsCompatibleMatch(GetTarget().GetArchitecture())) - { - GetTarget().SetArchitecture(host_arch); - } - } - } - } - m_breakpoint_pc_offset = 0; - StructuredData::ObjectSP breakpoint_pc_offset_value = target_definition_sp->GetValueForKey("breakpoint-pc-offset"); - if (breakpoint_pc_offset_value) - { - if (auto breakpoint_pc_int_value = breakpoint_pc_offset_value->GetAsInteger()) - m_breakpoint_pc_offset = breakpoint_pc_int_value->GetValue(); - } - - if (m_register_info.SetRegisterInfo(*target_definition_sp, GetTarget().GetArchitecture()) > 0) - { - return true; +ConstString ProcessGDBRemote::GetPluginName() { return GetPluginNameStatic(); } + +uint32_t ProcessGDBRemote::GetPluginVersion() { return 1; } + +bool ProcessGDBRemote::ParsePythonTargetDefinition( + const FileSpec &target_definition_fspec) { + ScriptInterpreter *interpreter = + GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); + Error error; + StructuredData::ObjectSP module_object_sp( + interpreter->LoadPluginModule(target_definition_fspec, error)); + if (module_object_sp) { + StructuredData::DictionarySP target_definition_sp( + interpreter->GetDynamicSettings(module_object_sp, &GetTarget(), + "gdb-server-target-definition", error)); + + if (target_definition_sp) { + StructuredData::ObjectSP target_object( + target_definition_sp->GetValueForKey("host-info")); + if (target_object) { + if (auto host_info_dict = target_object->GetAsDictionary()) { + StructuredData::ObjectSP triple_value = + host_info_dict->GetValueForKey("triple"); + if (auto triple_string_value = triple_value->GetAsString()) { + std::string triple_string = triple_string_value->GetValue(); + ArchSpec host_arch(triple_string.c_str()); + if (!host_arch.IsCompatibleMatch(GetTarget().GetArchitecture())) { + GetTarget().SetArchitecture(host_arch); } + } } + } + m_breakpoint_pc_offset = 0; + StructuredData::ObjectSP breakpoint_pc_offset_value = + target_definition_sp->GetValueForKey("breakpoint-pc-offset"); + if (breakpoint_pc_offset_value) { + if (auto breakpoint_pc_int_value = + breakpoint_pc_offset_value->GetAsInteger()) + m_breakpoint_pc_offset = breakpoint_pc_int_value->GetValue(); + } + + if (m_register_info.SetRegisterInfo(*target_definition_sp, + GetTarget().GetArchitecture()) > 0) { + return true; + } } - return false; + } + return false; } -// If the remote stub didn't give us eh_frame or DWARF register numbers for a register, +// If the remote stub didn't give us eh_frame or DWARF register numbers for a +// register, // see if the ABI can provide them. // DWARF and eh_frame register numbers are defined as a part of the ABI. -static void -AugmentRegisterInfoViaABI (RegisterInfo ®_info, ConstString reg_name, ABISP abi_sp) -{ - if (reg_info.kinds[eRegisterKindEHFrame] == LLDB_INVALID_REGNUM - || reg_info.kinds[eRegisterKindDWARF] == LLDB_INVALID_REGNUM) - { - if (abi_sp) - { - RegisterInfo abi_reg_info; - if (abi_sp->GetRegisterInfoByName (reg_name, abi_reg_info)) - { - if (reg_info.kinds[eRegisterKindEHFrame] == LLDB_INVALID_REGNUM && - abi_reg_info.kinds[eRegisterKindEHFrame] != LLDB_INVALID_REGNUM) - { - reg_info.kinds[eRegisterKindEHFrame] = abi_reg_info.kinds[eRegisterKindEHFrame]; - } - if (reg_info.kinds[eRegisterKindDWARF] == LLDB_INVALID_REGNUM && - abi_reg_info.kinds[eRegisterKindDWARF] != LLDB_INVALID_REGNUM) - { - reg_info.kinds[eRegisterKindDWARF] = abi_reg_info.kinds[eRegisterKindDWARF]; - } - if (reg_info.kinds[eRegisterKindGeneric] == LLDB_INVALID_REGNUM && - abi_reg_info.kinds[eRegisterKindGeneric] != LLDB_INVALID_REGNUM) - { - reg_info.kinds[eRegisterKindGeneric] = abi_reg_info.kinds[eRegisterKindGeneric]; - } - } +static void AugmentRegisterInfoViaABI(RegisterInfo ®_info, + ConstString reg_name, ABISP abi_sp) { + if (reg_info.kinds[eRegisterKindEHFrame] == LLDB_INVALID_REGNUM || + reg_info.kinds[eRegisterKindDWARF] == LLDB_INVALID_REGNUM) { + if (abi_sp) { + RegisterInfo abi_reg_info; + if (abi_sp->GetRegisterInfoByName(reg_name, abi_reg_info)) { + if (reg_info.kinds[eRegisterKindEHFrame] == LLDB_INVALID_REGNUM && + abi_reg_info.kinds[eRegisterKindEHFrame] != LLDB_INVALID_REGNUM) { + reg_info.kinds[eRegisterKindEHFrame] = + abi_reg_info.kinds[eRegisterKindEHFrame]; } - } -} - -static size_t -SplitCommaSeparatedRegisterNumberString(const llvm::StringRef &comma_separated_regiter_numbers, std::vector<uint32_t> ®nums, int base) -{ - regnums.clear(); - std::pair<llvm::StringRef, llvm::StringRef> value_pair; - value_pair.second = comma_separated_regiter_numbers; - do - { - value_pair = value_pair.second.split(','); - if (!value_pair.first.empty()) - { - uint32_t reg = StringConvert::ToUInt32 (value_pair.first.str().c_str(), LLDB_INVALID_REGNUM, base); - if (reg != LLDB_INVALID_REGNUM) - regnums.push_back (reg); - } - } while (!value_pair.second.empty()); - return regnums.size(); -} - - -void -ProcessGDBRemote::BuildDynamicRegisterInfo (bool force) -{ - if (!force && m_register_info.GetNumRegisters() > 0) - return; - - m_register_info.Clear(); - - // Check if qHostInfo specified a specific packet timeout for this connection. - // If so then lets update our setting so the user knows what the timeout is - // and can see it. - const uint32_t host_packet_timeout = m_gdb_comm.GetHostDefaultPacketTimeout(); - if (host_packet_timeout) - { - GetGlobalPluginProperties()->SetPacketTimeout(host_packet_timeout); - } - - // Register info search order: - // 1 - Use the target definition python file if one is specified. - // 2 - If the target definition doesn't have any of the info from the target.xml (registers) then proceed to read the target.xml. - // 3 - Fall back on the qRegisterInfo packets. - - FileSpec target_definition_fspec = GetGlobalPluginProperties()->GetTargetDefinitionFile (); - if (!target_definition_fspec.Exists()) - { - // If the filename doesn't exist, it may be a ~ not having been expanded - try to resolve it. - target_definition_fspec.ResolvePath(); - } - if (target_definition_fspec) - { - // See if we can get register definitions from a python file - if (ParsePythonTargetDefinition (target_definition_fspec)) - { - return; + if (reg_info.kinds[eRegisterKindDWARF] == LLDB_INVALID_REGNUM && + abi_reg_info.kinds[eRegisterKindDWARF] != LLDB_INVALID_REGNUM) { + reg_info.kinds[eRegisterKindDWARF] = + abi_reg_info.kinds[eRegisterKindDWARF]; } - else - { - StreamSP stream_sp = GetTarget().GetDebugger().GetAsyncOutputStream(); - stream_sp->Printf ("ERROR: target description file %s failed to parse.\n", target_definition_fspec.GetPath().c_str()); + if (reg_info.kinds[eRegisterKindGeneric] == LLDB_INVALID_REGNUM && + abi_reg_info.kinds[eRegisterKindGeneric] != LLDB_INVALID_REGNUM) { + reg_info.kinds[eRegisterKindGeneric] = + abi_reg_info.kinds[eRegisterKindGeneric]; } + } } + } +} - const ArchSpec &target_arch = GetTarget().GetArchitecture(); - const ArchSpec &remote_host_arch = m_gdb_comm.GetHostArchitecture(); - const ArchSpec &remote_process_arch = m_gdb_comm.GetProcessArchitecture(); +static size_t SplitCommaSeparatedRegisterNumberString( + const llvm::StringRef &comma_separated_regiter_numbers, + std::vector<uint32_t> ®nums, int base) { + regnums.clear(); + std::pair<llvm::StringRef, llvm::StringRef> value_pair; + value_pair.second = comma_separated_regiter_numbers; + do { + value_pair = value_pair.second.split(','); + if (!value_pair.first.empty()) { + uint32_t reg = StringConvert::ToUInt32(value_pair.first.str().c_str(), + LLDB_INVALID_REGNUM, base); + if (reg != LLDB_INVALID_REGNUM) + regnums.push_back(reg); + } + } while (!value_pair.second.empty()); + return regnums.size(); +} - // Use the process' architecture instead of the host arch, if available - ArchSpec arch_to_use; - if (remote_process_arch.IsValid ()) - arch_to_use = remote_process_arch; - else - arch_to_use = remote_host_arch; - - if (!arch_to_use.IsValid()) - arch_to_use = target_arch; - - if (GetGDBServerRegisterInfo (arch_to_use)) - return; - - char packet[128]; - uint32_t reg_offset = 0; - uint32_t reg_num = 0; - for (StringExtractorGDBRemote::ResponseType response_type = StringExtractorGDBRemote::eResponse; - response_type == StringExtractorGDBRemote::eResponse; - ++reg_num) - { - const int packet_len = ::snprintf (packet, sizeof(packet), "qRegisterInfo%x", reg_num); - assert (packet_len < (int)sizeof(packet)); - StringExtractorGDBRemote response; - if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false) == GDBRemoteCommunication::PacketResult::Success) - { - response_type = response.GetResponseType(); - if (response_type == StringExtractorGDBRemote::eResponse) +void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) { + if (!force && m_register_info.GetNumRegisters() > 0) + return; + + m_register_info.Clear(); + + // Check if qHostInfo specified a specific packet timeout for this connection. + // If so then lets update our setting so the user knows what the timeout is + // and can see it. + const auto host_packet_timeout = m_gdb_comm.GetHostDefaultPacketTimeout(); + if (host_packet_timeout > std::chrono::seconds(0)) { + GetGlobalPluginProperties()->SetPacketTimeout(host_packet_timeout.count()); + } + + // Register info search order: + // 1 - Use the target definition python file if one is specified. + // 2 - If the target definition doesn't have any of the info from the + // target.xml (registers) then proceed to read the target.xml. + // 3 - Fall back on the qRegisterInfo packets. + + FileSpec target_definition_fspec = + GetGlobalPluginProperties()->GetTargetDefinitionFile(); + if (!target_definition_fspec.Exists()) { + // If the filename doesn't exist, it may be a ~ not having been expanded - + // try to resolve it. + target_definition_fspec.ResolvePath(); + } + if (target_definition_fspec) { + // See if we can get register definitions from a python file + if (ParsePythonTargetDefinition(target_definition_fspec)) { + return; + } else { + StreamSP stream_sp = GetTarget().GetDebugger().GetAsyncOutputStream(); + stream_sp->Printf("ERROR: target description file %s failed to parse.\n", + target_definition_fspec.GetPath().c_str()); + } + } + + const ArchSpec &target_arch = GetTarget().GetArchitecture(); + const ArchSpec &remote_host_arch = m_gdb_comm.GetHostArchitecture(); + const ArchSpec &remote_process_arch = m_gdb_comm.GetProcessArchitecture(); + + // Use the process' architecture instead of the host arch, if available + ArchSpec arch_to_use; + if (remote_process_arch.IsValid()) + arch_to_use = remote_process_arch; + else + arch_to_use = remote_host_arch; + + if (!arch_to_use.IsValid()) + arch_to_use = target_arch; + + if (GetGDBServerRegisterInfo(arch_to_use)) + return; + + char packet[128]; + uint32_t reg_offset = 0; + uint32_t reg_num = 0; + for (StringExtractorGDBRemote::ResponseType response_type = + StringExtractorGDBRemote::eResponse; + response_type == StringExtractorGDBRemote::eResponse; ++reg_num) { + const int packet_len = + ::snprintf(packet, sizeof(packet), "qRegisterInfo%x", reg_num); + assert(packet_len < (int)sizeof(packet)); + UNUSED_IF_ASSERT_DISABLED(packet_len); + StringExtractorGDBRemote response; + if (m_gdb_comm.SendPacketAndWaitForResponse(packet, response, false) == + GDBRemoteCommunication::PacketResult::Success) { + response_type = response.GetResponseType(); + if (response_type == StringExtractorGDBRemote::eResponse) { + llvm::StringRef name; + llvm::StringRef value; + ConstString reg_name; + ConstString alt_name; + ConstString set_name; + std::vector<uint32_t> value_regs; + std::vector<uint32_t> invalidate_regs; + std::vector<uint8_t> dwarf_opcode_bytes; + RegisterInfo reg_info = { + NULL, // Name + NULL, // Alt name + 0, // byte size + reg_offset, // offset + eEncodingUint, // encoding + eFormatHex, // format { - std::string name; - std::string value; - ConstString reg_name; - ConstString alt_name; - ConstString set_name; - std::vector<uint32_t> value_regs; - std::vector<uint32_t> invalidate_regs; - std::vector<uint8_t> dwarf_opcode_bytes; - RegisterInfo reg_info = { NULL, // Name - NULL, // Alt name - 0, // byte size - reg_offset, // offset - eEncodingUint, // encoding - eFormatHex, // format - { - LLDB_INVALID_REGNUM, // eh_frame reg num - LLDB_INVALID_REGNUM, // DWARF reg num - LLDB_INVALID_REGNUM, // generic reg num - reg_num, // process plugin reg num - reg_num // native register number - }, - NULL, - NULL, - NULL, // Dwarf expression opcode bytes pointer - 0 // Dwarf expression opcode bytes length - }; - - while (response.GetNameColonValue(name, value)) - { - if (name.compare("name") == 0) - { - reg_name.SetCString(value.c_str()); - } - else if (name.compare("alt-name") == 0) - { - alt_name.SetCString(value.c_str()); - } - else if (name.compare("bitsize") == 0) - { - reg_info.byte_size = StringConvert::ToUInt32(value.c_str(), 0, 0) / CHAR_BIT; - } - else if (name.compare("offset") == 0) - { - uint32_t offset = StringConvert::ToUInt32(value.c_str(), UINT32_MAX, 0); - if (reg_offset != offset) - { - reg_offset = offset; - } - } - else if (name.compare("encoding") == 0) - { - const Encoding encoding = Args::StringToEncoding (value.c_str()); - if (encoding != eEncodingInvalid) - reg_info.encoding = encoding; - } - else if (name.compare("format") == 0) - { - Format format = eFormatInvalid; - if (Args::StringToFormat (value.c_str(), format, NULL).Success()) - reg_info.format = format; - else if (value.compare("binary") == 0) - reg_info.format = eFormatBinary; - else if (value.compare("decimal") == 0) - reg_info.format = eFormatDecimal; - else if (value.compare("hex") == 0) - reg_info.format = eFormatHex; - else if (value.compare("float") == 0) - reg_info.format = eFormatFloat; - else if (value.compare("vector-sint8") == 0) - reg_info.format = eFormatVectorOfSInt8; - else if (value.compare("vector-uint8") == 0) - reg_info.format = eFormatVectorOfUInt8; - else if (value.compare("vector-sint16") == 0) - reg_info.format = eFormatVectorOfSInt16; - else if (value.compare("vector-uint16") == 0) - reg_info.format = eFormatVectorOfUInt16; - else if (value.compare("vector-sint32") == 0) - reg_info.format = eFormatVectorOfSInt32; - else if (value.compare("vector-uint32") == 0) - reg_info.format = eFormatVectorOfUInt32; - else if (value.compare("vector-float32") == 0) - reg_info.format = eFormatVectorOfFloat32; - else if (value.compare("vector-uint128") == 0) - reg_info.format = eFormatVectorOfUInt128; - } - else if (name.compare("set") == 0) - { - set_name.SetCString(value.c_str()); - } - else if (name.compare("gcc") == 0 || name.compare("ehframe") == 0) - { - reg_info.kinds[eRegisterKindEHFrame] = StringConvert::ToUInt32(value.c_str(), LLDB_INVALID_REGNUM, 0); - } - else if (name.compare("dwarf") == 0) - { - reg_info.kinds[eRegisterKindDWARF] = StringConvert::ToUInt32(value.c_str(), LLDB_INVALID_REGNUM, 0); - } - else if (name.compare("generic") == 0) - { - reg_info.kinds[eRegisterKindGeneric] = Args::StringToGenericRegister (value.c_str()); - } - else if (name.compare("container-regs") == 0) - { - SplitCommaSeparatedRegisterNumberString(value, value_regs, 16); - } - else if (name.compare("invalidate-regs") == 0) - { - SplitCommaSeparatedRegisterNumberString(value, invalidate_regs, 16); - } - else if (name.compare("dynamic_size_dwarf_expr_bytes") == 0) - { - size_t dwarf_opcode_len = value.length () / 2; - assert (dwarf_opcode_len > 0); - - dwarf_opcode_bytes.resize (dwarf_opcode_len); - StringExtractor opcode_extractor; - reg_info.dynamic_size_dwarf_len = dwarf_opcode_len; - - // Swap "value" over into "opcode_extractor" - opcode_extractor.GetStringRef ().swap (value); - uint32_t ret_val = opcode_extractor.GetHexBytesAvail (dwarf_opcode_bytes.data (), - dwarf_opcode_len); - assert (dwarf_opcode_len == ret_val); - - reg_info.dynamic_size_dwarf_expr_bytes = dwarf_opcode_bytes.data (); - } - } - - reg_info.byte_offset = reg_offset; - assert (reg_info.byte_size != 0); - reg_offset += reg_info.byte_size; - if (!value_regs.empty()) - { - value_regs.push_back(LLDB_INVALID_REGNUM); - reg_info.value_regs = value_regs.data(); - } - if (!invalidate_regs.empty()) - { - invalidate_regs.push_back(LLDB_INVALID_REGNUM); - reg_info.invalidate_regs = invalidate_regs.data(); - } - - // We have to make a temporary ABI here, and not use the GetABI because this code - // gets called in DidAttach, when the target architecture (and consequently the ABI we'll get from - // the process) may be wrong. - ABISP abi_to_use = ABI::FindPlugin(arch_to_use); - - AugmentRegisterInfoViaABI (reg_info, reg_name, abi_to_use); + LLDB_INVALID_REGNUM, // eh_frame reg num + LLDB_INVALID_REGNUM, // DWARF reg num + LLDB_INVALID_REGNUM, // generic reg num + reg_num, // process plugin reg num + reg_num // native register number + }, + NULL, + NULL, + NULL, // Dwarf expression opcode bytes pointer + 0 // Dwarf expression opcode bytes length + }; - m_register_info.AddRegister(reg_info, reg_name, alt_name, set_name); + while (response.GetNameColonValue(name, value)) { + if (name.equals("name")) { + reg_name.SetString(value); + } else if (name.equals("alt-name")) { + alt_name.SetString(value); + } else if (name.equals("bitsize")) { + value.getAsInteger(0, reg_info.byte_size); + reg_info.byte_size /= CHAR_BIT; + } else if (name.equals("offset")) { + if (value.getAsInteger(0, reg_offset)) + reg_offset = UINT32_MAX; + } else if (name.equals("encoding")) { + const Encoding encoding = Args::StringToEncoding(value); + if (encoding != eEncodingInvalid) + reg_info.encoding = encoding; + } else if (name.equals("format")) { + Format format = eFormatInvalid; + if (Args::StringToFormat(value.str().c_str(), format, NULL) + .Success()) + reg_info.format = format; + else { + reg_info.format = + llvm::StringSwitch<Format>(value) + .Case("binary", eFormatBinary) + .Case("decimal", eFormatDecimal) + .Case("hex", eFormatHex) + .Case("float", eFormatFloat) + .Case("vector-sint8", eFormatVectorOfSInt8) + .Case("vector-uint8", eFormatVectorOfUInt8) + .Case("vector-sint16", eFormatVectorOfSInt16) + .Case("vector-uint16", eFormatVectorOfUInt16) + .Case("vector-sint32", eFormatVectorOfSInt32) + .Case("vector-uint32", eFormatVectorOfUInt32) + .Case("vector-float32", eFormatVectorOfFloat32) + .Case("vector-uint64", eFormatVectorOfUInt64) + .Case("vector-uint128", eFormatVectorOfUInt128) + .Default(eFormatInvalid); } - else - { - break; // ensure exit before reg_num is incremented - } - } - else - { - break; + } else if (name.equals("set")) { + set_name.SetString(value); + } else if (name.equals("gcc") || name.equals("ehframe")) { + if (value.getAsInteger(0, reg_info.kinds[eRegisterKindEHFrame])) + reg_info.kinds[eRegisterKindEHFrame] = LLDB_INVALID_REGNUM; + } else if (name.equals("dwarf")) { + if (value.getAsInteger(0, reg_info.kinds[eRegisterKindDWARF])) + reg_info.kinds[eRegisterKindDWARF] = LLDB_INVALID_REGNUM; + } else if (name.equals("generic")) { + reg_info.kinds[eRegisterKindGeneric] = + Args::StringToGenericRegister(value); + } else if (name.equals("container-regs")) { + SplitCommaSeparatedRegisterNumberString(value, value_regs, 16); + } else if (name.equals("invalidate-regs")) { + SplitCommaSeparatedRegisterNumberString(value, invalidate_regs, 16); + } else if (name.equals("dynamic_size_dwarf_expr_bytes")) { + size_t dwarf_opcode_len = value.size() / 2; + assert(dwarf_opcode_len > 0); + + dwarf_opcode_bytes.resize(dwarf_opcode_len); + reg_info.dynamic_size_dwarf_len = dwarf_opcode_len; + + StringExtractor opcode_extractor(value); + uint32_t ret_val = + opcode_extractor.GetHexBytesAvail(dwarf_opcode_bytes); + assert(dwarf_opcode_len == ret_val); + + reg_info.dynamic_size_dwarf_expr_bytes = dwarf_opcode_bytes.data(); + } } - } - if (m_register_info.GetNumRegisters() > 0) - { - m_register_info.Finalize(GetTarget().GetArchitecture()); - return; - } + reg_info.byte_offset = reg_offset; + assert(reg_info.byte_size != 0); + reg_offset += reg_info.byte_size; + if (!value_regs.empty()) { + value_regs.push_back(LLDB_INVALID_REGNUM); + reg_info.value_regs = value_regs.data(); + } + if (!invalidate_regs.empty()) { + invalidate_regs.push_back(LLDB_INVALID_REGNUM); + reg_info.invalidate_regs = invalidate_regs.data(); + } - // We didn't get anything if the accumulated reg_num is zero. See if we are - // debugging ARM and fill with a hard coded register set until we can get an - // updated debugserver down on the devices. - // On the other hand, if the accumulated reg_num is positive, see if we can - // add composite registers to the existing primordial ones. - bool from_scratch = (m_register_info.GetNumRegisters() == 0); + // We have to make a temporary ABI here, and not use the GetABI because + // this code + // gets called in DidAttach, when the target architecture (and + // consequently the ABI we'll get from + // the process) may be wrong. + ABISP abi_to_use = ABI::FindPlugin(arch_to_use); - if (!target_arch.IsValid()) - { - if (arch_to_use.IsValid() - && (arch_to_use.GetMachine() == llvm::Triple::arm || arch_to_use.GetMachine() == llvm::Triple::thumb) - && arch_to_use.GetTriple().getVendor() == llvm::Triple::Apple) - m_register_info.HardcodeARMRegisters(from_scratch); - } - else if (target_arch.GetMachine() == llvm::Triple::arm - || target_arch.GetMachine() == llvm::Triple::thumb) - { - m_register_info.HardcodeARMRegisters(from_scratch); - } + AugmentRegisterInfoViaABI(reg_info, reg_name, abi_to_use); - // At this point, we can finalize our register info. - m_register_info.Finalize (GetTarget().GetArchitecture()); + m_register_info.AddRegister(reg_info, reg_name, alt_name, set_name); + } else { + break; // ensure exit before reg_num is incremented + } + } else { + break; + } + } + + if (m_register_info.GetNumRegisters() > 0) { + m_register_info.Finalize(GetTarget().GetArchitecture()); + return; + } + + // We didn't get anything if the accumulated reg_num is zero. See if we are + // debugging ARM and fill with a hard coded register set until we can get an + // updated debugserver down on the devices. + // On the other hand, if the accumulated reg_num is positive, see if we can + // add composite registers to the existing primordial ones. + bool from_scratch = (m_register_info.GetNumRegisters() == 0); + + if (!target_arch.IsValid()) { + if (arch_to_use.IsValid() && + (arch_to_use.GetMachine() == llvm::Triple::arm || + arch_to_use.GetMachine() == llvm::Triple::thumb) && + arch_to_use.GetTriple().getVendor() == llvm::Triple::Apple) + m_register_info.HardcodeARMRegisters(from_scratch); + } else if (target_arch.GetMachine() == llvm::Triple::arm || + target_arch.GetMachine() == llvm::Triple::thumb) { + m_register_info.HardcodeARMRegisters(from_scratch); + } + + // At this point, we can finalize our register info. + m_register_info.Finalize(GetTarget().GetArchitecture()); } -Error -ProcessGDBRemote::WillLaunch (Module* module) -{ - return WillLaunchOrAttach (); +Error ProcessGDBRemote::WillLaunch(Module *module) { + return WillLaunchOrAttach(); } -Error -ProcessGDBRemote::WillAttachToProcessWithID (lldb::pid_t pid) -{ - return WillLaunchOrAttach (); +Error ProcessGDBRemote::WillAttachToProcessWithID(lldb::pid_t pid) { + return WillLaunchOrAttach(); } -Error -ProcessGDBRemote::WillAttachToProcessWithName (const char *process_name, bool wait_for_launch) -{ - return WillLaunchOrAttach (); +Error ProcessGDBRemote::WillAttachToProcessWithName(const char *process_name, + bool wait_for_launch) { + return WillLaunchOrAttach(); } -Error -ProcessGDBRemote::DoConnectRemote (Stream *strm, const char *remote_url) -{ - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); - Error error (WillLaunchOrAttach ()); - - if (error.Fail()) - return error; - - error = ConnectToDebugserver (remote_url); +Error ProcessGDBRemote::DoConnectRemote(Stream *strm, + llvm::StringRef remote_url) { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + Error error(WillLaunchOrAttach()); - if (error.Fail()) - return error; - StartAsyncThread (); - - lldb::pid_t pid = m_gdb_comm.GetCurrentProcessID (); - if (pid == LLDB_INVALID_PROCESS_ID) - { - // We don't have a valid process ID, so note that we are connected - // and could now request to launch or attach, or get remote process - // listings... - SetPrivateState (eStateConnected); - } - else - { - // We have a valid process - SetID (pid); - GetThreadList(); - StringExtractorGDBRemote response; - if (m_gdb_comm.GetStopReply(response)) - { - SetLastStopPacket(response); + if (error.Fail()) + return error; - // '?' Packets must be handled differently in non-stop mode - if (GetTarget().GetNonStopModeEnabled()) - HandleStopReplySequence(); + error = ConnectToDebugserver(remote_url); - Target &target = GetTarget(); - if (!target.GetArchitecture().IsValid()) - { - if (m_gdb_comm.GetProcessArchitecture().IsValid()) - { - target.SetArchitecture(m_gdb_comm.GetProcessArchitecture()); - } - else - { - target.SetArchitecture(m_gdb_comm.GetHostArchitecture()); - } - } - - const StateType state = SetThreadStopInfo (response); - if (state != eStateInvalid) - { - SetPrivateState (state); - } - else - error.SetErrorStringWithFormat ("Process %" PRIu64 " was reported after connecting to '%s', but state was not stopped: %s", pid, remote_url, StateAsCString (state)); + if (error.Fail()) + return error; + StartAsyncThread(); + + lldb::pid_t pid = m_gdb_comm.GetCurrentProcessID(); + if (pid == LLDB_INVALID_PROCESS_ID) { + // We don't have a valid process ID, so note that we are connected + // and could now request to launch or attach, or get remote process + // listings... + SetPrivateState(eStateConnected); + } else { + // We have a valid process + SetID(pid); + GetThreadList(); + StringExtractorGDBRemote response; + if (m_gdb_comm.GetStopReply(response)) { + SetLastStopPacket(response); + + // '?' Packets must be handled differently in non-stop mode + if (GetTarget().GetNonStopModeEnabled()) + HandleStopReplySequence(); + + Target &target = GetTarget(); + if (!target.GetArchitecture().IsValid()) { + if (m_gdb_comm.GetProcessArchitecture().IsValid()) { + target.SetArchitecture(m_gdb_comm.GetProcessArchitecture()); + } else { + target.SetArchitecture(m_gdb_comm.GetHostArchitecture()); } - else - error.SetErrorStringWithFormat ("Process %" PRIu64 " was reported after connecting to '%s', but no stop reply packet was received", pid, remote_url); - } - - if (log) - log->Printf ("ProcessGDBRemote::%s pid %" PRIu64 ": normalizing target architecture initial triple: %s (GetTarget().GetArchitecture().IsValid() %s, m_gdb_comm.GetHostArchitecture().IsValid(): %s)", __FUNCTION__, GetID (), GetTarget ().GetArchitecture ().GetTriple ().getTriple ().c_str (), GetTarget ().GetArchitecture ().IsValid () ? "true" : "false", m_gdb_comm.GetHostArchitecture ().IsValid () ? "true" : "false"); - - - if (error.Success() - && !GetTarget().GetArchitecture().IsValid() - && m_gdb_comm.GetHostArchitecture().IsValid()) - { - // Prefer the *process'* architecture over that of the *host*, if available. - if (m_gdb_comm.GetProcessArchitecture().IsValid()) - GetTarget().SetArchitecture(m_gdb_comm.GetProcessArchitecture()); - else - GetTarget().SetArchitecture(m_gdb_comm.GetHostArchitecture()); - } - - if (log) - log->Printf ("ProcessGDBRemote::%s pid %" PRIu64 ": normalized target architecture triple: %s", __FUNCTION__, GetID (), GetTarget ().GetArchitecture ().GetTriple ().getTriple ().c_str ()); - - if (error.Success()) - { - PlatformSP platform_sp = GetTarget().GetPlatform(); - if (platform_sp && platform_sp->IsConnected()) - SetUnixSignals(platform_sp->GetUnixSignals()); - else - SetUnixSignals(UnixSignals::Create(GetTarget().GetArchitecture())); - } + } + + const StateType state = SetThreadStopInfo(response); + if (state != eStateInvalid) { + SetPrivateState(state); + } else + error.SetErrorStringWithFormat( + "Process %" PRIu64 " was reported after connecting to " + "'%s', but state was not stopped: %s", + pid, remote_url.str().c_str(), StateAsCString(state)); + } else + error.SetErrorStringWithFormat("Process %" PRIu64 + " was reported after connecting to '%s', " + "but no stop reply packet was received", + pid, remote_url.str().c_str()); + } + + if (log) + log->Printf("ProcessGDBRemote::%s pid %" PRIu64 + ": normalizing target architecture initial triple: %s " + "(GetTarget().GetArchitecture().IsValid() %s, " + "m_gdb_comm.GetHostArchitecture().IsValid(): %s)", + __FUNCTION__, GetID(), + GetTarget().GetArchitecture().GetTriple().getTriple().c_str(), + GetTarget().GetArchitecture().IsValid() ? "true" : "false", + m_gdb_comm.GetHostArchitecture().IsValid() ? "true" : "false"); + + if (error.Success() && !GetTarget().GetArchitecture().IsValid() && + m_gdb_comm.GetHostArchitecture().IsValid()) { + // Prefer the *process'* architecture over that of the *host*, if available. + if (m_gdb_comm.GetProcessArchitecture().IsValid()) + GetTarget().SetArchitecture(m_gdb_comm.GetProcessArchitecture()); + else + GetTarget().SetArchitecture(m_gdb_comm.GetHostArchitecture()); + } + + if (log) + log->Printf("ProcessGDBRemote::%s pid %" PRIu64 + ": normalized target architecture triple: %s", + __FUNCTION__, GetID(), + GetTarget().GetArchitecture().GetTriple().getTriple().c_str()); + + if (error.Success()) { + PlatformSP platform_sp = GetTarget().GetPlatform(); + if (platform_sp && platform_sp->IsConnected()) + SetUnixSignals(platform_sp->GetUnixSignals()); + else + SetUnixSignals(UnixSignals::Create(GetTarget().GetArchitecture())); + } - return error; + return error; } -Error -ProcessGDBRemote::WillLaunchOrAttach () -{ - Error error; - m_stdio_communication.Clear (); - return error; +Error ProcessGDBRemote::WillLaunchOrAttach() { + Error error; + m_stdio_communication.Clear(); + return error; } //---------------------------------------------------------------------- // Process Control //---------------------------------------------------------------------- -Error -ProcessGDBRemote::DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info) -{ - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); - Error error; - - if (log) - log->Printf ("ProcessGDBRemote::%s() entered", __FUNCTION__); - - uint32_t launch_flags = launch_info.GetFlags().Get(); - FileSpec stdin_file_spec{}; - FileSpec stdout_file_spec{}; - FileSpec stderr_file_spec{}; - FileSpec working_dir = launch_info.GetWorkingDirectory(); - - const FileAction *file_action; - file_action = launch_info.GetFileActionForFD (STDIN_FILENO); - if (file_action) - { - if (file_action->GetAction() == FileAction::eFileActionOpen) - stdin_file_spec = file_action->GetFileSpec(); - } - file_action = launch_info.GetFileActionForFD (STDOUT_FILENO); - if (file_action) - { - if (file_action->GetAction() == FileAction::eFileActionOpen) - stdout_file_spec = file_action->GetFileSpec(); - } - file_action = launch_info.GetFileActionForFD (STDERR_FILENO); - if (file_action) - { - if (file_action->GetAction() == FileAction::eFileActionOpen) - stderr_file_spec = file_action->GetFileSpec(); - } - - if (log) - { - if (stdin_file_spec || stdout_file_spec || stderr_file_spec) - log->Printf ("ProcessGDBRemote::%s provided with STDIO paths via launch_info: stdin=%s, stdout=%s, stderr=%s", - __FUNCTION__, - stdin_file_spec ? stdin_file_spec.GetCString() : "<null>", - stdout_file_spec ? stdout_file_spec.GetCString() : "<null>", - stderr_file_spec ? stderr_file_spec.GetCString() : "<null>"); - else - log->Printf ("ProcessGDBRemote::%s no STDIO paths given via launch_info", __FUNCTION__); - } - - const bool disable_stdio = (launch_flags & eLaunchFlagDisableSTDIO) != 0; - if (stdin_file_spec || disable_stdio) - { - // the inferior will be reading stdin from the specified file - // or stdio is completely disabled - m_stdin_forward = false; - } +Error ProcessGDBRemote::DoLaunch(Module *exe_module, + ProcessLaunchInfo &launch_info) { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + Error error; + + if (log) + log->Printf("ProcessGDBRemote::%s() entered", __FUNCTION__); + + uint32_t launch_flags = launch_info.GetFlags().Get(); + FileSpec stdin_file_spec{}; + FileSpec stdout_file_spec{}; + FileSpec stderr_file_spec{}; + FileSpec working_dir = launch_info.GetWorkingDirectory(); + + const FileAction *file_action; + file_action = launch_info.GetFileActionForFD(STDIN_FILENO); + if (file_action) { + if (file_action->GetAction() == FileAction::eFileActionOpen) + stdin_file_spec = file_action->GetFileSpec(); + } + file_action = launch_info.GetFileActionForFD(STDOUT_FILENO); + if (file_action) { + if (file_action->GetAction() == FileAction::eFileActionOpen) + stdout_file_spec = file_action->GetFileSpec(); + } + file_action = launch_info.GetFileActionForFD(STDERR_FILENO); + if (file_action) { + if (file_action->GetAction() == FileAction::eFileActionOpen) + stderr_file_spec = file_action->GetFileSpec(); + } + + if (log) { + if (stdin_file_spec || stdout_file_spec || stderr_file_spec) + log->Printf("ProcessGDBRemote::%s provided with STDIO paths via " + "launch_info: stdin=%s, stdout=%s, stderr=%s", + __FUNCTION__, + stdin_file_spec ? stdin_file_spec.GetCString() : "<null>", + stdout_file_spec ? stdout_file_spec.GetCString() : "<null>", + stderr_file_spec ? stderr_file_spec.GetCString() : "<null>"); else - { - m_stdin_forward = true; - } - - // ::LogSetBitMask (GDBR_LOG_DEFAULT); - // ::LogSetOptions (LLDB_LOG_OPTION_THREADSAFE | LLDB_LOG_OPTION_PREPEND_TIMESTAMP | LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD); - // ::LogSetLogFile ("/dev/stdout"); - - ObjectFile * object_file = exe_module->GetObjectFile(); - if (object_file) - { - error = EstablishConnectionIfNeeded (launch_info); - if (error.Success()) - { - lldb_utility::PseudoTerminal pty; - const bool disable_stdio = (launch_flags & eLaunchFlagDisableSTDIO) != 0; - - PlatformSP platform_sp (GetTarget().GetPlatform()); - if (disable_stdio) - { - // set to /dev/null unless redirected to a file above - if (!stdin_file_spec) - stdin_file_spec.SetFile(FileSystem::DEV_NULL, false); - if (!stdout_file_spec) - stdout_file_spec.SetFile(FileSystem::DEV_NULL, false); - if (!stderr_file_spec) - stderr_file_spec.SetFile(FileSystem::DEV_NULL, false); - } - else if (platform_sp && platform_sp->IsHost()) - { - // If the debugserver is local and we aren't disabling STDIO, lets use - // a pseudo terminal to instead of relying on the 'O' packets for stdio - // since 'O' packets can really slow down debugging if the inferior - // does a lot of output. - if ((!stdin_file_spec || !stdout_file_spec || !stderr_file_spec) && - pty.OpenFirstAvailableMaster(O_RDWR|O_NOCTTY, NULL, 0)) - { - FileSpec slave_name{pty.GetSlaveName(NULL, 0), false}; - - if (!stdin_file_spec) - stdin_file_spec = slave_name; - - if (!stdout_file_spec) - stdout_file_spec = slave_name; - - if (!stderr_file_spec) - stderr_file_spec = slave_name; - } - if (log) - log->Printf ("ProcessGDBRemote::%s adjusted STDIO paths for local platform (IsHost() is true) using slave: stdin=%s, stdout=%s, stderr=%s", - __FUNCTION__, - stdin_file_spec ? stdin_file_spec.GetCString() : "<null>", - stdout_file_spec ? stdout_file_spec.GetCString() : "<null>", - stderr_file_spec ? stderr_file_spec.GetCString() : "<null>"); - } - - if (log) - log->Printf ("ProcessGDBRemote::%s final STDIO paths after all adjustments: stdin=%s, stdout=%s, stderr=%s", - __FUNCTION__, - stdin_file_spec ? stdin_file_spec.GetCString() : "<null>", - stdout_file_spec ? stdout_file_spec.GetCString() : "<null>", - stderr_file_spec ? stderr_file_spec.GetCString() : "<null>"); - - if (stdin_file_spec) - m_gdb_comm.SetSTDIN(stdin_file_spec); - if (stdout_file_spec) - m_gdb_comm.SetSTDOUT(stdout_file_spec); - if (stderr_file_spec) - m_gdb_comm.SetSTDERR(stderr_file_spec); - - m_gdb_comm.SetDisableASLR (launch_flags & eLaunchFlagDisableASLR); - m_gdb_comm.SetDetachOnError (launch_flags & eLaunchFlagDetachOnError); - - m_gdb_comm.SendLaunchArchPacket (GetTarget().GetArchitecture().GetArchitectureName()); - - const char * launch_event_data = launch_info.GetLaunchEventData(); - if (launch_event_data != NULL && *launch_event_data != '\0') - m_gdb_comm.SendLaunchEventDataPacket (launch_event_data); - - if (working_dir) - { - m_gdb_comm.SetWorkingDir (working_dir); - } - - // Send the environment and the program + arguments after we connect - const Args &environment = launch_info.GetEnvironmentEntries(); - if (environment.GetArgumentCount()) - { - size_t num_environment_entries = environment.GetArgumentCount(); - for (size_t i=0; i<num_environment_entries; ++i) - { - const char *env_entry = environment.GetArgumentAtIndex(i); - if (env_entry == NULL || m_gdb_comm.SendEnvironmentPacket(env_entry) != 0) - break; - } - } - - { - // Scope for the scoped timeout object - GDBRemoteCommunication::ScopedTimeout timeout (m_gdb_comm, 10); - - int arg_packet_err = m_gdb_comm.SendArgumentsPacket (launch_info); - if (arg_packet_err == 0) - { - std::string error_str; - if (m_gdb_comm.GetLaunchSuccess (error_str)) - { - SetID (m_gdb_comm.GetCurrentProcessID ()); - } - else - { - error.SetErrorString (error_str.c_str()); - } - } - else - { - error.SetErrorStringWithFormat("'A' packet returned an error: %i", arg_packet_err); - } - } - - if (GetID() == LLDB_INVALID_PROCESS_ID) - { - if (log) - log->Printf("failed to connect to debugserver: %s", error.AsCString()); - KillDebugserverProcess (); - return error; - } - - StringExtractorGDBRemote response; - if (m_gdb_comm.GetStopReply(response)) - { - SetLastStopPacket(response); - // '?' Packets must be handled differently in non-stop mode - if (GetTarget().GetNonStopModeEnabled()) - HandleStopReplySequence(); - - const ArchSpec &process_arch = m_gdb_comm.GetProcessArchitecture(); - - if (process_arch.IsValid()) - { - GetTarget().MergeArchitecture(process_arch); - } - else - { - const ArchSpec &host_arch = m_gdb_comm.GetHostArchitecture(); - if (host_arch.IsValid()) - GetTarget().MergeArchitecture(host_arch); - } - - SetPrivateState (SetThreadStopInfo (response)); - - if (!disable_stdio) - { - if (pty.GetMasterFileDescriptor() != lldb_utility::PseudoTerminal::invalid_fd) - SetSTDIOFileDescriptor (pty.ReleaseMasterFileDescriptor()); - } - } + log->Printf("ProcessGDBRemote::%s no STDIO paths given via launch_info", + __FUNCTION__); + } + + const bool disable_stdio = (launch_flags & eLaunchFlagDisableSTDIO) != 0; + if (stdin_file_spec || disable_stdio) { + // the inferior will be reading stdin from the specified file + // or stdio is completely disabled + m_stdin_forward = false; + } else { + m_stdin_forward = true; + } + + // ::LogSetBitMask (GDBR_LOG_DEFAULT); + // ::LogSetOptions (LLDB_LOG_OPTION_THREADSAFE | + // LLDB_LOG_OPTION_PREPEND_TIMESTAMP | + // LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD); + // ::LogSetLogFile ("/dev/stdout"); + + ObjectFile *object_file = exe_module->GetObjectFile(); + if (object_file) { + error = EstablishConnectionIfNeeded(launch_info); + if (error.Success()) { + lldb_utility::PseudoTerminal pty; + const bool disable_stdio = (launch_flags & eLaunchFlagDisableSTDIO) != 0; + + PlatformSP platform_sp(GetTarget().GetPlatform()); + if (disable_stdio) { + // set to /dev/null unless redirected to a file above + if (!stdin_file_spec) + stdin_file_spec.SetFile(FileSystem::DEV_NULL, false); + if (!stdout_file_spec) + stdout_file_spec.SetFile(FileSystem::DEV_NULL, false); + if (!stderr_file_spec) + stderr_file_spec.SetFile(FileSystem::DEV_NULL, false); + } else if (platform_sp && platform_sp->IsHost()) { + // If the debugserver is local and we aren't disabling STDIO, lets use + // a pseudo terminal to instead of relying on the 'O' packets for stdio + // since 'O' packets can really slow down debugging if the inferior + // does a lot of output. + if ((!stdin_file_spec || !stdout_file_spec || !stderr_file_spec) && + pty.OpenFirstAvailableMaster(O_RDWR | O_NOCTTY, NULL, 0)) { + FileSpec slave_name{pty.GetSlaveName(NULL, 0), false}; + + if (!stdin_file_spec) + stdin_file_spec = slave_name; + + if (!stdout_file_spec) + stdout_file_spec = slave_name; + + if (!stderr_file_spec) + stderr_file_spec = slave_name; } - else - { - if (log) - log->Printf("failed to connect to debugserver: %s", error.AsCString()); + if (log) + log->Printf( + "ProcessGDBRemote::%s adjusted STDIO paths for local platform " + "(IsHost() is true) using slave: stdin=%s, stdout=%s, stderr=%s", + __FUNCTION__, + stdin_file_spec ? stdin_file_spec.GetCString() : "<null>", + stdout_file_spec ? stdout_file_spec.GetCString() : "<null>", + stderr_file_spec ? stderr_file_spec.GetCString() : "<null>"); + } + + if (log) + log->Printf("ProcessGDBRemote::%s final STDIO paths after all " + "adjustments: stdin=%s, stdout=%s, stderr=%s", + __FUNCTION__, + stdin_file_spec ? stdin_file_spec.GetCString() : "<null>", + stdout_file_spec ? stdout_file_spec.GetCString() : "<null>", + stderr_file_spec ? stderr_file_spec.GetCString() + : "<null>"); + + if (stdin_file_spec) + m_gdb_comm.SetSTDIN(stdin_file_spec); + if (stdout_file_spec) + m_gdb_comm.SetSTDOUT(stdout_file_spec); + if (stderr_file_spec) + m_gdb_comm.SetSTDERR(stderr_file_spec); + + m_gdb_comm.SetDisableASLR(launch_flags & eLaunchFlagDisableASLR); + m_gdb_comm.SetDetachOnError(launch_flags & eLaunchFlagDetachOnError); + + m_gdb_comm.SendLaunchArchPacket( + GetTarget().GetArchitecture().GetArchitectureName()); + + const char *launch_event_data = launch_info.GetLaunchEventData(); + if (launch_event_data != NULL && *launch_event_data != '\0') + m_gdb_comm.SendLaunchEventDataPacket(launch_event_data); + + if (working_dir) { + m_gdb_comm.SetWorkingDir(working_dir); + } + + // Send the environment and the program + arguments after we connect + const Args &environment = launch_info.GetEnvironmentEntries(); + if (environment.GetArgumentCount()) { + size_t num_environment_entries = environment.GetArgumentCount(); + for (size_t i = 0; i < num_environment_entries; ++i) { + const char *env_entry = environment.GetArgumentAtIndex(i); + if (env_entry == NULL || + m_gdb_comm.SendEnvironmentPacket(env_entry) != 0) + break; } - } - else - { - // Set our user ID to an invalid process ID. - SetID(LLDB_INVALID_PROCESS_ID); - error.SetErrorStringWithFormat ("failed to get object file from '%s' for arch %s", - exe_module->GetFileSpec().GetFilename().AsCString(), - exe_module->GetArchitecture().GetArchitectureName()); - } - return error; - -} - + } -Error -ProcessGDBRemote::ConnectToDebugserver (const char *connect_url) -{ - Error error; - // Only connect if we have a valid connect URL - Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + { + // Scope for the scoped timeout object + GDBRemoteCommunication::ScopedTimeout timeout(m_gdb_comm, + std::chrono::seconds(10)); + + int arg_packet_err = m_gdb_comm.SendArgumentsPacket(launch_info); + if (arg_packet_err == 0) { + std::string error_str; + if (m_gdb_comm.GetLaunchSuccess(error_str)) { + SetID(m_gdb_comm.GetCurrentProcessID()); + } else { + error.SetErrorString(error_str.c_str()); + } + } else { + error.SetErrorStringWithFormat("'A' packet returned an error: %i", + arg_packet_err); + } + } - if (connect_url && connect_url[0]) - { + if (GetID() == LLDB_INVALID_PROCESS_ID) { if (log) - log->Printf("ProcessGDBRemote::%s Connecting to %s", __FUNCTION__, connect_url); - std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor()); - if (conn_ap.get()) - { - const uint32_t max_retry_count = 50; - uint32_t retry_count = 0; - while (!m_gdb_comm.IsConnected()) - { - if (conn_ap->Connect(connect_url, &error) == eConnectionStatusSuccess) - { - m_gdb_comm.SetConnection (conn_ap.release()); - break; - } - else if (error.WasInterrupted()) - { - // If we were interrupted, don't keep retrying. - break; - } + log->Printf("failed to connect to debugserver: %s", + error.AsCString()); + KillDebugserverProcess(); + return error; + } - retry_count++; + StringExtractorGDBRemote response; + if (m_gdb_comm.GetStopReply(response)) { + SetLastStopPacket(response); + // '?' Packets must be handled differently in non-stop mode + if (GetTarget().GetNonStopModeEnabled()) + HandleStopReplySequence(); + + const ArchSpec &process_arch = m_gdb_comm.GetProcessArchitecture(); + + if (process_arch.IsValid()) { + GetTarget().MergeArchitecture(process_arch); + } else { + const ArchSpec &host_arch = m_gdb_comm.GetHostArchitecture(); + if (host_arch.IsValid()) + GetTarget().MergeArchitecture(host_arch); + } - if (retry_count >= max_retry_count) - break; + SetPrivateState(SetThreadStopInfo(response)); - usleep (100000); - } + if (!disable_stdio) { + if (pty.GetMasterFileDescriptor() != + lldb_utility::PseudoTerminal::invalid_fd) + SetSTDIOFileDescriptor(pty.ReleaseMasterFileDescriptor()); } - } + } + } else { + if (log) + log->Printf("failed to connect to debugserver: %s", error.AsCString()); + } + } else { + // Set our user ID to an invalid process ID. + SetID(LLDB_INVALID_PROCESS_ID); + error.SetErrorStringWithFormat( + "failed to get object file from '%s' for arch %s", + exe_module->GetFileSpec().GetFilename().AsCString(), + exe_module->GetArchitecture().GetArchitectureName()); + } + return error; +} - if (!m_gdb_comm.IsConnected()) - { - if (error.Success()) - error.SetErrorString("not connected to remote gdb server"); - return error; - } +Error ProcessGDBRemote::ConnectToDebugserver(llvm::StringRef connect_url) { + Error error; + // Only connect if we have a valid connect URL + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + if (!connect_url.empty()) { + if (log) + log->Printf("ProcessGDBRemote::%s Connecting to %s", __FUNCTION__, + connect_url.str().c_str()); + std::unique_ptr<ConnectionFileDescriptor> conn_ap( + new ConnectionFileDescriptor()); + if (conn_ap.get()) { + const uint32_t max_retry_count = 50; + uint32_t retry_count = 0; + while (!m_gdb_comm.IsConnected()) { + if (conn_ap->Connect(connect_url, &error) == eConnectionStatusSuccess) { + m_gdb_comm.SetConnection(conn_ap.release()); + break; + } else if (error.WasInterrupted()) { + // If we were interrupted, don't keep retrying. + break; + } - // Start the communications read thread so all incoming data can be - // parsed into packets and queued as they arrive. - if (GetTarget().GetNonStopModeEnabled()) - m_gdb_comm.StartReadThread(); + retry_count++; - // We always seem to be able to open a connection to a local port - // so we need to make sure we can then send data to it. If we can't - // then we aren't actually connected to anything, so try and do the - // handshake with the remote GDB server and make sure that goes - // alright. - if (!m_gdb_comm.HandshakeWithServer (&error)) - { - m_gdb_comm.Disconnect(); - if (error.Success()) - error.SetErrorString("not connected to remote gdb server"); - return error; + if (retry_count >= max_retry_count) + break; + + usleep(100000); + } } + } - // Send $QNonStop:1 packet on startup if required - if (GetTarget().GetNonStopModeEnabled()) - GetTarget().SetNonStopModeEnabled (m_gdb_comm.SetNonStopMode(true)); + if (!m_gdb_comm.IsConnected()) { + if (error.Success()) + error.SetErrorString("not connected to remote gdb server"); + return error; + } + + // Start the communications read thread so all incoming data can be + // parsed into packets and queued as they arrive. + if (GetTarget().GetNonStopModeEnabled()) + m_gdb_comm.StartReadThread(); + + // We always seem to be able to open a connection to a local port + // so we need to make sure we can then send data to it. If we can't + // then we aren't actually connected to anything, so try and do the + // handshake with the remote GDB server and make sure that goes + // alright. + if (!m_gdb_comm.HandshakeWithServer(&error)) { + m_gdb_comm.Disconnect(); + if (error.Success()) + error.SetErrorString("not connected to remote gdb server"); + return error; + } - m_gdb_comm.GetEchoSupported (); - m_gdb_comm.GetThreadSuffixSupported (); - m_gdb_comm.GetListThreadsInStopReplySupported (); - m_gdb_comm.GetHostInfo (); - m_gdb_comm.GetVContSupported ('c'); - m_gdb_comm.GetVAttachOrWaitSupported(); + // Send $QNonStop:1 packet on startup if required + if (GetTarget().GetNonStopModeEnabled()) + GetTarget().SetNonStopModeEnabled(m_gdb_comm.SetNonStopMode(true)); - // Ask the remote server for the default thread id - if (GetTarget().GetNonStopModeEnabled()) - m_gdb_comm.GetDefaultThreadId(m_initial_tid); + m_gdb_comm.GetEchoSupported(); + m_gdb_comm.GetThreadSuffixSupported(); + m_gdb_comm.GetListThreadsInStopReplySupported(); + m_gdb_comm.GetHostInfo(); + m_gdb_comm.GetVContSupported('c'); + m_gdb_comm.GetVAttachOrWaitSupported(); + // Ask the remote server for the default thread id + if (GetTarget().GetNonStopModeEnabled()) + m_gdb_comm.GetDefaultThreadId(m_initial_tid); - size_t num_cmds = GetExtraStartupCommands().GetArgumentCount(); - for (size_t idx = 0; idx < num_cmds; idx++) - { - StringExtractorGDBRemote response; - m_gdb_comm.SendPacketAndWaitForResponse (GetExtraStartupCommands().GetArgumentAtIndex(idx), response, false); - } - return error; + size_t num_cmds = GetExtraStartupCommands().GetArgumentCount(); + for (size_t idx = 0; idx < num_cmds; idx++) { + StringExtractorGDBRemote response; + m_gdb_comm.SendPacketAndWaitForResponse( + GetExtraStartupCommands().GetArgumentAtIndex(idx), response, false); + } + return error; } -void -ProcessGDBRemote::DidLaunchOrAttach (ArchSpec& process_arch) -{ - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); - if (log) - log->Printf ("ProcessGDBRemote::DidLaunch()"); - if (GetID() != LLDB_INVALID_PROCESS_ID) - { - BuildDynamicRegisterInfo (false); +void ProcessGDBRemote::DidLaunchOrAttach(ArchSpec &process_arch) { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + if (log) + log->Printf("ProcessGDBRemote::%s()", __FUNCTION__); + if (GetID() != LLDB_INVALID_PROCESS_ID) { + BuildDynamicRegisterInfo(false); - // See if the GDB server supports the qHostInfo information + // See if the GDB server supports the qHostInfo information + // See if the GDB server supports the qProcessInfo packet, if so + // prefer that over the Host information as it will be more specific + // to our process. - // See if the GDB server supports the qProcessInfo packet, if so - // prefer that over the Host information as it will be more specific - // to our process. + const ArchSpec &remote_process_arch = m_gdb_comm.GetProcessArchitecture(); + if (remote_process_arch.IsValid()) { + process_arch = remote_process_arch; + if (log) + log->Printf("ProcessGDBRemote::%s gdb-remote had process architecture, " + "using %s %s", + __FUNCTION__, process_arch.GetArchitectureName() + ? process_arch.GetArchitectureName() + : "<null>", + process_arch.GetTriple().getTriple().c_str() + ? process_arch.GetTriple().getTriple().c_str() + : "<null>"); + } else { + process_arch = m_gdb_comm.GetHostArchitecture(); + if (log) + log->Printf("ProcessGDBRemote::%s gdb-remote did not have process " + "architecture, using gdb-remote host architecture %s %s", + __FUNCTION__, process_arch.GetArchitectureName() + ? process_arch.GetArchitectureName() + : "<null>", + process_arch.GetTriple().getTriple().c_str() + ? process_arch.GetTriple().getTriple().c_str() + : "<null>"); + } + + if (process_arch.IsValid()) { + const ArchSpec &target_arch = GetTarget().GetArchitecture(); + if (target_arch.IsValid()) { + if (log) + log->Printf( + "ProcessGDBRemote::%s analyzing target arch, currently %s %s", + __FUNCTION__, target_arch.GetArchitectureName() + ? target_arch.GetArchitectureName() + : "<null>", + target_arch.GetTriple().getTriple().c_str() + ? target_arch.GetTriple().getTriple().c_str() + : "<null>"); + + // If the remote host is ARM and we have apple as the vendor, then + // ARM executables and shared libraries can have mixed ARM + // architectures. + // You can have an armv6 executable, and if the host is armv7, then the + // system will load the best possible architecture for all shared + // libraries + // it has, so we really need to take the remote host architecture as our + // defacto architecture in this case. + + if ((process_arch.GetMachine() == llvm::Triple::arm || + process_arch.GetMachine() == llvm::Triple::thumb) && + process_arch.GetTriple().getVendor() == llvm::Triple::Apple) { + GetTarget().SetArchitecture(process_arch); + if (log) + log->Printf("ProcessGDBRemote::%s remote process is ARM/Apple, " + "setting target arch to %s %s", + __FUNCTION__, process_arch.GetArchitectureName() + ? process_arch.GetArchitectureName() + : "<null>", + process_arch.GetTriple().getTriple().c_str() + ? process_arch.GetTriple().getTriple().c_str() + : "<null>"); + } else { + // Fill in what is missing in the triple + const llvm::Triple &remote_triple = process_arch.GetTriple(); + llvm::Triple new_target_triple = target_arch.GetTriple(); + if (new_target_triple.getVendorName().size() == 0) { + new_target_triple.setVendor(remote_triple.getVendor()); + + if (new_target_triple.getOSName().size() == 0) { + new_target_triple.setOS(remote_triple.getOS()); + + if (new_target_triple.getEnvironmentName().size() == 0) + new_target_triple.setEnvironment( + remote_triple.getEnvironment()); + } - const ArchSpec &remote_process_arch = m_gdb_comm.GetProcessArchitecture(); - if (remote_process_arch.IsValid()) - { - process_arch = remote_process_arch; - if (log) - log->Printf ("ProcessGDBRemote::%s gdb-remote had process architecture, using %s %s", - __FUNCTION__, - process_arch.GetArchitectureName () ? process_arch.GetArchitectureName () : "<null>", - process_arch.GetTriple().getTriple ().c_str() ? process_arch.GetTriple().getTriple ().c_str() : "<null>"); + ArchSpec new_target_arch = target_arch; + new_target_arch.SetTriple(new_target_triple); + GetTarget().SetArchitecture(new_target_arch); + } } - else - { - process_arch = m_gdb_comm.GetHostArchitecture(); - if (log) - log->Printf ("ProcessGDBRemote::%s gdb-remote did not have process architecture, using gdb-remote host architecture %s %s", - __FUNCTION__, - process_arch.GetArchitectureName () ? process_arch.GetArchitectureName () : "<null>", - process_arch.GetTriple().getTriple ().c_str() ? process_arch.GetTriple().getTriple ().c_str() : "<null>"); - } - - if (process_arch.IsValid()) - { - const ArchSpec &target_arch = GetTarget().GetArchitecture(); - if (target_arch.IsValid()) - { - if (log) - log->Printf ("ProcessGDBRemote::%s analyzing target arch, currently %s %s", - __FUNCTION__, - target_arch.GetArchitectureName () ? target_arch.GetArchitectureName () : "<null>", - target_arch.GetTriple().getTriple ().c_str() ? target_arch.GetTriple().getTriple ().c_str() : "<null>"); - - // If the remote host is ARM and we have apple as the vendor, then - // ARM executables and shared libraries can have mixed ARM architectures. - // You can have an armv6 executable, and if the host is armv7, then the - // system will load the best possible architecture for all shared libraries - // it has, so we really need to take the remote host architecture as our - // defacto architecture in this case. - - if ((process_arch.GetMachine() == llvm::Triple::arm || process_arch.GetMachine() == llvm::Triple::thumb) - && process_arch.GetTriple().getVendor() == llvm::Triple::Apple) - { - GetTarget().SetArchitecture (process_arch); - if (log) - log->Printf ("ProcessGDBRemote::%s remote process is ARM/Apple, setting target arch to %s %s", - __FUNCTION__, - process_arch.GetArchitectureName () ? process_arch.GetArchitectureName () : "<null>", - process_arch.GetTriple().getTriple ().c_str() ? process_arch.GetTriple().getTriple ().c_str() : "<null>"); - } - else - { - // Fill in what is missing in the triple - const llvm::Triple &remote_triple = process_arch.GetTriple(); - llvm::Triple new_target_triple = target_arch.GetTriple(); - if (new_target_triple.getVendorName().size() == 0) - { - new_target_triple.setVendor (remote_triple.getVendor()); - - if (new_target_triple.getOSName().size() == 0) - { - new_target_triple.setOS (remote_triple.getOS()); - - if (new_target_triple.getEnvironmentName().size() == 0) - new_target_triple.setEnvironment (remote_triple.getEnvironment()); - } - - ArchSpec new_target_arch = target_arch; - new_target_arch.SetTriple(new_target_triple); - GetTarget().SetArchitecture(new_target_arch); - } - } - if (log) - log->Printf ("ProcessGDBRemote::%s final target arch after adjustments for remote architecture: %s %s", - __FUNCTION__, - target_arch.GetArchitectureName () ? target_arch.GetArchitectureName () : "<null>", - target_arch.GetTriple().getTriple ().c_str() ? target_arch.GetTriple().getTriple ().c_str() : "<null>"); - } - else - { - // The target doesn't have a valid architecture yet, set it from - // the architecture we got from the remote GDB server - GetTarget().SetArchitecture (process_arch); - } - } - } + if (log) + log->Printf("ProcessGDBRemote::%s final target arch after " + "adjustments for remote architecture: %s %s", + __FUNCTION__, target_arch.GetArchitectureName() + ? target_arch.GetArchitectureName() + : "<null>", + target_arch.GetTriple().getTriple().c_str() + ? target_arch.GetTriple().getTriple().c_str() + : "<null>"); + } else { + // The target doesn't have a valid architecture yet, set it from + // the architecture we got from the remote GDB server + GetTarget().SetArchitecture(process_arch); + } + } + + // Find out which StructuredDataPlugins are supported by the + // debug monitor. These plugins transmit data over async $J packets. + auto supported_packets_array = + m_gdb_comm.GetSupportedStructuredDataPlugins(); + if (supported_packets_array) + MapSupportedStructuredDataPlugins(*supported_packets_array); + } } -void -ProcessGDBRemote::DidLaunch () -{ - ArchSpec process_arch; - DidLaunchOrAttach (process_arch); +void ProcessGDBRemote::DidLaunch() { + ArchSpec process_arch; + DidLaunchOrAttach(process_arch); } -Error -ProcessGDBRemote::DoAttachToProcessWithID (lldb::pid_t attach_pid, const ProcessAttachInfo &attach_info) -{ - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); - Error error; - - if (log) - log->Printf ("ProcessGDBRemote::%s()", __FUNCTION__); - - // Clear out and clean up from any current state - Clear(); - if (attach_pid != LLDB_INVALID_PROCESS_ID) - { - error = EstablishConnectionIfNeeded (attach_info); - if (error.Success()) - { - m_gdb_comm.SetDetachOnError(attach_info.GetDetachOnError()); - - char packet[64]; - const int packet_len = ::snprintf (packet, sizeof(packet), "vAttach;%" PRIx64, attach_pid); - SetID (attach_pid); - m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncContinue, new EventDataBytes (packet, packet_len)); - } - else - SetExitStatus (-1, error.AsCString()); - } - - return error; +Error ProcessGDBRemote::DoAttachToProcessWithID( + lldb::pid_t attach_pid, const ProcessAttachInfo &attach_info) { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + Error error; + + if (log) + log->Printf("ProcessGDBRemote::%s()", __FUNCTION__); + + // Clear out and clean up from any current state + Clear(); + if (attach_pid != LLDB_INVALID_PROCESS_ID) { + error = EstablishConnectionIfNeeded(attach_info); + if (error.Success()) { + m_gdb_comm.SetDetachOnError(attach_info.GetDetachOnError()); + + char packet[64]; + const int packet_len = + ::snprintf(packet, sizeof(packet), "vAttach;%" PRIx64, attach_pid); + SetID(attach_pid); + m_async_broadcaster.BroadcastEvent( + eBroadcastBitAsyncContinue, new EventDataBytes(packet, packet_len)); + } else + SetExitStatus(-1, error.AsCString()); + } + + return error; } -Error -ProcessGDBRemote::DoAttachToProcessWithName (const char *process_name, const ProcessAttachInfo &attach_info) -{ - Error error; - // Clear out and clean up from any current state - Clear(); - - if (process_name && process_name[0]) - { - error = EstablishConnectionIfNeeded (attach_info); - if (error.Success()) - { - StreamString packet; - - m_gdb_comm.SetDetachOnError(attach_info.GetDetachOnError()); - - if (attach_info.GetWaitForLaunch()) - { - if (!m_gdb_comm.GetVAttachOrWaitSupported()) - { - packet.PutCString ("vAttachWait"); - } - else - { - if (attach_info.GetIgnoreExisting()) - packet.PutCString("vAttachWait"); - else - packet.PutCString ("vAttachOrWait"); - } - } - else - packet.PutCString("vAttachName"); - packet.PutChar(';'); - packet.PutBytesAsRawHex8(process_name, strlen(process_name), endian::InlHostByteOrder(), endian::InlHostByteOrder()); - - m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncContinue, new EventDataBytes (packet.GetData(), packet.GetSize())); - +Error ProcessGDBRemote::DoAttachToProcessWithName( + const char *process_name, const ProcessAttachInfo &attach_info) { + Error error; + // Clear out and clean up from any current state + Clear(); + + if (process_name && process_name[0]) { + error = EstablishConnectionIfNeeded(attach_info); + if (error.Success()) { + StreamString packet; + + m_gdb_comm.SetDetachOnError(attach_info.GetDetachOnError()); + + if (attach_info.GetWaitForLaunch()) { + if (!m_gdb_comm.GetVAttachOrWaitSupported()) { + packet.PutCString("vAttachWait"); + } else { + if (attach_info.GetIgnoreExisting()) + packet.PutCString("vAttachWait"); + else + packet.PutCString("vAttachOrWait"); } - else - SetExitStatus (-1, error.AsCString()); - } - return error; + } else + packet.PutCString("vAttachName"); + packet.PutChar(';'); + packet.PutBytesAsRawHex8(process_name, strlen(process_name), + endian::InlHostByteOrder(), + endian::InlHostByteOrder()); + + m_async_broadcaster.BroadcastEvent( + eBroadcastBitAsyncContinue, + new EventDataBytes(packet.GetString().data(), packet.GetSize())); + + } else + SetExitStatus(-1, error.AsCString()); + } + return error; } -void -ProcessGDBRemote::DidExit () -{ - // When we exit, disconnect from the GDB server communications - m_gdb_comm.Disconnect(); +void ProcessGDBRemote::DidExit() { + // When we exit, disconnect from the GDB server communications + m_gdb_comm.Disconnect(); } -void -ProcessGDBRemote::DidAttach (ArchSpec &process_arch) -{ - // If you can figure out what the architecture is, fill it in here. - process_arch.Clear(); - DidLaunchOrAttach (process_arch); +void ProcessGDBRemote::DidAttach(ArchSpec &process_arch) { + // If you can figure out what the architecture is, fill it in here. + process_arch.Clear(); + DidLaunchOrAttach(process_arch); } - -Error -ProcessGDBRemote::WillResume () -{ - m_continue_c_tids.clear(); - m_continue_C_tids.clear(); - m_continue_s_tids.clear(); - m_continue_S_tids.clear(); - m_jstopinfo_sp.reset(); - m_jthreadsinfo_sp.reset(); - return Error(); +Error ProcessGDBRemote::WillResume() { + m_continue_c_tids.clear(); + m_continue_C_tids.clear(); + m_continue_s_tids.clear(); + m_continue_S_tids.clear(); + m_jstopinfo_sp.reset(); + m_jthreadsinfo_sp.reset(); + return Error(); } -Error -ProcessGDBRemote::DoResume () -{ - Error error; - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); - if (log) - log->Printf ("ProcessGDBRemote::Resume()"); - - ListenerSP listener_sp (Listener::MakeListener("gdb-remote.resume-packet-sent")); - if (listener_sp->StartListeningForEvents (&m_gdb_comm, GDBRemoteCommunication::eBroadcastBitRunPacketSent)) - { - listener_sp->StartListeningForEvents (&m_async_broadcaster, ProcessGDBRemote::eBroadcastBitAsyncThreadDidExit); - - const size_t num_threads = GetThreadList().GetSize(); - - StreamString continue_packet; - bool continue_packet_error = false; - if (m_gdb_comm.HasAnyVContSupport ()) - { - if (!GetTarget().GetNonStopModeEnabled() && - (m_continue_c_tids.size() == num_threads || - (m_continue_c_tids.empty() && - m_continue_C_tids.empty() && - m_continue_s_tids.empty() && - m_continue_S_tids.empty()))) - { - // All threads are continuing, just send a "c" packet - continue_packet.PutCString ("c"); - } - else - { - continue_packet.PutCString ("vCont"); - - if (!m_continue_c_tids.empty()) - { - if (m_gdb_comm.GetVContSupported ('c')) - { - for (tid_collection::const_iterator t_pos = m_continue_c_tids.begin(), t_end = m_continue_c_tids.end(); t_pos != t_end; ++t_pos) - continue_packet.Printf(";c:%4.4" PRIx64, *t_pos); - } - else - continue_packet_error = true; - } - - if (!continue_packet_error && !m_continue_C_tids.empty()) - { - if (m_gdb_comm.GetVContSupported ('C')) - { - for (tid_sig_collection::const_iterator s_pos = m_continue_C_tids.begin(), s_end = m_continue_C_tids.end(); s_pos != s_end; ++s_pos) - continue_packet.Printf(";C%2.2x:%4.4" PRIx64, s_pos->second, s_pos->first); - } - else - continue_packet_error = true; - } - - if (!continue_packet_error && !m_continue_s_tids.empty()) - { - if (m_gdb_comm.GetVContSupported ('s')) - { - for (tid_collection::const_iterator t_pos = m_continue_s_tids.begin(), t_end = m_continue_s_tids.end(); t_pos != t_end; ++t_pos) - continue_packet.Printf(";s:%4.4" PRIx64, *t_pos); - } - else - continue_packet_error = true; - } +Error ProcessGDBRemote::DoResume() { + Error error; + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + if (log) + log->Printf("ProcessGDBRemote::Resume()"); + + ListenerSP listener_sp( + Listener::MakeListener("gdb-remote.resume-packet-sent")); + if (listener_sp->StartListeningForEvents( + &m_gdb_comm, GDBRemoteCommunication::eBroadcastBitRunPacketSent)) { + listener_sp->StartListeningForEvents( + &m_async_broadcaster, + ProcessGDBRemote::eBroadcastBitAsyncThreadDidExit); + + const size_t num_threads = GetThreadList().GetSize(); + + StreamString continue_packet; + bool continue_packet_error = false; + if (m_gdb_comm.HasAnyVContSupport()) { + if (!GetTarget().GetNonStopModeEnabled() && + (m_continue_c_tids.size() == num_threads || + (m_continue_c_tids.empty() && m_continue_C_tids.empty() && + m_continue_s_tids.empty() && m_continue_S_tids.empty()))) { + // All threads are continuing, just send a "c" packet + continue_packet.PutCString("c"); + } else { + continue_packet.PutCString("vCont"); + + if (!m_continue_c_tids.empty()) { + if (m_gdb_comm.GetVContSupported('c')) { + for (tid_collection::const_iterator + t_pos = m_continue_c_tids.begin(), + t_end = m_continue_c_tids.end(); + t_pos != t_end; ++t_pos) + continue_packet.Printf(";c:%4.4" PRIx64, *t_pos); + } else + continue_packet_error = true; + } - if (!continue_packet_error && !m_continue_S_tids.empty()) - { - if (m_gdb_comm.GetVContSupported ('S')) - { - for (tid_sig_collection::const_iterator s_pos = m_continue_S_tids.begin(), s_end = m_continue_S_tids.end(); s_pos != s_end; ++s_pos) - continue_packet.Printf(";S%2.2x:%4.4" PRIx64, s_pos->second, s_pos->first); - } - else - continue_packet_error = true; - } + if (!continue_packet_error && !m_continue_C_tids.empty()) { + if (m_gdb_comm.GetVContSupported('C')) { + for (tid_sig_collection::const_iterator + s_pos = m_continue_C_tids.begin(), + s_end = m_continue_C_tids.end(); + s_pos != s_end; ++s_pos) + continue_packet.Printf(";C%2.2x:%4.4" PRIx64, s_pos->second, + s_pos->first); + } else + continue_packet_error = true; + } - if (continue_packet_error) - continue_packet.GetString().clear(); - } + if (!continue_packet_error && !m_continue_s_tids.empty()) { + if (m_gdb_comm.GetVContSupported('s')) { + for (tid_collection::const_iterator + t_pos = m_continue_s_tids.begin(), + t_end = m_continue_s_tids.end(); + t_pos != t_end; ++t_pos) + continue_packet.Printf(";s:%4.4" PRIx64, *t_pos); + } else + continue_packet_error = true; } - else + + if (!continue_packet_error && !m_continue_S_tids.empty()) { + if (m_gdb_comm.GetVContSupported('S')) { + for (tid_sig_collection::const_iterator + s_pos = m_continue_S_tids.begin(), + s_end = m_continue_S_tids.end(); + s_pos != s_end; ++s_pos) + continue_packet.Printf(";S%2.2x:%4.4" PRIx64, s_pos->second, + s_pos->first); + } else continue_packet_error = true; + } if (continue_packet_error) - { - // Either no vCont support, or we tried to use part of the vCont - // packet that wasn't supported by the remote GDB server. - // We need to try and make a simple packet that can do our continue - const size_t num_continue_c_tids = m_continue_c_tids.size(); - const size_t num_continue_C_tids = m_continue_C_tids.size(); - const size_t num_continue_s_tids = m_continue_s_tids.size(); - const size_t num_continue_S_tids = m_continue_S_tids.size(); - if (num_continue_c_tids > 0) - { - if (num_continue_c_tids == num_threads) - { - // All threads are resuming... - m_gdb_comm.SetCurrentThreadForRun (-1); - continue_packet.PutChar ('c'); - continue_packet_error = false; - } - else if (num_continue_c_tids == 1 && - num_continue_C_tids == 0 && - num_continue_s_tids == 0 && - num_continue_S_tids == 0 ) - { - // Only one thread is continuing - m_gdb_comm.SetCurrentThreadForRun (m_continue_c_tids.front()); - continue_packet.PutChar ('c'); - continue_packet_error = false; - } + continue_packet.Clear(); + } + } else + continue_packet_error = true; + + if (continue_packet_error) { + // Either no vCont support, or we tried to use part of the vCont + // packet that wasn't supported by the remote GDB server. + // We need to try and make a simple packet that can do our continue + const size_t num_continue_c_tids = m_continue_c_tids.size(); + const size_t num_continue_C_tids = m_continue_C_tids.size(); + const size_t num_continue_s_tids = m_continue_s_tids.size(); + const size_t num_continue_S_tids = m_continue_S_tids.size(); + if (num_continue_c_tids > 0) { + if (num_continue_c_tids == num_threads) { + // All threads are resuming... + m_gdb_comm.SetCurrentThreadForRun(-1); + continue_packet.PutChar('c'); + continue_packet_error = false; + } else if (num_continue_c_tids == 1 && num_continue_C_tids == 0 && + num_continue_s_tids == 0 && num_continue_S_tids == 0) { + // Only one thread is continuing + m_gdb_comm.SetCurrentThreadForRun(m_continue_c_tids.front()); + continue_packet.PutChar('c'); + continue_packet_error = false; + } + } + + if (continue_packet_error && num_continue_C_tids > 0) { + if ((num_continue_C_tids + num_continue_c_tids) == num_threads && + num_continue_C_tids > 0 && num_continue_s_tids == 0 && + num_continue_S_tids == 0) { + const int continue_signo = m_continue_C_tids.front().second; + // Only one thread is continuing + if (num_continue_C_tids > 1) { + // More that one thread with a signal, yet we don't have + // vCont support and we are being asked to resume each + // thread with a signal, we need to make sure they are + // all the same signal, or we can't issue the continue + // accurately with the current support... + if (num_continue_C_tids > 1) { + continue_packet_error = false; + for (size_t i = 1; i < m_continue_C_tids.size(); ++i) { + if (m_continue_C_tids[i].second != continue_signo) + continue_packet_error = true; + } } + if (!continue_packet_error) + m_gdb_comm.SetCurrentThreadForRun(-1); + } else { + // Set the continue thread ID + continue_packet_error = false; + m_gdb_comm.SetCurrentThreadForRun(m_continue_C_tids.front().first); + } + if (!continue_packet_error) { + // Add threads continuing with the same signo... + continue_packet.Printf("C%2.2x", continue_signo); + } + } + } - if (continue_packet_error && num_continue_C_tids > 0) - { - if ((num_continue_C_tids + num_continue_c_tids) == num_threads && - num_continue_C_tids > 0 && - num_continue_s_tids == 0 && - num_continue_S_tids == 0 ) - { - const int continue_signo = m_continue_C_tids.front().second; - // Only one thread is continuing - if (num_continue_C_tids > 1) - { - // More that one thread with a signal, yet we don't have - // vCont support and we are being asked to resume each - // thread with a signal, we need to make sure they are - // all the same signal, or we can't issue the continue - // accurately with the current support... - if (num_continue_C_tids > 1) - { - continue_packet_error = false; - for (size_t i=1; i<m_continue_C_tids.size(); ++i) - { - if (m_continue_C_tids[i].second != continue_signo) - continue_packet_error = true; - } - } - if (!continue_packet_error) - m_gdb_comm.SetCurrentThreadForRun (-1); - } - else - { - // Set the continue thread ID - continue_packet_error = false; - m_gdb_comm.SetCurrentThreadForRun (m_continue_C_tids.front().first); - } - if (!continue_packet_error) - { - // Add threads continuing with the same signo... - continue_packet.Printf("C%2.2x", continue_signo); - } - } - } + if (continue_packet_error && num_continue_s_tids > 0) { + if (num_continue_s_tids == num_threads) { + // All threads are resuming... + m_gdb_comm.SetCurrentThreadForRun(-1); - if (continue_packet_error && num_continue_s_tids > 0) - { - if (num_continue_s_tids == num_threads) - { - // All threads are resuming... - m_gdb_comm.SetCurrentThreadForRun (-1); - - // If in Non-Stop-Mode use vCont when stepping - if (GetTarget().GetNonStopModeEnabled()) - { - if (m_gdb_comm.GetVContSupported('s')) - continue_packet.PutCString("vCont;s"); - else - continue_packet.PutChar('s'); - } - else - continue_packet.PutChar('s'); - - continue_packet_error = false; - } - else if (num_continue_c_tids == 0 && - num_continue_C_tids == 0 && - num_continue_s_tids == 1 && - num_continue_S_tids == 0 ) - { - // Only one thread is stepping - m_gdb_comm.SetCurrentThreadForRun (m_continue_s_tids.front()); - continue_packet.PutChar ('s'); - continue_packet_error = false; - } - } - - if (!continue_packet_error && num_continue_S_tids > 0) - { - if (num_continue_S_tids == num_threads) - { - const int step_signo = m_continue_S_tids.front().second; - // Are all threads trying to step with the same signal? - continue_packet_error = false; - if (num_continue_S_tids > 1) - { - for (size_t i=1; i<num_threads; ++i) - { - if (m_continue_S_tids[i].second != step_signo) - continue_packet_error = true; - } - } - if (!continue_packet_error) - { - // Add threads stepping with the same signo... - m_gdb_comm.SetCurrentThreadForRun (-1); - continue_packet.Printf("S%2.2x", step_signo); - } - } - else if (num_continue_c_tids == 0 && - num_continue_C_tids == 0 && - num_continue_s_tids == 0 && - num_continue_S_tids == 1 ) - { - // Only one thread is stepping with signal - m_gdb_comm.SetCurrentThreadForRun (m_continue_S_tids.front().first); - continue_packet.Printf("S%2.2x", m_continue_S_tids.front().second); - continue_packet_error = false; - } + // If in Non-Stop-Mode use vCont when stepping + if (GetTarget().GetNonStopModeEnabled()) { + if (m_gdb_comm.GetVContSupported('s')) + continue_packet.PutCString("vCont;s"); + else + continue_packet.PutChar('s'); + } else + continue_packet.PutChar('s'); + + continue_packet_error = false; + } else if (num_continue_c_tids == 0 && num_continue_C_tids == 0 && + num_continue_s_tids == 1 && num_continue_S_tids == 0) { + // Only one thread is stepping + m_gdb_comm.SetCurrentThreadForRun(m_continue_s_tids.front()); + continue_packet.PutChar('s'); + continue_packet_error = false; + } + } + + if (!continue_packet_error && num_continue_S_tids > 0) { + if (num_continue_S_tids == num_threads) { + const int step_signo = m_continue_S_tids.front().second; + // Are all threads trying to step with the same signal? + continue_packet_error = false; + if (num_continue_S_tids > 1) { + for (size_t i = 1; i < num_threads; ++i) { + if (m_continue_S_tids[i].second != step_signo) + continue_packet_error = true; } + } + if (!continue_packet_error) { + // Add threads stepping with the same signo... + m_gdb_comm.SetCurrentThreadForRun(-1); + continue_packet.Printf("S%2.2x", step_signo); + } + } else if (num_continue_c_tids == 0 && num_continue_C_tids == 0 && + num_continue_s_tids == 0 && num_continue_S_tids == 1) { + // Only one thread is stepping with signal + m_gdb_comm.SetCurrentThreadForRun(m_continue_S_tids.front().first); + continue_packet.Printf("S%2.2x", m_continue_S_tids.front().second); + continue_packet_error = false; } + } + } - if (continue_packet_error) - { - error.SetErrorString ("can't make continue packet for this resume"); - } - else - { - EventSP event_sp; - TimeValue timeout; - timeout = TimeValue::Now(); - timeout.OffsetWithSeconds (5); - if (!m_async_thread.IsJoinable()) - { - error.SetErrorString ("Trying to resume but the async thread is dead."); - if (log) - log->Printf ("ProcessGDBRemote::DoResume: Trying to resume but the async thread is dead."); - return error; - } + if (continue_packet_error) { + error.SetErrorString("can't make continue packet for this resume"); + } else { + EventSP event_sp; + if (!m_async_thread.IsJoinable()) { + error.SetErrorString("Trying to resume but the async thread is dead."); + if (log) + log->Printf("ProcessGDBRemote::DoResume: Trying to resume but the " + "async thread is dead."); + return error; + } - m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncContinue, new EventDataBytes (continue_packet.GetData(), continue_packet.GetSize())); + m_async_broadcaster.BroadcastEvent( + eBroadcastBitAsyncContinue, + new EventDataBytes(continue_packet.GetString().data(), + continue_packet.GetSize())); - if (listener_sp->WaitForEvent (&timeout, event_sp) == false) - { - error.SetErrorString("Resume timed out."); - if (log) - log->Printf ("ProcessGDBRemote::DoResume: Resume timed out."); - } - else if (event_sp->BroadcasterIs (&m_async_broadcaster)) - { - error.SetErrorString ("Broadcast continue, but the async thread was killed before we got an ack back."); - if (log) - log->Printf ("ProcessGDBRemote::DoResume: Broadcast continue, but the async thread was killed before we got an ack back."); - return error; - } - } + if (listener_sp->GetEvent(event_sp, std::chrono::seconds(5)) == false) { + error.SetErrorString("Resume timed out."); + if (log) + log->Printf("ProcessGDBRemote::DoResume: Resume timed out."); + } else if (event_sp->BroadcasterIs(&m_async_broadcaster)) { + error.SetErrorString("Broadcast continue, but the async thread was " + "killed before we got an ack back."); + if (log) + log->Printf("ProcessGDBRemote::DoResume: Broadcast continue, but the " + "async thread was killed before we got an ack back."); + return error; + } } + } - return error; + return error; } -void -ProcessGDBRemote::HandleStopReplySequence () -{ - while(true) - { - // Send vStopped - StringExtractorGDBRemote response; - m_gdb_comm.SendPacketAndWaitForResponse("vStopped", response, false); +void ProcessGDBRemote::HandleStopReplySequence() { + while (true) { + // Send vStopped + StringExtractorGDBRemote response; + m_gdb_comm.SendPacketAndWaitForResponse("vStopped", response, false); - // OK represents end of signal list - if (response.IsOKResponse()) - break; + // OK represents end of signal list + if (response.IsOKResponse()) + break; - // If not OK or a normal packet we have a problem - if (!response.IsNormalResponse()) - break; + // If not OK or a normal packet we have a problem + if (!response.IsNormalResponse()) + break; - SetLastStopPacket(response); - } + SetLastStopPacket(response); + } } -void -ProcessGDBRemote::ClearThreadIDList () -{ - std::lock_guard<std::recursive_mutex> guard(m_thread_list_real.GetMutex()); - m_thread_ids.clear(); - m_thread_pcs.clear(); +void ProcessGDBRemote::ClearThreadIDList() { + std::lock_guard<std::recursive_mutex> guard(m_thread_list_real.GetMutex()); + m_thread_ids.clear(); + m_thread_pcs.clear(); } size_t -ProcessGDBRemote::UpdateThreadIDsFromStopReplyThreadsValue (std::string &value) -{ - m_thread_ids.clear(); - m_thread_pcs.clear(); - size_t comma_pos; - lldb::tid_t tid; - while ((comma_pos = value.find(',')) != std::string::npos) - { - value[comma_pos] = '\0'; - // thread in big endian hex - tid = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_THREAD_ID, 16); - if (tid != LLDB_INVALID_THREAD_ID) - m_thread_ids.push_back (tid); - value.erase(0, comma_pos + 1); - } - tid = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_THREAD_ID, 16); +ProcessGDBRemote::UpdateThreadIDsFromStopReplyThreadsValue(std::string &value) { + m_thread_ids.clear(); + m_thread_pcs.clear(); + size_t comma_pos; + lldb::tid_t tid; + while ((comma_pos = value.find(',')) != std::string::npos) { + value[comma_pos] = '\0'; + // thread in big endian hex + tid = StringConvert::ToUInt64(value.c_str(), LLDB_INVALID_THREAD_ID, 16); if (tid != LLDB_INVALID_THREAD_ID) - m_thread_ids.push_back (tid); - return m_thread_ids.size(); + m_thread_ids.push_back(tid); + value.erase(0, comma_pos + 1); + } + tid = StringConvert::ToUInt64(value.c_str(), LLDB_INVALID_THREAD_ID, 16); + if (tid != LLDB_INVALID_THREAD_ID) + m_thread_ids.push_back(tid); + return m_thread_ids.size(); } size_t -ProcessGDBRemote::UpdateThreadPCsFromStopReplyThreadsValue (std::string &value) -{ - m_thread_pcs.clear(); - size_t comma_pos; - lldb::addr_t pc; - while ((comma_pos = value.find(',')) != std::string::npos) - { - value[comma_pos] = '\0'; - pc = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_ADDRESS, 16); - if (pc != LLDB_INVALID_ADDRESS) - m_thread_pcs.push_back (pc); - value.erase(0, comma_pos + 1); - } - pc = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_ADDRESS, 16); - if (pc != LLDB_INVALID_THREAD_ID) - m_thread_pcs.push_back (pc); - return m_thread_pcs.size(); +ProcessGDBRemote::UpdateThreadPCsFromStopReplyThreadsValue(std::string &value) { + m_thread_pcs.clear(); + size_t comma_pos; + lldb::addr_t pc; + while ((comma_pos = value.find(',')) != std::string::npos) { + value[comma_pos] = '\0'; + pc = StringConvert::ToUInt64(value.c_str(), LLDB_INVALID_ADDRESS, 16); + if (pc != LLDB_INVALID_ADDRESS) + m_thread_pcs.push_back(pc); + value.erase(0, comma_pos + 1); + } + pc = StringConvert::ToUInt64(value.c_str(), LLDB_INVALID_ADDRESS, 16); + if (pc != LLDB_INVALID_THREAD_ID) + m_thread_pcs.push_back(pc); + return m_thread_pcs.size(); } -bool -ProcessGDBRemote::UpdateThreadIDList () -{ - std::lock_guard<std::recursive_mutex> guard(m_thread_list_real.GetMutex()); - - if (m_jthreadsinfo_sp) - { - // If we have the JSON threads info, we can get the thread list from that - StructuredData::Array *thread_infos = m_jthreadsinfo_sp->GetAsArray(); - if (thread_infos && thread_infos->GetSize() > 0) - { - m_thread_ids.clear(); - m_thread_pcs.clear(); - thread_infos->ForEach([this](StructuredData::Object* object) -> bool { - StructuredData::Dictionary *thread_dict = object->GetAsDictionary(); - if (thread_dict) - { - // Set the thread stop info from the JSON dictionary - SetThreadStopInfo (thread_dict); - lldb::tid_t tid = LLDB_INVALID_THREAD_ID; - if (thread_dict->GetValueForKeyAsInteger<lldb::tid_t>("tid", tid)) - m_thread_ids.push_back(tid); - } - return true; // Keep iterating through all thread_info objects - }); +bool ProcessGDBRemote::UpdateThreadIDList() { + std::lock_guard<std::recursive_mutex> guard(m_thread_list_real.GetMutex()); + + if (m_jthreadsinfo_sp) { + // If we have the JSON threads info, we can get the thread list from that + StructuredData::Array *thread_infos = m_jthreadsinfo_sp->GetAsArray(); + if (thread_infos && thread_infos->GetSize() > 0) { + m_thread_ids.clear(); + m_thread_pcs.clear(); + thread_infos->ForEach([this](StructuredData::Object *object) -> bool { + StructuredData::Dictionary *thread_dict = object->GetAsDictionary(); + if (thread_dict) { + // Set the thread stop info from the JSON dictionary + SetThreadStopInfo(thread_dict); + lldb::tid_t tid = LLDB_INVALID_THREAD_ID; + if (thread_dict->GetValueForKeyAsInteger<lldb::tid_t>("tid", tid)) + m_thread_ids.push_back(tid); + } + return true; // Keep iterating through all thread_info objects + }); + } + if (!m_thread_ids.empty()) + return true; + } else { + // See if we can get the thread IDs from the current stop reply packets + // that might contain a "threads" key/value pair + + // Lock the thread stack while we access it + // Mutex::Locker stop_stack_lock(m_last_stop_packet_mutex); + std::unique_lock<std::recursive_mutex> stop_stack_lock( + m_last_stop_packet_mutex, std::defer_lock); + if (stop_stack_lock.try_lock()) { + // Get the number of stop packets on the stack + int nItems = m_stop_packet_stack.size(); + // Iterate over them + for (int i = 0; i < nItems; i++) { + // Get the thread stop info + StringExtractorGDBRemote &stop_info = m_stop_packet_stack[i]; + const std::string &stop_info_str = stop_info.GetStringRef(); + + m_thread_pcs.clear(); + const size_t thread_pcs_pos = stop_info_str.find(";thread-pcs:"); + if (thread_pcs_pos != std::string::npos) { + const size_t start = thread_pcs_pos + strlen(";thread-pcs:"); + const size_t end = stop_info_str.find(';', start); + if (end != std::string::npos) { + std::string value = stop_info_str.substr(start, end - start); + UpdateThreadPCsFromStopReplyThreadsValue(value); + } } - if (!m_thread_ids.empty()) - return true; - } - else - { - // See if we can get the thread IDs from the current stop reply packets - // that might contain a "threads" key/value pair - - // Lock the thread stack while we access it - //Mutex::Locker stop_stack_lock(m_last_stop_packet_mutex); - std::unique_lock<std::recursive_mutex> stop_stack_lock(m_last_stop_packet_mutex, std::defer_lock); - if (stop_stack_lock.try_lock()) - { - // Get the number of stop packets on the stack - int nItems = m_stop_packet_stack.size(); - // Iterate over them - for (int i = 0; i < nItems; i++) - { - // Get the thread stop info - StringExtractorGDBRemote &stop_info = m_stop_packet_stack[i]; - const std::string &stop_info_str = stop_info.GetStringRef(); - - m_thread_pcs.clear(); - const size_t thread_pcs_pos = stop_info_str.find(";thread-pcs:"); - if (thread_pcs_pos != std::string::npos) - { - const size_t start = thread_pcs_pos + strlen(";thread-pcs:"); - const size_t end = stop_info_str.find(';', start); - if (end != std::string::npos) - { - std::string value = stop_info_str.substr(start, end - start); - UpdateThreadPCsFromStopReplyThreadsValue(value); - } - } - const size_t threads_pos = stop_info_str.find(";threads:"); - if (threads_pos != std::string::npos) - { - const size_t start = threads_pos + strlen(";threads:"); - const size_t end = stop_info_str.find(';', start); - if (end != std::string::npos) - { - std::string value = stop_info_str.substr(start, end - start); - if (UpdateThreadIDsFromStopReplyThreadsValue(value)) - return true; - } - } - } + const size_t threads_pos = stop_info_str.find(";threads:"); + if (threads_pos != std::string::npos) { + const size_t start = threads_pos + strlen(";threads:"); + const size_t end = stop_info_str.find(';', start); + if (end != std::string::npos) { + std::string value = stop_info_str.substr(start, end - start); + if (UpdateThreadIDsFromStopReplyThreadsValue(value)) + return true; + } } + } } + } - bool sequence_mutex_unavailable = false; - m_gdb_comm.GetCurrentThreadIDs (m_thread_ids, sequence_mutex_unavailable); - if (sequence_mutex_unavailable) - { - return false; // We just didn't get the list - } - return true; + bool sequence_mutex_unavailable = false; + m_gdb_comm.GetCurrentThreadIDs(m_thread_ids, sequence_mutex_unavailable); + if (sequence_mutex_unavailable) { + return false; // We just didn't get the list + } + return true; } -bool -ProcessGDBRemote::UpdateThreadList (ThreadList &old_thread_list, ThreadList &new_thread_list) -{ - // locker will keep a mutex locked until it goes out of scope - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_THREAD)); - if (log && log->GetMask().Test(GDBR_LOG_VERBOSE)) - log->Printf ("ProcessGDBRemote::%s (pid = %" PRIu64 ")", __FUNCTION__, GetID()); - - size_t num_thread_ids = m_thread_ids.size(); - // The "m_thread_ids" thread ID list should always be updated after each stop - // reply packet, but in case it isn't, update it here. - if (num_thread_ids == 0) - { - if (!UpdateThreadIDList ()) - return false; - num_thread_ids = m_thread_ids.size(); - } - - ThreadList old_thread_list_copy(old_thread_list); - if (num_thread_ids > 0) - { - for (size_t i=0; i<num_thread_ids; ++i) - { - tid_t tid = m_thread_ids[i]; - ThreadSP thread_sp (old_thread_list_copy.RemoveThreadByProtocolID(tid, false)); - if (!thread_sp) - { - thread_sp.reset (new ThreadGDBRemote (*this, tid)); - if (log && log->GetMask().Test(GDBR_LOG_VERBOSE)) - log->Printf( - "ProcessGDBRemote::%s Making new thread: %p for thread ID: 0x%" PRIx64 ".\n", - __FUNCTION__, static_cast<void*>(thread_sp.get()), - thread_sp->GetID()); - } - else - { - if (log && log->GetMask().Test(GDBR_LOG_VERBOSE)) - log->Printf( - "ProcessGDBRemote::%s Found old thread: %p for thread ID: 0x%" PRIx64 ".\n", - __FUNCTION__, static_cast<void*>(thread_sp.get()), - thread_sp->GetID()); - } - // The m_thread_pcs vector has pc values in big-endian order, not target-endian, unlike most - // of the register read/write packets in gdb-remote protocol. - // Early in the process startup, we may not yet have set the process ByteOrder so we ignore these; - // they are a performance improvement over fetching thread register values individually, the - // method we will fall back to if needed. - if (m_thread_ids.size() == m_thread_pcs.size() && thread_sp.get() && GetByteOrder() != eByteOrderInvalid) - { - ThreadGDBRemote *gdb_thread = static_cast<ThreadGDBRemote *> (thread_sp.get()); - RegisterContextSP reg_ctx_sp (thread_sp->GetRegisterContext()); - if (reg_ctx_sp) - { - uint32_t pc_regnum = reg_ctx_sp->ConvertRegisterKindToRegisterNumber - (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); - if (pc_regnum != LLDB_INVALID_REGNUM) - { - gdb_thread->PrivateSetRegisterValue (pc_regnum, m_thread_pcs[i]); - } - } - } - new_thread_list.AddThreadSortedByIndexID (thread_sp); +bool ProcessGDBRemote::UpdateThreadList(ThreadList &old_thread_list, + ThreadList &new_thread_list) { + // locker will keep a mutex locked until it goes out of scope + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_THREAD)); + if (log && log->GetMask().Test(GDBR_LOG_VERBOSE)) + log->Printf("ProcessGDBRemote::%s (pid = %" PRIu64 ")", __FUNCTION__, + GetID()); + + size_t num_thread_ids = m_thread_ids.size(); + // The "m_thread_ids" thread ID list should always be updated after each stop + // reply packet, but in case it isn't, update it here. + if (num_thread_ids == 0) { + if (!UpdateThreadIDList()) + return false; + num_thread_ids = m_thread_ids.size(); + } + + ThreadList old_thread_list_copy(old_thread_list); + if (num_thread_ids > 0) { + for (size_t i = 0; i < num_thread_ids; ++i) { + tid_t tid = m_thread_ids[i]; + ThreadSP thread_sp( + old_thread_list_copy.RemoveThreadByProtocolID(tid, false)); + if (!thread_sp) { + thread_sp.reset(new ThreadGDBRemote(*this, tid)); + if (log && log->GetMask().Test(GDBR_LOG_VERBOSE)) + log->Printf("ProcessGDBRemote::%s Making new thread: %p for thread " + "ID: 0x%" PRIx64 ".\n", + __FUNCTION__, static_cast<void *>(thread_sp.get()), + thread_sp->GetID()); + } else { + if (log && log->GetMask().Test(GDBR_LOG_VERBOSE)) + log->Printf("ProcessGDBRemote::%s Found old thread: %p for thread " + "ID: 0x%" PRIx64 ".\n", + __FUNCTION__, static_cast<void *>(thread_sp.get()), + thread_sp->GetID()); + } + // The m_thread_pcs vector has pc values in big-endian order, not + // target-endian, unlike most + // of the register read/write packets in gdb-remote protocol. + // Early in the process startup, we may not yet have set the process + // ByteOrder so we ignore these; + // they are a performance improvement over fetching thread register values + // individually, the + // method we will fall back to if needed. + if (m_thread_ids.size() == m_thread_pcs.size() && thread_sp.get() && + GetByteOrder() != eByteOrderInvalid) { + ThreadGDBRemote *gdb_thread = + static_cast<ThreadGDBRemote *>(thread_sp.get()); + RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext()); + if (reg_ctx_sp) { + uint32_t pc_regnum = reg_ctx_sp->ConvertRegisterKindToRegisterNumber( + eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); + if (pc_regnum != LLDB_INVALID_REGNUM) { + gdb_thread->PrivateSetRegisterValue(pc_regnum, m_thread_pcs[i]); + } } + } + new_thread_list.AddThreadSortedByIndexID(thread_sp); } + } - // Whatever that is left in old_thread_list_copy are not - // present in new_thread_list. Remove non-existent threads from internal id table. - size_t old_num_thread_ids = old_thread_list_copy.GetSize(false); - for (size_t i=0; i<old_num_thread_ids; i++) - { - ThreadSP old_thread_sp(old_thread_list_copy.GetThreadAtIndex (i, false)); - if (old_thread_sp) - { - lldb::tid_t old_thread_id = old_thread_sp->GetProtocolID(); - m_thread_id_to_index_id_map.erase(old_thread_id); - } + // Whatever that is left in old_thread_list_copy are not + // present in new_thread_list. Remove non-existent threads from internal id + // table. + size_t old_num_thread_ids = old_thread_list_copy.GetSize(false); + for (size_t i = 0; i < old_num_thread_ids; i++) { + ThreadSP old_thread_sp(old_thread_list_copy.GetThreadAtIndex(i, false)); + if (old_thread_sp) { + lldb::tid_t old_thread_id = old_thread_sp->GetProtocolID(); + m_thread_id_to_index_id_map.erase(old_thread_id); } + } - return true; + return true; } - -bool -ProcessGDBRemote::GetThreadStopInfoFromJSON (ThreadGDBRemote *thread, const StructuredData::ObjectSP &thread_infos_sp) -{ - // See if we got thread stop infos for all threads via the "jThreadsInfo" packet - if (thread_infos_sp) - { - StructuredData::Array *thread_infos = thread_infos_sp->GetAsArray(); - if (thread_infos) - { - lldb::tid_t tid; - const size_t n = thread_infos->GetSize(); - for (size_t i=0; i<n; ++i) - { - StructuredData::Dictionary *thread_dict = thread_infos->GetItemAtIndex(i)->GetAsDictionary(); - if (thread_dict) - { - if (thread_dict->GetValueForKeyAsInteger<lldb::tid_t>("tid", tid, LLDB_INVALID_THREAD_ID)) - { - if (tid == thread->GetID()) - return (bool)SetThreadStopInfo(thread_dict); - } - } - } +bool ProcessGDBRemote::GetThreadStopInfoFromJSON( + ThreadGDBRemote *thread, const StructuredData::ObjectSP &thread_infos_sp) { + // See if we got thread stop infos for all threads via the "jThreadsInfo" + // packet + if (thread_infos_sp) { + StructuredData::Array *thread_infos = thread_infos_sp->GetAsArray(); + if (thread_infos) { + lldb::tid_t tid; + const size_t n = thread_infos->GetSize(); + for (size_t i = 0; i < n; ++i) { + StructuredData::Dictionary *thread_dict = + thread_infos->GetItemAtIndex(i)->GetAsDictionary(); + if (thread_dict) { + if (thread_dict->GetValueForKeyAsInteger<lldb::tid_t>( + "tid", tid, LLDB_INVALID_THREAD_ID)) { + if (tid == thread->GetID()) + return (bool)SetThreadStopInfo(thread_dict); + } } + } } - return false; + } + return false; } -bool -ProcessGDBRemote::CalculateThreadStopInfo (ThreadGDBRemote *thread) -{ - // See if we got thread stop infos for all threads via the "jThreadsInfo" packet - if (GetThreadStopInfoFromJSON (thread, m_jthreadsinfo_sp)) - return true; +bool ProcessGDBRemote::CalculateThreadStopInfo(ThreadGDBRemote *thread) { + // See if we got thread stop infos for all threads via the "jThreadsInfo" + // packet + if (GetThreadStopInfoFromJSON(thread, m_jthreadsinfo_sp)) + return true; - // See if we got thread stop info for any threads valid stop info reasons threads - // via the "jstopinfo" packet stop reply packet key/value pair? - if (m_jstopinfo_sp) - { - // If we have "jstopinfo" then we have stop descriptions for all threads - // that have stop reasons, and if there is no entry for a thread, then - // it has no stop reason. - thread->GetRegisterContext()->InvalidateIfNeeded(true); - if (!GetThreadStopInfoFromJSON (thread, m_jstopinfo_sp)) - { - thread->SetStopInfo (StopInfoSP()); - } - return true; + // See if we got thread stop info for any threads valid stop info reasons + // threads + // via the "jstopinfo" packet stop reply packet key/value pair? + if (m_jstopinfo_sp) { + // If we have "jstopinfo" then we have stop descriptions for all threads + // that have stop reasons, and if there is no entry for a thread, then + // it has no stop reason. + thread->GetRegisterContext()->InvalidateIfNeeded(true); + if (!GetThreadStopInfoFromJSON(thread, m_jstopinfo_sp)) { + thread->SetStopInfo(StopInfoSP()); } + return true; + } - // Fall back to using the qThreadStopInfo packet - StringExtractorGDBRemote stop_packet; - if (GetGDBRemote().GetThreadStopInfo(thread->GetProtocolID(), stop_packet)) - return SetThreadStopInfo (stop_packet) == eStateStopped; - return false; + // Fall back to using the qThreadStopInfo packet + StringExtractorGDBRemote stop_packet; + if (GetGDBRemote().GetThreadStopInfo(thread->GetProtocolID(), stop_packet)) + return SetThreadStopInfo(stop_packet) == eStateStopped; + return false; } - -ThreadSP -ProcessGDBRemote::SetThreadStopInfo (lldb::tid_t tid, - ExpeditedRegisterMap &expedited_register_map, - uint8_t signo, - const std::string &thread_name, - const std::string &reason, - const std::string &description, - uint32_t exc_type, - const std::vector<addr_t> &exc_data, - addr_t thread_dispatch_qaddr, - bool queue_vars_valid, // Set to true if queue_name, queue_kind and queue_serial are valid - LazyBool associated_with_dispatch_queue, - addr_t dispatch_queue_t, - std::string &queue_name, - QueueKind queue_kind, - uint64_t queue_serial) -{ - ThreadSP thread_sp; - if (tid != LLDB_INVALID_THREAD_ID) - { - // Scope for "locker" below - { - // m_thread_list_real does have its own mutex, but we need to - // hold onto the mutex between the call to m_thread_list_real.FindThreadByID(...) - // and the m_thread_list_real.AddThread(...) so it doesn't change on us - std::lock_guard<std::recursive_mutex> guard(m_thread_list_real.GetMutex()); - thread_sp = m_thread_list_real.FindThreadByProtocolID(tid, false); - - if (!thread_sp) - { - // Create the thread if we need to - thread_sp.reset (new ThreadGDBRemote (*this, tid)); - m_thread_list_real.AddThread(thread_sp); +ThreadSP ProcessGDBRemote::SetThreadStopInfo( + lldb::tid_t tid, ExpeditedRegisterMap &expedited_register_map, + uint8_t signo, const std::string &thread_name, const std::string &reason, + const std::string &description, uint32_t exc_type, + const std::vector<addr_t> &exc_data, addr_t thread_dispatch_qaddr, + bool queue_vars_valid, // Set to true if queue_name, queue_kind and + // queue_serial are valid + LazyBool associated_with_dispatch_queue, addr_t dispatch_queue_t, + std::string &queue_name, QueueKind queue_kind, uint64_t queue_serial) { + ThreadSP thread_sp; + if (tid != LLDB_INVALID_THREAD_ID) { + // Scope for "locker" below + { + // m_thread_list_real does have its own mutex, but we need to + // hold onto the mutex between the call to + // m_thread_list_real.FindThreadByID(...) + // and the m_thread_list_real.AddThread(...) so it doesn't change on us + std::lock_guard<std::recursive_mutex> guard( + m_thread_list_real.GetMutex()); + thread_sp = m_thread_list_real.FindThreadByProtocolID(tid, false); + + if (!thread_sp) { + // Create the thread if we need to + thread_sp.reset(new ThreadGDBRemote(*this, tid)); + m_thread_list_real.AddThread(thread_sp); + } + } + + if (thread_sp) { + ThreadGDBRemote *gdb_thread = + static_cast<ThreadGDBRemote *>(thread_sp.get()); + gdb_thread->GetRegisterContext()->InvalidateIfNeeded(true); + + for (const auto &pair : expedited_register_map) { + StringExtractor reg_value_extractor; + reg_value_extractor.GetStringRef() = pair.second; + DataBufferSP buffer_sp(new DataBufferHeap( + reg_value_extractor.GetStringRef().size() / 2, 0)); + reg_value_extractor.GetHexBytes(buffer_sp->GetData(), '\xcc'); + gdb_thread->PrivateSetRegisterValue(pair.first, buffer_sp->GetData()); + } + + thread_sp->SetName(thread_name.empty() ? NULL : thread_name.c_str()); + + gdb_thread->SetThreadDispatchQAddr(thread_dispatch_qaddr); + // Check if the GDB server was able to provide the queue name, kind and + // serial number + if (queue_vars_valid) + gdb_thread->SetQueueInfo(std::move(queue_name), queue_kind, + queue_serial, dispatch_queue_t, + associated_with_dispatch_queue); + else + gdb_thread->ClearQueueInfo(); + + gdb_thread->SetAssociatedWithLibdispatchQueue( + associated_with_dispatch_queue); + + if (dispatch_queue_t != LLDB_INVALID_ADDRESS) + gdb_thread->SetQueueLibdispatchQueueAddress(dispatch_queue_t); + + // Make sure we update our thread stop reason just once + if (!thread_sp->StopInfoIsUpToDate()) { + thread_sp->SetStopInfo(StopInfoSP()); + // If there's a memory thread backed by this thread, we need to use it + // to calcualte StopInfo. + ThreadSP memory_thread_sp = + m_thread_list.FindThreadByProtocolID(thread_sp->GetProtocolID()); + if (memory_thread_sp) + thread_sp = memory_thread_sp; + + if (exc_type != 0) { + const size_t exc_data_size = exc_data.size(); + + thread_sp->SetStopInfo( + StopInfoMachException::CreateStopReasonWithMachException( + *thread_sp, exc_type, exc_data_size, + exc_data_size >= 1 ? exc_data[0] : 0, + exc_data_size >= 2 ? exc_data[1] : 0, + exc_data_size >= 3 ? exc_data[2] : 0)); + } else { + bool handled = false; + bool did_exec = false; + if (!reason.empty()) { + if (reason.compare("trace") == 0) { + addr_t pc = thread_sp->GetRegisterContext()->GetPC(); + lldb::BreakpointSiteSP bp_site_sp = thread_sp->GetProcess() + ->GetBreakpointSiteList() + .FindByAddress(pc); + + // If the current pc is a breakpoint site then the StopInfo should + // be set to Breakpoint + // Otherwise, it will be set to Trace. + if (bp_site_sp && + bp_site_sp->ValidForThisThread(thread_sp.get())) { + thread_sp->SetStopInfo( + StopInfo::CreateStopReasonWithBreakpointSiteID( + *thread_sp, bp_site_sp->GetID())); + } else + thread_sp->SetStopInfo( + StopInfo::CreateStopReasonToTrace(*thread_sp)); + handled = true; + } else if (reason.compare("breakpoint") == 0) { + addr_t pc = thread_sp->GetRegisterContext()->GetPC(); + lldb::BreakpointSiteSP bp_site_sp = thread_sp->GetProcess() + ->GetBreakpointSiteList() + .FindByAddress(pc); + if (bp_site_sp) { + // If the breakpoint is for this thread, then we'll report the + // hit, but if it is for another thread, + // we can just report no reason. We don't need to worry about + // stepping over the breakpoint here, that + // will be taken care of when the thread resumes and notices + // that there's a breakpoint under the pc. + handled = true; + if (bp_site_sp->ValidForThisThread(thread_sp.get())) { + thread_sp->SetStopInfo( + StopInfo::CreateStopReasonWithBreakpointSiteID( + *thread_sp, bp_site_sp->GetID())); + } else { + StopInfoSP invalid_stop_info_sp; + thread_sp->SetStopInfo(invalid_stop_info_sp); + } + } + } else if (reason.compare("trap") == 0) { + // Let the trap just use the standard signal stop reason below... + } else if (reason.compare("watchpoint") == 0) { + StringExtractor desc_extractor(description.c_str()); + addr_t wp_addr = desc_extractor.GetU64(LLDB_INVALID_ADDRESS); + uint32_t wp_index = desc_extractor.GetU32(LLDB_INVALID_INDEX32); + addr_t wp_hit_addr = desc_extractor.GetU64(LLDB_INVALID_ADDRESS); + watch_id_t watch_id = LLDB_INVALID_WATCH_ID; + if (wp_addr != LLDB_INVALID_ADDRESS) { + WatchpointSP wp_sp; + ArchSpec::Core core = GetTarget().GetArchitecture().GetCore(); + if ((core >= ArchSpec::kCore_mips_first && + core <= ArchSpec::kCore_mips_last) || + (core >= ArchSpec::eCore_arm_generic && + core <= ArchSpec::eCore_arm_aarch64)) + wp_sp = GetTarget().GetWatchpointList().FindByAddress( + wp_hit_addr); + if (!wp_sp) + wp_sp = + GetTarget().GetWatchpointList().FindByAddress(wp_addr); + if (wp_sp) { + wp_sp->SetHardwareIndex(wp_index); + watch_id = wp_sp->GetID(); + } + } + if (watch_id == LLDB_INVALID_WATCH_ID) { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet( + GDBR_LOG_WATCHPOINTS)); + if (log) + log->Printf("failed to find watchpoint"); + } + thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithWatchpointID( + *thread_sp, watch_id, wp_hit_addr)); + handled = true; + } else if (reason.compare("exception") == 0) { + thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithException( + *thread_sp, description.c_str())); + handled = true; + } else if (reason.compare("exec") == 0) { + did_exec = true; + thread_sp->SetStopInfo( + StopInfo::CreateStopReasonWithExec(*thread_sp)); + handled = true; } - } - - if (thread_sp) - { - ThreadGDBRemote *gdb_thread = static_cast<ThreadGDBRemote *> (thread_sp.get()); - gdb_thread->GetRegisterContext()->InvalidateIfNeeded(true); - - for (const auto &pair : expedited_register_map) - { - StringExtractor reg_value_extractor; - reg_value_extractor.GetStringRef() = pair.second; - gdb_thread->PrivateSetRegisterValue (pair.first, reg_value_extractor); + } else if (!signo) { + addr_t pc = thread_sp->GetRegisterContext()->GetPC(); + lldb::BreakpointSiteSP bp_site_sp = + thread_sp->GetProcess()->GetBreakpointSiteList().FindByAddress( + pc); + + // If the current pc is a breakpoint site then the StopInfo should + // be set to Breakpoint + // even though the remote stub did not set it as such. This can + // happen when + // the thread is involuntarily interrupted (e.g. due to stops on + // other + // threads) just as it is about to execute the breakpoint + // instruction. + if (bp_site_sp && bp_site_sp->ValidForThisThread(thread_sp.get())) { + thread_sp->SetStopInfo( + StopInfo::CreateStopReasonWithBreakpointSiteID( + *thread_sp, bp_site_sp->GetID())); + handled = true; } - - thread_sp->SetName (thread_name.empty() ? NULL : thread_name.c_str()); - - gdb_thread->SetThreadDispatchQAddr (thread_dispatch_qaddr); - // Check if the GDB server was able to provide the queue name, kind and serial number - if (queue_vars_valid) - gdb_thread->SetQueueInfo(std::move(queue_name), queue_kind, queue_serial, dispatch_queue_t, associated_with_dispatch_queue); - else - gdb_thread->ClearQueueInfo(); - - gdb_thread->SetAssociatedWithLibdispatchQueue (associated_with_dispatch_queue); - - if (dispatch_queue_t != LLDB_INVALID_ADDRESS) - gdb_thread->SetQueueLibdispatchQueueAddress (dispatch_queue_t); - - // Make sure we update our thread stop reason just once - if (!thread_sp->StopInfoIsUpToDate()) - { - thread_sp->SetStopInfo (StopInfoSP()); - // If there's a memory thread backed by this thread, we need to use it to calcualte StopInfo. - ThreadSP memory_thread_sp = m_thread_list.FindThreadByProtocolID(thread_sp->GetProtocolID()); - if (memory_thread_sp) - thread_sp = memory_thread_sp; - - if (exc_type != 0) - { - const size_t exc_data_size = exc_data.size(); - - thread_sp->SetStopInfo (StopInfoMachException::CreateStopReasonWithMachException (*thread_sp, - exc_type, - exc_data_size, - exc_data_size >= 1 ? exc_data[0] : 0, - exc_data_size >= 2 ? exc_data[1] : 0, - exc_data_size >= 3 ? exc_data[2] : 0)); + } + + if (!handled && signo && did_exec == false) { + if (signo == SIGTRAP) { + // Currently we are going to assume SIGTRAP means we are either + // hitting a breakpoint or hardware single stepping. + handled = true; + addr_t pc = thread_sp->GetRegisterContext()->GetPC() + + m_breakpoint_pc_offset; + lldb::BreakpointSiteSP bp_site_sp = thread_sp->GetProcess() + ->GetBreakpointSiteList() + .FindByAddress(pc); + + if (bp_site_sp) { + // If the breakpoint is for this thread, then we'll report the + // hit, but if it is for another thread, + // we can just report no reason. We don't need to worry about + // stepping over the breakpoint here, that + // will be taken care of when the thread resumes and notices + // that there's a breakpoint under the pc. + if (bp_site_sp->ValidForThisThread(thread_sp.get())) { + if (m_breakpoint_pc_offset != 0) + thread_sp->GetRegisterContext()->SetPC(pc); + thread_sp->SetStopInfo( + StopInfo::CreateStopReasonWithBreakpointSiteID( + *thread_sp, bp_site_sp->GetID())); + } else { + StopInfoSP invalid_stop_info_sp; + thread_sp->SetStopInfo(invalid_stop_info_sp); } + } else { + // If we were stepping then assume the stop was the result of + // the trace. If we were + // not stepping then report the SIGTRAP. + // FIXME: We are still missing the case where we single step + // over a trap instruction. + if (thread_sp->GetTemporaryResumeState() == eStateStepping) + thread_sp->SetStopInfo( + StopInfo::CreateStopReasonToTrace(*thread_sp)); else - { - bool handled = false; - bool did_exec = false; - if (!reason.empty()) - { - if (reason.compare("trace") == 0) - { - addr_t pc = thread_sp->GetRegisterContext()->GetPC(); - lldb::BreakpointSiteSP bp_site_sp = thread_sp->GetProcess()->GetBreakpointSiteList().FindByAddress(pc); - - // If the current pc is a breakpoint site then the StopInfo should be set to Breakpoint - // Otherwise, it will be set to Trace. - if (bp_site_sp && bp_site_sp->ValidForThisThread(thread_sp.get())) - { - thread_sp->SetStopInfo( - StopInfo::CreateStopReasonWithBreakpointSiteID(*thread_sp, bp_site_sp->GetID())); - } - else - thread_sp->SetStopInfo (StopInfo::CreateStopReasonToTrace (*thread_sp)); - handled = true; - } - else if (reason.compare("breakpoint") == 0) - { - addr_t pc = thread_sp->GetRegisterContext()->GetPC(); - lldb::BreakpointSiteSP bp_site_sp = thread_sp->GetProcess()->GetBreakpointSiteList().FindByAddress(pc); - if (bp_site_sp) - { - // If the breakpoint is for this thread, then we'll report the hit, but if it is for another thread, - // we can just report no reason. We don't need to worry about stepping over the breakpoint here, that - // will be taken care of when the thread resumes and notices that there's a breakpoint under the pc. - handled = true; - if (bp_site_sp->ValidForThisThread (thread_sp.get())) - { - thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID (*thread_sp, bp_site_sp->GetID())); - } - else - { - StopInfoSP invalid_stop_info_sp; - thread_sp->SetStopInfo (invalid_stop_info_sp); - } - } - } - else if (reason.compare("trap") == 0) - { - // Let the trap just use the standard signal stop reason below... - } - else if (reason.compare("watchpoint") == 0) - { - StringExtractor desc_extractor(description.c_str()); - addr_t wp_addr = desc_extractor.GetU64(LLDB_INVALID_ADDRESS); - uint32_t wp_index = desc_extractor.GetU32(LLDB_INVALID_INDEX32); - addr_t wp_hit_addr = desc_extractor.GetU64(LLDB_INVALID_ADDRESS); - watch_id_t watch_id = LLDB_INVALID_WATCH_ID; - if (wp_addr != LLDB_INVALID_ADDRESS) - { - WatchpointSP wp_sp; - ArchSpec::Core core = GetTarget().GetArchitecture().GetCore(); - if ((core >= ArchSpec::kCore_mips_first && core <= ArchSpec::kCore_mips_last) || - (core >= ArchSpec::eCore_arm_generic && core <= ArchSpec::eCore_arm_aarch64)) - wp_sp = GetTarget().GetWatchpointList().FindByAddress(wp_hit_addr); - if (!wp_sp) - wp_sp = GetTarget().GetWatchpointList().FindByAddress(wp_addr); - if (wp_sp) - { - wp_sp->SetHardwareIndex(wp_index); - watch_id = wp_sp->GetID(); - } - } - if (watch_id == LLDB_INVALID_WATCH_ID) - { - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_WATCHPOINTS)); - if (log) log->Printf ("failed to find watchpoint"); - } - thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithWatchpointID (*thread_sp, watch_id, wp_hit_addr)); - handled = true; - } - else if (reason.compare("exception") == 0) - { - thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithException(*thread_sp, description.c_str())); - handled = true; - } - else if (reason.compare("exec") == 0) - { - did_exec = true; - thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithExec(*thread_sp)); - handled = true; - } - } - else if (!signo) - { - addr_t pc = thread_sp->GetRegisterContext()->GetPC(); - lldb::BreakpointSiteSP bp_site_sp = - thread_sp->GetProcess()->GetBreakpointSiteList().FindByAddress(pc); - - // If the current pc is a breakpoint site then the StopInfo should be set to Breakpoint - // even though the remote stub did not set it as such. This can happen when - // the thread is involuntarily interrupted (e.g. due to stops on other - // threads) just as it is about to execute the breakpoint instruction. - if (bp_site_sp && bp_site_sp->ValidForThisThread(thread_sp.get())) - { - thread_sp->SetStopInfo( - StopInfo::CreateStopReasonWithBreakpointSiteID(*thread_sp, bp_site_sp->GetID())); - handled = true; - } - } - - if (!handled && signo && did_exec == false) - { - if (signo == SIGTRAP) - { - // Currently we are going to assume SIGTRAP means we are either - // hitting a breakpoint or hardware single stepping. - handled = true; - addr_t pc = thread_sp->GetRegisterContext()->GetPC() + m_breakpoint_pc_offset; - lldb::BreakpointSiteSP bp_site_sp = thread_sp->GetProcess()->GetBreakpointSiteList().FindByAddress(pc); - - if (bp_site_sp) - { - // If the breakpoint is for this thread, then we'll report the hit, but if it is for another thread, - // we can just report no reason. We don't need to worry about stepping over the breakpoint here, that - // will be taken care of when the thread resumes and notices that there's a breakpoint under the pc. - if (bp_site_sp->ValidForThisThread (thread_sp.get())) - { - if(m_breakpoint_pc_offset != 0) - thread_sp->GetRegisterContext()->SetPC(pc); - thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID (*thread_sp, bp_site_sp->GetID())); - } - else - { - StopInfoSP invalid_stop_info_sp; - thread_sp->SetStopInfo (invalid_stop_info_sp); - } - } - else - { - // If we were stepping then assume the stop was the result of the trace. If we were - // not stepping then report the SIGTRAP. - // FIXME: We are still missing the case where we single step over a trap instruction. - if (thread_sp->GetTemporaryResumeState() == eStateStepping) - thread_sp->SetStopInfo (StopInfo::CreateStopReasonToTrace (*thread_sp)); - else - thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithSignal(*thread_sp, signo, description.c_str())); - } - } - if (!handled) - thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithSignal (*thread_sp, signo, description.c_str())); - } - - if (!description.empty()) - { - lldb::StopInfoSP stop_info_sp (thread_sp->GetStopInfo ()); - if (stop_info_sp) - { - const char *stop_info_desc = stop_info_sp->GetDescription(); - if (!stop_info_desc || !stop_info_desc[0]) - stop_info_sp->SetDescription (description.c_str()); - } - else - { - thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithException (*thread_sp, description.c_str())); - } - } - } + thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithSignal( + *thread_sp, signo, description.c_str())); + } } + if (!handled) + thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithSignal( + *thread_sp, signo, description.c_str())); + } + + if (!description.empty()) { + lldb::StopInfoSP stop_info_sp(thread_sp->GetStopInfo()); + if (stop_info_sp) { + const char *stop_info_desc = stop_info_sp->GetDescription(); + if (!stop_info_desc || !stop_info_desc[0]) + stop_info_sp->SetDescription(description.c_str()); + } else { + thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithException( + *thread_sp, description.c_str())); + } + } } + } } - return thread_sp; + } + return thread_sp; } lldb::ThreadSP -ProcessGDBRemote::SetThreadStopInfo (StructuredData::Dictionary *thread_dict) -{ - static ConstString g_key_tid("tid"); - static ConstString g_key_name("name"); - static ConstString g_key_reason("reason"); - static ConstString g_key_metype("metype"); - static ConstString g_key_medata("medata"); - static ConstString g_key_qaddr("qaddr"); - static ConstString g_key_dispatch_queue_t("dispatch_queue_t"); - static ConstString g_key_associated_with_dispatch_queue("associated_with_dispatch_queue"); - static ConstString g_key_queue_name("qname"); - static ConstString g_key_queue_kind("qkind"); - static ConstString g_key_queue_serial_number("qserialnum"); - static ConstString g_key_registers("registers"); - static ConstString g_key_memory("memory"); - static ConstString g_key_address("address"); - static ConstString g_key_bytes("bytes"); - static ConstString g_key_description("description"); - static ConstString g_key_signal("signal"); +ProcessGDBRemote::SetThreadStopInfo(StructuredData::Dictionary *thread_dict) { + static ConstString g_key_tid("tid"); + static ConstString g_key_name("name"); + static ConstString g_key_reason("reason"); + static ConstString g_key_metype("metype"); + static ConstString g_key_medata("medata"); + static ConstString g_key_qaddr("qaddr"); + static ConstString g_key_dispatch_queue_t("dispatch_queue_t"); + static ConstString g_key_associated_with_dispatch_queue( + "associated_with_dispatch_queue"); + static ConstString g_key_queue_name("qname"); + static ConstString g_key_queue_kind("qkind"); + static ConstString g_key_queue_serial_number("qserialnum"); + static ConstString g_key_registers("registers"); + static ConstString g_key_memory("memory"); + static ConstString g_key_address("address"); + static ConstString g_key_bytes("bytes"); + static ConstString g_key_description("description"); + static ConstString g_key_signal("signal"); + + // Stop with signal and thread info + lldb::tid_t tid = LLDB_INVALID_THREAD_ID; + uint8_t signo = 0; + std::string value; + std::string thread_name; + std::string reason; + std::string description; + uint32_t exc_type = 0; + std::vector<addr_t> exc_data; + addr_t thread_dispatch_qaddr = LLDB_INVALID_ADDRESS; + ExpeditedRegisterMap expedited_register_map; + bool queue_vars_valid = false; + addr_t dispatch_queue_t = LLDB_INVALID_ADDRESS; + LazyBool associated_with_dispatch_queue = eLazyBoolCalculate; + std::string queue_name; + QueueKind queue_kind = eQueueKindUnknown; + uint64_t queue_serial_number = 0; + // Iterate through all of the thread dictionary key/value pairs from the + // structured data dictionary + + thread_dict->ForEach([this, &tid, &expedited_register_map, &thread_name, + &signo, &reason, &description, &exc_type, &exc_data, + &thread_dispatch_qaddr, &queue_vars_valid, + &associated_with_dispatch_queue, &dispatch_queue_t, + &queue_name, &queue_kind, &queue_serial_number]( + ConstString key, + StructuredData::Object *object) -> bool { + if (key == g_key_tid) { + // thread in big endian hex + tid = object->GetIntegerValue(LLDB_INVALID_THREAD_ID); + } else if (key == g_key_metype) { + // exception type in big endian hex + exc_type = object->GetIntegerValue(0); + } else if (key == g_key_medata) { + // exception data in big endian hex + StructuredData::Array *array = object->GetAsArray(); + if (array) { + array->ForEach([&exc_data](StructuredData::Object *object) -> bool { + exc_data.push_back(object->GetIntegerValue()); + return true; // Keep iterating through all array items + }); + } + } else if (key == g_key_name) { + thread_name = object->GetStringValue(); + } else if (key == g_key_qaddr) { + thread_dispatch_qaddr = object->GetIntegerValue(LLDB_INVALID_ADDRESS); + } else if (key == g_key_queue_name) { + queue_vars_valid = true; + queue_name = object->GetStringValue(); + } else if (key == g_key_queue_kind) { + std::string queue_kind_str = object->GetStringValue(); + if (queue_kind_str == "serial") { + queue_vars_valid = true; + queue_kind = eQueueKindSerial; + } else if (queue_kind_str == "concurrent") { + queue_vars_valid = true; + queue_kind = eQueueKindConcurrent; + } + } else if (key == g_key_queue_serial_number) { + queue_serial_number = object->GetIntegerValue(0); + if (queue_serial_number != 0) + queue_vars_valid = true; + } else if (key == g_key_dispatch_queue_t) { + dispatch_queue_t = object->GetIntegerValue(0); + if (dispatch_queue_t != 0 && dispatch_queue_t != LLDB_INVALID_ADDRESS) + queue_vars_valid = true; + } else if (key == g_key_associated_with_dispatch_queue) { + queue_vars_valid = true; + bool associated = object->GetBooleanValue(); + if (associated) + associated_with_dispatch_queue = eLazyBoolYes; + else + associated_with_dispatch_queue = eLazyBoolNo; + } else if (key == g_key_reason) { + reason = object->GetStringValue(); + } else if (key == g_key_description) { + description = object->GetStringValue(); + } else if (key == g_key_registers) { + StructuredData::Dictionary *registers_dict = object->GetAsDictionary(); + + if (registers_dict) { + registers_dict->ForEach( + [&expedited_register_map](ConstString key, + StructuredData::Object *object) -> bool { + const uint32_t reg = + StringConvert::ToUInt32(key.GetCString(), UINT32_MAX, 10); + if (reg != UINT32_MAX) + expedited_register_map[reg] = object->GetStringValue(); + return true; // Keep iterating through all array items + }); + } + } else if (key == g_key_memory) { + StructuredData::Array *array = object->GetAsArray(); + if (array) { + array->ForEach([this](StructuredData::Object *object) -> bool { + StructuredData::Dictionary *mem_cache_dict = + object->GetAsDictionary(); + if (mem_cache_dict) { + lldb::addr_t mem_cache_addr = LLDB_INVALID_ADDRESS; + if (mem_cache_dict->GetValueForKeyAsInteger<lldb::addr_t>( + "address", mem_cache_addr)) { + if (mem_cache_addr != LLDB_INVALID_ADDRESS) { + StringExtractor bytes; + if (mem_cache_dict->GetValueForKeyAsString( + "bytes", bytes.GetStringRef())) { + bytes.SetFilePos(0); + + const size_t byte_size = bytes.GetStringRef().size() / 2; + DataBufferSP data_buffer_sp(new DataBufferHeap(byte_size, 0)); + const size_t bytes_copied = + bytes.GetHexBytes(data_buffer_sp->GetData(), 0); + if (bytes_copied == byte_size) + m_memory_cache.AddL1CacheData(mem_cache_addr, + data_buffer_sp); + } + } + } + } + return true; // Keep iterating through all array items + }); + } + + } else if (key == g_key_signal) + signo = object->GetIntegerValue(LLDB_INVALID_SIGNAL_NUMBER); + return true; // Keep iterating through all dictionary key/value pairs + }); + + return SetThreadStopInfo(tid, expedited_register_map, signo, thread_name, + reason, description, exc_type, exc_data, + thread_dispatch_qaddr, queue_vars_valid, + associated_with_dispatch_queue, dispatch_queue_t, + queue_name, queue_kind, queue_serial_number); +} +StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) { + stop_packet.SetFilePos(0); + const char stop_type = stop_packet.GetChar(); + switch (stop_type) { + case 'T': + case 'S': { + // This is a bit of a hack, but is is required. If we did exec, we + // need to clear our thread lists and also know to rebuild our dynamic + // register info before we lookup and threads and populate the expedited + // register values so we need to know this right away so we can cleanup + // and update our registers. + const uint32_t stop_id = GetStopID(); + if (stop_id == 0) { + // Our first stop, make sure we have a process ID, and also make + // sure we know about our registers + if (GetID() == LLDB_INVALID_PROCESS_ID) { + lldb::pid_t pid = m_gdb_comm.GetCurrentProcessID(); + if (pid != LLDB_INVALID_PROCESS_ID) + SetID(pid); + } + BuildDynamicRegisterInfo(true); + } // Stop with signal and thread info lldb::tid_t tid = LLDB_INVALID_THREAD_ID; - uint8_t signo = 0; - std::string value; + const uint8_t signo = stop_packet.GetHexU8(); + llvm::StringRef key; + llvm::StringRef value; std::string thread_name; std::string reason; std::string description; uint32_t exc_type = 0; std::vector<addr_t> exc_data; addr_t thread_dispatch_qaddr = LLDB_INVALID_ADDRESS; - ExpeditedRegisterMap expedited_register_map; - bool queue_vars_valid = false; + bool queue_vars_valid = + false; // says if locals below that start with "queue_" are valid addr_t dispatch_queue_t = LLDB_INVALID_ADDRESS; LazyBool associated_with_dispatch_queue = eLazyBoolCalculate; std::string queue_name; QueueKind queue_kind = eQueueKindUnknown; uint64_t queue_serial_number = 0; - // Iterate through all of the thread dictionary key/value pairs from the structured data dictionary - - thread_dict->ForEach([this, - &tid, - &expedited_register_map, - &thread_name, - &signo, - &reason, - &description, - &exc_type, - &exc_data, - &thread_dispatch_qaddr, - &queue_vars_valid, - &associated_with_dispatch_queue, - &dispatch_queue_t, - &queue_name, - &queue_kind, - &queue_serial_number] - (ConstString key, StructuredData::Object* object) -> bool - { - if (key == g_key_tid) - { - // thread in big endian hex - tid = object->GetIntegerValue(LLDB_INVALID_THREAD_ID); - } - else if (key == g_key_metype) - { - // exception type in big endian hex - exc_type = object->GetIntegerValue(0); - } - else if (key == g_key_medata) - { - // exception data in big endian hex - StructuredData::Array *array = object->GetAsArray(); - if (array) - { - array->ForEach([&exc_data](StructuredData::Object* object) -> bool { - exc_data.push_back(object->GetIntegerValue()); - return true; // Keep iterating through all array items - }); - } - } - else if (key == g_key_name) - { - thread_name = object->GetStringValue(); - } - else if (key == g_key_qaddr) - { - thread_dispatch_qaddr = object->GetIntegerValue(LLDB_INVALID_ADDRESS); - } - else if (key == g_key_queue_name) - { - queue_vars_valid = true; - queue_name = object->GetStringValue(); - } - else if (key == g_key_queue_kind) - { - std::string queue_kind_str = object->GetStringValue(); - if (queue_kind_str == "serial") - { - queue_vars_valid = true; - queue_kind = eQueueKindSerial; - } - else if (queue_kind_str == "concurrent") - { - queue_vars_valid = true; - queue_kind = eQueueKindConcurrent; - } - } - else if (key == g_key_queue_serial_number) - { - queue_serial_number = object->GetIntegerValue(0); - if (queue_serial_number != 0) - queue_vars_valid = true; - } - else if (key == g_key_dispatch_queue_t) - { - dispatch_queue_t = object->GetIntegerValue(0); - if (dispatch_queue_t != 0 && dispatch_queue_t != LLDB_INVALID_ADDRESS) - queue_vars_valid = true; - } - else if (key == g_key_associated_with_dispatch_queue) - { - queue_vars_valid = true; - bool associated = object->GetBooleanValue (); - if (associated) - associated_with_dispatch_queue = eLazyBoolYes; - else - associated_with_dispatch_queue = eLazyBoolNo; - } - else if (key == g_key_reason) - { - reason = object->GetStringValue(); - } - else if (key == g_key_description) - { - description = object->GetStringValue(); + ExpeditedRegisterMap expedited_register_map; + while (stop_packet.GetNameColonValue(key, value)) { + if (key.compare("metype") == 0) { + // exception type in big endian hex + value.getAsInteger(16, exc_type); + } else if (key.compare("medata") == 0) { + // exception data in big endian hex + uint64_t x; + value.getAsInteger(16, x); + exc_data.push_back(x); + } else if (key.compare("thread") == 0) { + // thread in big endian hex + if (value.getAsInteger(16, tid)) + tid = LLDB_INVALID_THREAD_ID; + } else if (key.compare("threads") == 0) { + std::lock_guard<std::recursive_mutex> guard( + m_thread_list_real.GetMutex()); + + m_thread_ids.clear(); + // A comma separated list of all threads in the current + // process that includes the thread for this stop reply + // packet + lldb::tid_t tid; + while (!value.empty()) { + llvm::StringRef tid_str; + std::tie(tid_str, value) = value.split(','); + if (tid_str.getAsInteger(16, tid)) + tid = LLDB_INVALID_THREAD_ID; + m_thread_ids.push_back(tid); } - else if (key == g_key_registers) - { - StructuredData::Dictionary *registers_dict = object->GetAsDictionary(); - - if (registers_dict) - { - registers_dict->ForEach([&expedited_register_map](ConstString key, StructuredData::Object* object) -> bool { - const uint32_t reg = StringConvert::ToUInt32 (key.GetCString(), UINT32_MAX, 10); - if (reg != UINT32_MAX) - expedited_register_map[reg] = object->GetStringValue(); - return true; // Keep iterating through all array items - }); - } + } else if (key.compare("thread-pcs") == 0) { + m_thread_pcs.clear(); + // A comma separated list of all threads in the current + // process that includes the thread for this stop reply + // packet + lldb::addr_t pc; + while (!value.empty()) { + llvm::StringRef pc_str; + std::tie(pc_str, value) = value.split(','); + if (pc_str.getAsInteger(16, pc)) + pc = LLDB_INVALID_ADDRESS; + m_thread_pcs.push_back(pc); } - else if (key == g_key_memory) - { - StructuredData::Array *array = object->GetAsArray(); - if (array) - { - array->ForEach([this](StructuredData::Object* object) -> bool { - StructuredData::Dictionary *mem_cache_dict = object->GetAsDictionary(); - if (mem_cache_dict) - { - lldb::addr_t mem_cache_addr = LLDB_INVALID_ADDRESS; - if (mem_cache_dict->GetValueForKeyAsInteger<lldb::addr_t>("address", mem_cache_addr)) - { - if (mem_cache_addr != LLDB_INVALID_ADDRESS) - { - StringExtractor bytes; - if (mem_cache_dict->GetValueForKeyAsString("bytes", bytes.GetStringRef())) - { - bytes.SetFilePos(0); - - const size_t byte_size = bytes.GetStringRef().size()/2; - DataBufferSP data_buffer_sp(new DataBufferHeap(byte_size, 0)); - const size_t bytes_copied = bytes.GetHexBytes (data_buffer_sp->GetBytes(), byte_size, 0); - if (bytes_copied == byte_size) - m_memory_cache.AddL1CacheData(mem_cache_addr, data_buffer_sp); - } - } - } - } - return true; // Keep iterating through all array items - }); - } - + } else if (key.compare("jstopinfo") == 0) { + StringExtractor json_extractor(value); + std::string json; + // Now convert the HEX bytes into a string value + json_extractor.GetHexByteString(json); + + // This JSON contains thread IDs and thread stop info for all threads. + // It doesn't contain expedited registers, memory or queue info. + m_jstopinfo_sp = StructuredData::ParseJSON(json); + } else if (key.compare("hexname") == 0) { + StringExtractor name_extractor(value); + std::string name; + // Now convert the HEX bytes into a string value + name_extractor.GetHexByteString(thread_name); + } else if (key.compare("name") == 0) { + thread_name = value; + } else if (key.compare("qaddr") == 0) { + value.getAsInteger(16, thread_dispatch_qaddr); + } else if (key.compare("dispatch_queue_t") == 0) { + queue_vars_valid = true; + value.getAsInteger(16, dispatch_queue_t); + } else if (key.compare("qname") == 0) { + queue_vars_valid = true; + StringExtractor name_extractor(value); + // Now convert the HEX bytes into a string value + name_extractor.GetHexByteString(queue_name); + } else if (key.compare("qkind") == 0) { + queue_kind = llvm::StringSwitch<QueueKind>(value) + .Case("serial", eQueueKindSerial) + .Case("concurrent", eQueueKindConcurrent) + .Default(eQueueKindUnknown); + queue_vars_valid = queue_kind != eQueueKindUnknown; + } else if (key.compare("qserialnum") == 0) { + if (!value.getAsInteger(0, queue_serial_number)) + queue_vars_valid = true; + } else if (key.compare("reason") == 0) { + reason = value; + } else if (key.compare("description") == 0) { + StringExtractor desc_extractor(value); + // Now convert the HEX bytes into a string value + desc_extractor.GetHexByteString(description); + } else if (key.compare("memory") == 0) { + // Expedited memory. GDB servers can choose to send back expedited + // memory + // that can populate the L1 memory cache in the process so that things + // like + // the frame pointer backchain can be expedited. This will help stack + // backtracing be more efficient by not having to send as many memory + // read + // requests down the remote GDB server. + + // Key/value pair format: memory:<addr>=<bytes>; + // <addr> is a number whose base will be interpreted by the prefix: + // "0x[0-9a-fA-F]+" for hex + // "0[0-7]+" for octal + // "[1-9]+" for decimal + // <bytes> is native endian ASCII hex bytes just like the register + // values + llvm::StringRef addr_str, bytes_str; + std::tie(addr_str, bytes_str) = value.split('='); + if (!addr_str.empty() && !bytes_str.empty()) { + lldb::addr_t mem_cache_addr = LLDB_INVALID_ADDRESS; + if (!addr_str.getAsInteger(0, mem_cache_addr)) { + StringExtractor bytes(bytes_str); + const size_t byte_size = bytes.GetBytesLeft() / 2; + DataBufferSP data_buffer_sp(new DataBufferHeap(byte_size, 0)); + const size_t bytes_copied = + bytes.GetHexBytes(data_buffer_sp->GetData(), 0); + if (bytes_copied == byte_size) + m_memory_cache.AddL1CacheData(mem_cache_addr, data_buffer_sp); + } } - else if (key == g_key_signal) - signo = object->GetIntegerValue(LLDB_INVALID_SIGNAL_NUMBER); - return true; // Keep iterating through all dictionary key/value pairs - }); - - return SetThreadStopInfo (tid, - expedited_register_map, - signo, - thread_name, - reason, - description, - exc_type, - exc_data, - thread_dispatch_qaddr, - queue_vars_valid, - associated_with_dispatch_queue, - dispatch_queue_t, - queue_name, - queue_kind, - queue_serial_number); + } else if (key.compare("watch") == 0 || key.compare("rwatch") == 0 || + key.compare("awatch") == 0) { + // Support standard GDB remote stop reply packet 'TAAwatch:addr' + lldb::addr_t wp_addr = LLDB_INVALID_ADDRESS; + value.getAsInteger(16, wp_addr); + + WatchpointSP wp_sp = + GetTarget().GetWatchpointList().FindByAddress(wp_addr); + uint32_t wp_index = LLDB_INVALID_INDEX32; + + if (wp_sp) + wp_index = wp_sp->GetHardwareIndex(); + + reason = "watchpoint"; + StreamString ostr; + ostr.Printf("%" PRIu64 " %" PRIu32, wp_addr, wp_index); + description = ostr.GetString(); + } else if (key.compare("library") == 0) { + LoadModules(); + } else if (key.size() == 2 && ::isxdigit(key[0]) && ::isxdigit(key[1])) { + uint32_t reg = UINT32_MAX; + if (!key.getAsInteger(16, reg)) + expedited_register_map[reg] = std::move(value); + } + } + + if (tid == LLDB_INVALID_THREAD_ID) { + // A thread id may be invalid if the response is old style 'S' packet + // which does not provide the + // thread information. So update the thread list and choose the first one. + UpdateThreadIDList(); + + if (!m_thread_ids.empty()) { + tid = m_thread_ids.front(); + } + } + + ThreadSP thread_sp = SetThreadStopInfo( + tid, expedited_register_map, signo, thread_name, reason, description, + exc_type, exc_data, thread_dispatch_qaddr, queue_vars_valid, + associated_with_dispatch_queue, dispatch_queue_t, queue_name, + queue_kind, queue_serial_number); + + return eStateStopped; + } break; + + case 'W': + case 'X': + // process exited + return eStateExited; + + default: + break; + } + return eStateInvalid; } -StateType -ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet) -{ - stop_packet.SetFilePos (0); - const char stop_type = stop_packet.GetChar(); - switch (stop_type) - { - case 'T': - case 'S': - { - // This is a bit of a hack, but is is required. If we did exec, we - // need to clear our thread lists and also know to rebuild our dynamic - // register info before we lookup and threads and populate the expedited - // register values so we need to know this right away so we can cleanup - // and update our registers. - const uint32_t stop_id = GetStopID(); - if (stop_id == 0) - { - // Our first stop, make sure we have a process ID, and also make - // sure we know about our registers - if (GetID() == LLDB_INVALID_PROCESS_ID) - { - lldb::pid_t pid = m_gdb_comm.GetCurrentProcessID (); - if (pid != LLDB_INVALID_PROCESS_ID) - SetID (pid); - } - BuildDynamicRegisterInfo (true); - } - // Stop with signal and thread info - lldb::tid_t tid = LLDB_INVALID_THREAD_ID; - const uint8_t signo = stop_packet.GetHexU8(); - std::string key; - std::string value; - std::string thread_name; - std::string reason; - std::string description; - uint32_t exc_type = 0; - std::vector<addr_t> exc_data; - addr_t thread_dispatch_qaddr = LLDB_INVALID_ADDRESS; - bool queue_vars_valid = false; // says if locals below that start with "queue_" are valid - addr_t dispatch_queue_t = LLDB_INVALID_ADDRESS; - LazyBool associated_with_dispatch_queue = eLazyBoolCalculate; - std::string queue_name; - QueueKind queue_kind = eQueueKindUnknown; - uint64_t queue_serial_number = 0; - ExpeditedRegisterMap expedited_register_map; - while (stop_packet.GetNameColonValue(key, value)) - { - if (key.compare("metype") == 0) - { - // exception type in big endian hex - exc_type = StringConvert::ToUInt32 (value.c_str(), 0, 16); - } - else if (key.compare("medata") == 0) - { - // exception data in big endian hex - exc_data.push_back(StringConvert::ToUInt64 (value.c_str(), 0, 16)); - } - else if (key.compare("thread") == 0) - { - // thread in big endian hex - tid = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_THREAD_ID, 16); - } - else if (key.compare("threads") == 0) - { - std::lock_guard<std::recursive_mutex> guard(m_thread_list_real.GetMutex()); - - m_thread_ids.clear(); - // A comma separated list of all threads in the current - // process that includes the thread for this stop reply - // packet - size_t comma_pos; - lldb::tid_t tid; - while ((comma_pos = value.find(',')) != std::string::npos) - { - value[comma_pos] = '\0'; - // thread in big endian hex - tid = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_THREAD_ID, 16); - if (tid != LLDB_INVALID_THREAD_ID) - m_thread_ids.push_back (tid); - value.erase(0, comma_pos + 1); - } - tid = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_THREAD_ID, 16); - if (tid != LLDB_INVALID_THREAD_ID) - m_thread_ids.push_back (tid); - } - else if (key.compare("thread-pcs") == 0) - { - m_thread_pcs.clear(); - // A comma separated list of all threads in the current - // process that includes the thread for this stop reply - // packet - size_t comma_pos; - lldb::addr_t pc; - while ((comma_pos = value.find(',')) != std::string::npos) - { - value[comma_pos] = '\0'; - // thread in big endian hex - pc = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_ADDRESS, 16); - if (pc != LLDB_INVALID_ADDRESS) - m_thread_pcs.push_back (pc); - value.erase(0, comma_pos + 1); - } - pc = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_ADDRESS, 16); - if (pc != LLDB_INVALID_ADDRESS) - m_thread_pcs.push_back (pc); - } - else if (key.compare("jstopinfo") == 0) - { - StringExtractor json_extractor; - // Swap "value" over into "name_extractor" - json_extractor.GetStringRef().swap(value); - // Now convert the HEX bytes into a string value - json_extractor.GetHexByteString (value); - - // This JSON contains thread IDs and thread stop info for all threads. - // It doesn't contain expedited registers, memory or queue info. - m_jstopinfo_sp = StructuredData::ParseJSON (value); - } - else if (key.compare("hexname") == 0) - { - StringExtractor name_extractor; - // Swap "value" over into "name_extractor" - name_extractor.GetStringRef().swap(value); - // Now convert the HEX bytes into a string value - name_extractor.GetHexByteString (value); - thread_name.swap (value); - } - else if (key.compare("name") == 0) - { - thread_name.swap (value); - } - else if (key.compare("qaddr") == 0) - { - thread_dispatch_qaddr = StringConvert::ToUInt64 (value.c_str(), 0, 16); - } - else if (key.compare("dispatch_queue_t") == 0) - { - queue_vars_valid = true; - dispatch_queue_t = StringConvert::ToUInt64 (value.c_str(), 0, 16); - } - else if (key.compare("qname") == 0) - { - queue_vars_valid = true; - StringExtractor name_extractor; - // Swap "value" over into "name_extractor" - name_extractor.GetStringRef().swap(value); - // Now convert the HEX bytes into a string value - name_extractor.GetHexByteString (value); - queue_name.swap (value); - } - else if (key.compare("qkind") == 0) - { - if (value == "serial") - { - queue_vars_valid = true; - queue_kind = eQueueKindSerial; - } - else if (value == "concurrent") - { - queue_vars_valid = true; - queue_kind = eQueueKindConcurrent; - } - } - else if (key.compare("qserialnum") == 0) - { - queue_serial_number = StringConvert::ToUInt64 (value.c_str(), 0, 0); - if (queue_serial_number != 0) - queue_vars_valid = true; - } - else if (key.compare("reason") == 0) - { - reason.swap(value); - } - else if (key.compare("description") == 0) - { - StringExtractor desc_extractor; - // Swap "value" over into "name_extractor" - desc_extractor.GetStringRef().swap(value); - // Now convert the HEX bytes into a string value - desc_extractor.GetHexByteString (value); - description.swap(value); - } - else if (key.compare("memory") == 0) - { - // Expedited memory. GDB servers can choose to send back expedited memory - // that can populate the L1 memory cache in the process so that things like - // the frame pointer backchain can be expedited. This will help stack - // backtracing be more efficient by not having to send as many memory read - // requests down the remote GDB server. - - // Key/value pair format: memory:<addr>=<bytes>; - // <addr> is a number whose base will be interpreted by the prefix: - // "0x[0-9a-fA-F]+" for hex - // "0[0-7]+" for octal - // "[1-9]+" for decimal - // <bytes> is native endian ASCII hex bytes just like the register values - llvm::StringRef value_ref(value); - std::pair<llvm::StringRef, llvm::StringRef> pair; - pair = value_ref.split('='); - if (!pair.first.empty() && !pair.second.empty()) - { - std::string addr_str(pair.first.str()); - const lldb::addr_t mem_cache_addr = StringConvert::ToUInt64(addr_str.c_str(), LLDB_INVALID_ADDRESS, 0); - if (mem_cache_addr != LLDB_INVALID_ADDRESS) - { - StringExtractor bytes; - bytes.GetStringRef() = pair.second.str(); - const size_t byte_size = bytes.GetStringRef().size()/2; - DataBufferSP data_buffer_sp(new DataBufferHeap(byte_size, 0)); - const size_t bytes_copied = bytes.GetHexBytes (data_buffer_sp->GetBytes(), byte_size, 0); - if (bytes_copied == byte_size) - m_memory_cache.AddL1CacheData(mem_cache_addr, data_buffer_sp); - } - } - } - else if (key.compare("watch") == 0 || key.compare("rwatch") == 0 || key.compare("awatch") == 0) - { - // Support standard GDB remote stop reply packet 'TAAwatch:addr' - lldb::addr_t wp_addr = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_ADDRESS, 16); - WatchpointSP wp_sp = GetTarget().GetWatchpointList().FindByAddress(wp_addr); - uint32_t wp_index = LLDB_INVALID_INDEX32; - - if (wp_sp) - wp_index = wp_sp->GetHardwareIndex(); - - reason = "watchpoint"; - StreamString ostr; - ostr.Printf("%" PRIu64 " %" PRIu32, wp_addr, wp_index); - description = ostr.GetString().c_str(); - } - else if (key.compare("library") == 0) - { - LoadModules(); - } - else if (key.size() == 2 && ::isxdigit(key[0]) && ::isxdigit(key[1])) - { - uint32_t reg = StringConvert::ToUInt32 (key.c_str(), UINT32_MAX, 16); - if (reg != UINT32_MAX) - expedited_register_map[reg] = std::move(value); - } - } - - if (tid == LLDB_INVALID_THREAD_ID) - { - // A thread id may be invalid if the response is old style 'S' packet which does not provide the - // thread information. So update the thread list and choose the first one. - UpdateThreadIDList (); - - if (!m_thread_ids.empty ()) - { - tid = m_thread_ids.front (); - } - } - - ThreadSP thread_sp = SetThreadStopInfo (tid, - expedited_register_map, - signo, - thread_name, - reason, - description, - exc_type, - exc_data, - thread_dispatch_qaddr, - queue_vars_valid, - associated_with_dispatch_queue, - dispatch_queue_t, - queue_name, - queue_kind, - queue_serial_number); - - return eStateStopped; - } - break; - - case 'W': - case 'X': - // process exited - return eStateExited; - - default: - break; - } - return eStateInvalid; +void ProcessGDBRemote::RefreshStateAfterStop() { + std::lock_guard<std::recursive_mutex> guard(m_thread_list_real.GetMutex()); + + m_thread_ids.clear(); + m_thread_pcs.clear(); + // Set the thread stop info. It might have a "threads" key whose value is + // a list of all thread IDs in the current process, so m_thread_ids might + // get set. + + // Scope for the lock + { + // Lock the thread stack while we access it + std::lock_guard<std::recursive_mutex> guard(m_last_stop_packet_mutex); + // Get the number of stop packets on the stack + int nItems = m_stop_packet_stack.size(); + // Iterate over them + for (int i = 0; i < nItems; i++) { + // Get the thread stop info + StringExtractorGDBRemote stop_info = m_stop_packet_stack[i]; + // Process thread stop info + SetThreadStopInfo(stop_info); + } + // Clear the thread stop stack + m_stop_packet_stack.clear(); + } + + // Check to see if SetThreadStopInfo() filled in m_thread_ids? + if (m_thread_ids.empty()) { + // No, we need to fetch the thread list manually + UpdateThreadIDList(); + } + + // If we have queried for a default thread id + if (m_initial_tid != LLDB_INVALID_THREAD_ID) { + m_thread_list.SetSelectedThreadByID(m_initial_tid); + m_initial_tid = LLDB_INVALID_THREAD_ID; + } + + // Let all threads recover from stopping and do any clean up based + // on the previous thread state (if any). + m_thread_list_real.RefreshStateAfterStop(); } -void -ProcessGDBRemote::RefreshStateAfterStop () -{ - std::lock_guard<std::recursive_mutex> guard(m_thread_list_real.GetMutex()); - - m_thread_ids.clear(); - m_thread_pcs.clear(); - // Set the thread stop info. It might have a "threads" key whose value is - // a list of all thread IDs in the current process, so m_thread_ids might - // get set. - - // Scope for the lock - { - // Lock the thread stack while we access it - std::lock_guard<std::recursive_mutex> guard(m_last_stop_packet_mutex); - // Get the number of stop packets on the stack - int nItems = m_stop_packet_stack.size(); - // Iterate over them - for (int i = 0; i < nItems; i++) - { - // Get the thread stop info - StringExtractorGDBRemote stop_info = m_stop_packet_stack[i]; - // Process thread stop info - SetThreadStopInfo(stop_info); - } - // Clear the thread stop stack - m_stop_packet_stack.clear(); - } - - // Check to see if SetThreadStopInfo() filled in m_thread_ids? - if (m_thread_ids.empty()) - { - // No, we need to fetch the thread list manually - UpdateThreadIDList(); - } - - // If we have queried for a default thread id - if (m_initial_tid != LLDB_INVALID_THREAD_ID) - { - m_thread_list.SetSelectedThreadByID(m_initial_tid); - m_initial_tid = LLDB_INVALID_THREAD_ID; - } - - // Let all threads recover from stopping and do any clean up based - // on the previous thread state (if any). - m_thread_list_real.RefreshStateAfterStop(); +Error ProcessGDBRemote::DoHalt(bool &caused_stop) { + Error error; + if (m_public_state.GetValue() == eStateAttaching) { + // We are being asked to halt during an attach. We need to just close + // our file handle and debugserver will go away, and we can be done... + m_gdb_comm.Disconnect(); + } else + caused_stop = m_gdb_comm.Interrupt(); + return error; } -Error -ProcessGDBRemote::DoHalt (bool &caused_stop) -{ - Error error; - - bool timed_out = false; - Mutex::Locker locker; +Error ProcessGDBRemote::DoDetach(bool keep_stopped) { + Error error; + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + if (log) + log->Printf("ProcessGDBRemote::DoDetach(keep_stopped: %i)", keep_stopped); - if (m_public_state.GetValue() == eStateAttaching) - { - // We are being asked to halt during an attach. We need to just close - // our file handle and debugserver will go away, and we can be done... - m_gdb_comm.Disconnect(); - } + error = m_gdb_comm.Detach(keep_stopped); + if (log) { + if (error.Success()) + log->PutCString( + "ProcessGDBRemote::DoDetach() detach packet sent successfully"); else - { - if (!m_gdb_comm.SendInterrupt (locker, 2, timed_out)) - { - if (timed_out) - error.SetErrorString("timed out sending interrupt packet"); - else - error.SetErrorString("unknown error sending interrupt packet"); - } + log->Printf("ProcessGDBRemote::DoDetach() detach packet send failed: %s", + error.AsCString() ? error.AsCString() : "<unknown error>"); + } - caused_stop = m_gdb_comm.GetInterruptWasSent (); - } + if (!error.Success()) return error; -} -Error -ProcessGDBRemote::DoDetach(bool keep_stopped) -{ - Error error; - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); - if (log) - log->Printf ("ProcessGDBRemote::DoDetach(keep_stopped: %i)", keep_stopped); + // Sleep for one second to let the process get all detached... + StopAsyncThread(); - error = m_gdb_comm.Detach (keep_stopped); - if (log) - { - if (error.Success()) - log->PutCString ("ProcessGDBRemote::DoDetach() detach packet sent successfully"); - else - log->Printf ("ProcessGDBRemote::DoDetach() detach packet send failed: %s", error.AsCString() ? error.AsCString() : "<unknown error>"); - } - - if (!error.Success()) - return error; + SetPrivateState(eStateDetached); + ResumePrivateStateThread(); - // Sleep for one second to let the process get all detached... - StopAsyncThread (); - - SetPrivateState (eStateDetached); - ResumePrivateStateThread(); - - //KillDebugserverProcess (); - return error; + // KillDebugserverProcess (); + return error; } - -Error -ProcessGDBRemote::DoDestroy () -{ - Error error; - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); - if (log) - log->Printf ("ProcessGDBRemote::DoDestroy()"); +Error ProcessGDBRemote::DoDestroy() { + Error error; + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + if (log) + log->Printf("ProcessGDBRemote::DoDestroy()"); #if 0 // XXX Currently no iOS target support on FreeBSD - // There is a bug in older iOS debugservers where they don't shut down the process - // they are debugging properly. If the process is sitting at a breakpoint or an exception, - // this can cause problems with restarting. So we check to see if any of our threads are stopped - // at a breakpoint, and if so we remove all the breakpoints, resume the process, and THEN - // destroy it again. - // - // Note, we don't have a good way to test the version of debugserver, but I happen to know that - // the set of all the iOS debugservers which don't support GetThreadSuffixSupported() and that of - // the debugservers with this bug are equal. There really should be a better way to test this! - // - // We also use m_destroy_tried_resuming to make sure we only do this once, if we resume and then halt and - // get called here to destroy again and we're still at a breakpoint or exception, then we should - // just do the straight-forward kill. - // - // And of course, if we weren't able to stop the process by the time we get here, it isn't - // necessary (or helpful) to do any of this. - - if (!m_gdb_comm.GetThreadSuffixSupported() && m_public_state.GetValue() != eStateRunning) - { - PlatformSP platform_sp = GetTarget().GetPlatform(); + // There is a bug in older iOS debugservers where they don't shut down the + // process + // they are debugging properly. If the process is sitting at a breakpoint or + // an exception, + // this can cause problems with restarting. So we check to see if any of our + // threads are stopped + // at a breakpoint, and if so we remove all the breakpoints, resume the + // process, and THEN + // destroy it again. + // + // Note, we don't have a good way to test the version of debugserver, but I + // happen to know that + // the set of all the iOS debugservers which don't support + // GetThreadSuffixSupported() and that of + // the debugservers with this bug are equal. There really should be a better + // way to test this! + // + // We also use m_destroy_tried_resuming to make sure we only do this once, if + // we resume and then halt and + // get called here to destroy again and we're still at a breakpoint or + // exception, then we should + // just do the straight-forward kill. + // + // And of course, if we weren't able to stop the process by the time we get + // here, it isn't + // necessary (or helpful) to do any of this. + + if (!m_gdb_comm.GetThreadSuffixSupported() && + m_public_state.GetValue() != eStateRunning) { + PlatformSP platform_sp = GetTarget().GetPlatform(); + + // FIXME: These should be ConstStrings so we aren't doing strcmp'ing. + if (platform_sp && platform_sp->GetName() && + platform_sp->GetName() == PlatformRemoteiOS::GetPluginNameStatic()) { + if (m_destroy_tried_resuming) { + if (log) + log->PutCString("ProcessGDBRemote::DoDestroy() - Tried resuming to " + "destroy once already, not doing it again."); + } else { + // At present, the plans are discarded and the breakpoints disabled + // Process::Destroy, + // but we really need it to happen here and it doesn't matter if we do + // it twice. + m_thread_list.DiscardThreadPlans(); + DisableAllBreakpointSites(); + + bool stop_looks_like_crash = false; + ThreadList &threads = GetThreadList(); - // FIXME: These should be ConstStrings so we aren't doing strcmp'ing. - if (platform_sp - && platform_sp->GetName() - && platform_sp->GetName() == PlatformRemoteiOS::GetPluginNameStatic()) { - if (m_destroy_tried_resuming) - { - if (log) - log->PutCString ("ProcessGDBRemote::DoDestroy() - Tried resuming to destroy once already, not doing it again."); + std::lock_guard<std::recursive_mutex> guard(threads.GetMutex()); + + size_t num_threads = threads.GetSize(); + for (size_t i = 0; i < num_threads; i++) { + ThreadSP thread_sp = threads.GetThreadAtIndex(i); + StopInfoSP stop_info_sp = thread_sp->GetPrivateStopInfo(); + StopReason reason = eStopReasonInvalid; + if (stop_info_sp) + reason = stop_info_sp->GetStopReason(); + if (reason == eStopReasonBreakpoint || + reason == eStopReasonException) { + if (log) + log->Printf( + "ProcessGDBRemote::DoDestroy() - thread: 0x%4.4" PRIx64 + " stopped with reason: %s.", + thread_sp->GetProtocolID(), stop_info_sp->GetDescription()); + stop_looks_like_crash = true; + break; } - else - { - // At present, the plans are discarded and the breakpoints disabled Process::Destroy, - // but we really need it to happen here and it doesn't matter if we do it twice. - m_thread_list.DiscardThreadPlans(); - DisableAllBreakpointSites(); - - bool stop_looks_like_crash = false; - ThreadList &threads = GetThreadList(); - - { - std::lock_guard<std::recursive_mutex> guard(threads.GetMutex()); - - size_t num_threads = threads.GetSize(); - for (size_t i = 0; i < num_threads; i++) - { - ThreadSP thread_sp = threads.GetThreadAtIndex(i); - StopInfoSP stop_info_sp = thread_sp->GetPrivateStopInfo(); - StopReason reason = eStopReasonInvalid; - if (stop_info_sp) - reason = stop_info_sp->GetStopReason(); - if (reason == eStopReasonBreakpoint - || reason == eStopReasonException) - { - if (log) - log->Printf ("ProcessGDBRemote::DoDestroy() - thread: 0x%4.4" PRIx64 " stopped with reason: %s.", - thread_sp->GetProtocolID(), - stop_info_sp->GetDescription()); - stop_looks_like_crash = true; - break; - } - } - } + } + } - if (stop_looks_like_crash) - { - if (log) - log->PutCString ("ProcessGDBRemote::DoDestroy() - Stopped at a breakpoint, continue and then kill."); - m_destroy_tried_resuming = true; - - // If we are going to run again before killing, it would be good to suspend all the threads - // before resuming so they won't get into more trouble. Sadly, for the threads stopped with - // the breakpoint or exception, the exception doesn't get cleared if it is suspended, so we do - // have to run the risk of letting those threads proceed a bit. - - { - std::lock_guard<std::recursive_mutex> guard(threads.GetMutex()); - - size_t num_threads = threads.GetSize(); - for (size_t i = 0; i < num_threads; i++) - { - ThreadSP thread_sp = threads.GetThreadAtIndex(i); - StopInfoSP stop_info_sp = thread_sp->GetPrivateStopInfo(); - StopReason reason = eStopReasonInvalid; - if (stop_info_sp) - reason = stop_info_sp->GetStopReason(); - if (reason != eStopReasonBreakpoint - && reason != eStopReasonException) - { - if (log) - log->Printf ("ProcessGDBRemote::DoDestroy() - Suspending thread: 0x%4.4" PRIx64 " before running.", - thread_sp->GetProtocolID()); - thread_sp->SetResumeState(eStateSuspended); - } - } - } - Resume (); - return Destroy(false); - } + if (stop_looks_like_crash) { + if (log) + log->PutCString("ProcessGDBRemote::DoDestroy() - Stopped at a " + "breakpoint, continue and then kill."); + m_destroy_tried_resuming = true; + + // If we are going to run again before killing, it would be good to + // suspend all the threads + // before resuming so they won't get into more trouble. Sadly, for + // the threads stopped with + // the breakpoint or exception, the exception doesn't get cleared if + // it is suspended, so we do + // have to run the risk of letting those threads proceed a bit. + + { + std::lock_guard<std::recursive_mutex> guard(threads.GetMutex()); + + size_t num_threads = threads.GetSize(); + for (size_t i = 0; i < num_threads; i++) { + ThreadSP thread_sp = threads.GetThreadAtIndex(i); + StopInfoSP stop_info_sp = thread_sp->GetPrivateStopInfo(); + StopReason reason = eStopReasonInvalid; + if (stop_info_sp) + reason = stop_info_sp->GetStopReason(); + if (reason != eStopReasonBreakpoint && + reason != eStopReasonException) { + if (log) + log->Printf("ProcessGDBRemote::DoDestroy() - Suspending " + "thread: 0x%4.4" PRIx64 " before running.", + thread_sp->GetProtocolID()); + thread_sp->SetResumeState(eStateSuspended); + } } + } + Resume(); + return Destroy(false); } + } } + } #endif - // Interrupt if our inferior is running... - int exit_status = SIGABRT; - std::string exit_string; + // Interrupt if our inferior is running... + int exit_status = SIGABRT; + std::string exit_string; - if (m_gdb_comm.IsConnected()) - { - if (m_public_state.GetValue() != eStateAttaching) - { - StringExtractorGDBRemote response; - bool send_async = true; - GDBRemoteCommunication::ScopedTimeout (m_gdb_comm, 3); + if (m_gdb_comm.IsConnected()) { + if (m_public_state.GetValue() != eStateAttaching) { + StringExtractorGDBRemote response; + bool send_async = true; + GDBRemoteCommunication::ScopedTimeout(m_gdb_comm, + std::chrono::seconds(3)); - if (m_gdb_comm.SendPacketAndWaitForResponse("k", 1, response, send_async) == GDBRemoteCommunication::PacketResult::Success) - { - char packet_cmd = response.GetChar(0); + if (m_gdb_comm.SendPacketAndWaitForResponse("k", response, send_async) == + GDBRemoteCommunication::PacketResult::Success) { + char packet_cmd = response.GetChar(0); - if (packet_cmd == 'W' || packet_cmd == 'X') - { + if (packet_cmd == 'W' || packet_cmd == 'X') { #if defined(__APPLE__) - // For Native processes on Mac OS X, we launch through the Host Platform, then hand the process off - // to debugserver, which becomes the parent process through "PT_ATTACH". Then when we go to kill - // the process on Mac OS X we call ptrace(PT_KILL) to kill it, then we call waitpid which returns - // with no error and the correct status. But amusingly enough that doesn't seem to actually reap - // the process, but instead it is left around as a Zombie. Probably the kernel is in the process of - // switching ownership back to lldb which was the original parent, and gets confused in the handoff. - // Anyway, so call waitpid here to finally reap it. - PlatformSP platform_sp(GetTarget().GetPlatform()); - if (platform_sp && platform_sp->IsHost()) - { - int status; - ::pid_t reap_pid; - reap_pid = waitpid (GetID(), &status, WNOHANG); - if (log) - log->Printf ("Reaped pid: %d, status: %d.\n", reap_pid, status); - } -#endif - SetLastStopPacket (response); - ClearThreadIDList (); - exit_status = response.GetHexU8(); - } - else - { - if (log) - log->Printf ("ProcessGDBRemote::DoDestroy - got unexpected response to k packet: %s", response.GetStringRef().c_str()); - exit_string.assign("got unexpected response to k packet: "); - exit_string.append(response.GetStringRef()); - } - } - else - { - if (log) - log->Printf ("ProcessGDBRemote::DoDestroy - failed to send k packet"); - exit_string.assign("failed to send the k packet"); - } - } - else - { + // For Native processes on Mac OS X, we launch through the Host + // Platform, then hand the process off + // to debugserver, which becomes the parent process through + // "PT_ATTACH". Then when we go to kill + // the process on Mac OS X we call ptrace(PT_KILL) to kill it, then we + // call waitpid which returns + // with no error and the correct status. But amusingly enough that + // doesn't seem to actually reap + // the process, but instead it is left around as a Zombie. Probably + // the kernel is in the process of + // switching ownership back to lldb which was the original parent, and + // gets confused in the handoff. + // Anyway, so call waitpid here to finally reap it. + PlatformSP platform_sp(GetTarget().GetPlatform()); + if (platform_sp && platform_sp->IsHost()) { + int status; + ::pid_t reap_pid; + reap_pid = waitpid(GetID(), &status, WNOHANG); if (log) - log->Printf ("ProcessGDBRemote::DoDestroy - killed or interrupted while attaching"); - exit_string.assign ("killed or interrupted while attaching."); + log->Printf("Reaped pid: %d, status: %d.\n", reap_pid, status); + } +#endif + SetLastStopPacket(response); + ClearThreadIDList(); + exit_status = response.GetHexU8(); + } else { + if (log) + log->Printf("ProcessGDBRemote::DoDestroy - got unexpected response " + "to k packet: %s", + response.GetStringRef().c_str()); + exit_string.assign("got unexpected response to k packet: "); + exit_string.append(response.GetStringRef()); } - } - else - { - // If we missed setting the exit status on the way out, do it here. - // NB set exit status can be called multiple times, the first one sets the status. - exit_string.assign("destroying when not connected to debugserver"); - } - - SetExitStatus(exit_status, exit_string.c_str()); - - StopAsyncThread (); - KillDebugserverProcess (); - return error; -} - -void -ProcessGDBRemote::SetLastStopPacket (const StringExtractorGDBRemote &response) -{ - const bool did_exec = response.GetStringRef().find(";reason:exec;") != std::string::npos; - if (did_exec) - { - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + } else { if (log) - log->Printf ("ProcessGDBRemote::SetLastStopPacket () - detected exec"); + log->Printf("ProcessGDBRemote::DoDestroy - failed to send k packet"); + exit_string.assign("failed to send the k packet"); + } + } else { + if (log) + log->Printf("ProcessGDBRemote::DoDestroy - killed or interrupted while " + "attaching"); + exit_string.assign("killed or interrupted while attaching."); + } + } else { + // If we missed setting the exit status on the way out, do it here. + // NB set exit status can be called multiple times, the first one sets the + // status. + exit_string.assign("destroying when not connected to debugserver"); + } + + SetExitStatus(exit_status, exit_string.c_str()); + + StopAsyncThread(); + KillDebugserverProcess(); + return error; +} - m_thread_list_real.Clear(); - m_thread_list.Clear(); - BuildDynamicRegisterInfo (true); - m_gdb_comm.ResetDiscoverableSettings (did_exec); - } +void ProcessGDBRemote::SetLastStopPacket( + const StringExtractorGDBRemote &response) { + const bool did_exec = + response.GetStringRef().find(";reason:exec;") != std::string::npos; + if (did_exec) { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + if (log) + log->Printf("ProcessGDBRemote::SetLastStopPacket () - detected exec"); - // Scope the lock - { - // Lock the thread stack while we access it - std::lock_guard<std::recursive_mutex> guard(m_last_stop_packet_mutex); - - // We are are not using non-stop mode, there can only be one last stop - // reply packet, so clear the list. - if (GetTarget().GetNonStopModeEnabled() == false) - m_stop_packet_stack.clear(); - - // Add this stop packet to the stop packet stack - // This stack will get popped and examined when we switch to the - // Stopped state - m_stop_packet_stack.push_back(response); - } + m_thread_list_real.Clear(); + m_thread_list.Clear(); + BuildDynamicRegisterInfo(true); + m_gdb_comm.ResetDiscoverableSettings(did_exec); + } + + // Scope the lock + { + // Lock the thread stack while we access it + std::lock_guard<std::recursive_mutex> guard(m_last_stop_packet_mutex); + + // We are are not using non-stop mode, there can only be one last stop + // reply packet, so clear the list. + if (GetTarget().GetNonStopModeEnabled() == false) + m_stop_packet_stack.clear(); + + // Add this stop packet to the stop packet stack + // This stack will get popped and examined when we switch to the + // Stopped state + m_stop_packet_stack.push_back(response); + } } -void -ProcessGDBRemote::SetUnixSignals(const UnixSignalsSP &signals_sp) -{ - Process::SetUnixSignals(std::make_shared<GDBRemoteSignals>(signals_sp)); +void ProcessGDBRemote::SetUnixSignals(const UnixSignalsSP &signals_sp) { + Process::SetUnixSignals(std::make_shared<GDBRemoteSignals>(signals_sp)); } //------------------------------------------------------------------ // Process Queries //------------------------------------------------------------------ -bool -ProcessGDBRemote::IsAlive () -{ - return m_gdb_comm.IsConnected() && Process::IsAlive(); +bool ProcessGDBRemote::IsAlive() { + return m_gdb_comm.IsConnected() && Process::IsAlive(); } -addr_t -ProcessGDBRemote::GetImageInfoAddress() -{ - // request the link map address via the $qShlibInfoAddr packet - lldb::addr_t addr = m_gdb_comm.GetShlibInfoAddr(); +addr_t ProcessGDBRemote::GetImageInfoAddress() { + // request the link map address via the $qShlibInfoAddr packet + lldb::addr_t addr = m_gdb_comm.GetShlibInfoAddr(); - // the loaded module list can also provides a link map address - if (addr == LLDB_INVALID_ADDRESS) - { - LoadedModuleInfoList list; - if (GetLoadedModuleList (list).Success()) - addr = list.m_link_map; - } + // the loaded module list can also provides a link map address + if (addr == LLDB_INVALID_ADDRESS) { + LoadedModuleInfoList list; + if (GetLoadedModuleList(list).Success()) + addr = list.m_link_map; + } - return addr; + return addr; } -void -ProcessGDBRemote::WillPublicStop () -{ - // See if the GDB remote client supports the JSON threads info. - // If so, we gather stop info for all threads, expedited registers, - // expedited memory, runtime queue information (iOS and MacOSX only), - // and more. Expediting memory will help stack backtracing be much - // faster. Expediting registers will make sure we don't have to read - // the thread registers for GPRs. - m_jthreadsinfo_sp = m_gdb_comm.GetThreadsInfo(); - - if (m_jthreadsinfo_sp) - { - // Now set the stop info for each thread and also expedite any registers - // and memory that was in the jThreadsInfo response. - StructuredData::Array *thread_infos = m_jthreadsinfo_sp->GetAsArray(); - if (thread_infos) - { - const size_t n = thread_infos->GetSize(); - for (size_t i=0; i<n; ++i) - { - StructuredData::Dictionary *thread_dict = thread_infos->GetItemAtIndex(i)->GetAsDictionary(); - if (thread_dict) - SetThreadStopInfo(thread_dict); - } - } - } +void ProcessGDBRemote::WillPublicStop() { + // See if the GDB remote client supports the JSON threads info. + // If so, we gather stop info for all threads, expedited registers, + // expedited memory, runtime queue information (iOS and MacOSX only), + // and more. Expediting memory will help stack backtracing be much + // faster. Expediting registers will make sure we don't have to read + // the thread registers for GPRs. + m_jthreadsinfo_sp = m_gdb_comm.GetThreadsInfo(); + + if (m_jthreadsinfo_sp) { + // Now set the stop info for each thread and also expedite any registers + // and memory that was in the jThreadsInfo response. + StructuredData::Array *thread_infos = m_jthreadsinfo_sp->GetAsArray(); + if (thread_infos) { + const size_t n = thread_infos->GetSize(); + for (size_t i = 0; i < n; ++i) { + StructuredData::Dictionary *thread_dict = + thread_infos->GetItemAtIndex(i)->GetAsDictionary(); + if (thread_dict) + SetThreadStopInfo(thread_dict); + } + } + } } //------------------------------------------------------------------ // Process Memory //------------------------------------------------------------------ -size_t -ProcessGDBRemote::DoReadMemory (addr_t addr, void *buf, size_t size, Error &error) -{ - GetMaxMemorySize (); - if (size > m_max_memory_size) - { - // Keep memory read sizes down to a sane limit. This function will be - // called multiple times in order to complete the task by - // lldb_private::Process so it is ok to do this. - size = m_max_memory_size; - } - - char packet[64]; - int packet_len; - bool binary_memory_read = m_gdb_comm.GetxPacketSupported(); - packet_len = ::snprintf(packet, sizeof(packet), "%c%" PRIx64 ",%" PRIx64, - binary_memory_read ? 'x' : 'm', (uint64_t)addr, (uint64_t)size); - assert (packet_len + 1 < (int)sizeof(packet)); - StringExtractorGDBRemote response; - if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, true) == GDBRemoteCommunication::PacketResult::Success) - { - if (response.IsNormalResponse()) - { - error.Clear(); - if (binary_memory_read) - { - // The lower level GDBRemoteCommunication packet receive layer has already de-quoted any - // 0x7d character escaping that was present in the packet - - size_t data_received_size = response.GetBytesLeft(); - if (data_received_size > size) - { - // Don't write past the end of BUF if the remote debug server gave us too - // much data for some reason. - data_received_size = size; - } - memcpy (buf, response.GetStringRef().data(), data_received_size); - return data_received_size; - } - else - { - return response.GetHexBytes(buf, size, '\xdd'); - } +size_t ProcessGDBRemote::DoReadMemory(addr_t addr, void *buf, size_t size, + Error &error) { + GetMaxMemorySize(); + if (size > m_max_memory_size) { + // Keep memory read sizes down to a sane limit. This function will be + // called multiple times in order to complete the task by + // lldb_private::Process so it is ok to do this. + size = m_max_memory_size; + } + + char packet[64]; + int packet_len; + bool binary_memory_read = m_gdb_comm.GetxPacketSupported(); + packet_len = ::snprintf(packet, sizeof(packet), "%c%" PRIx64 ",%" PRIx64, + binary_memory_read ? 'x' : 'm', (uint64_t)addr, + (uint64_t)size); + assert(packet_len + 1 < (int)sizeof(packet)); + UNUSED_IF_ASSERT_DISABLED(packet_len); + StringExtractorGDBRemote response; + if (m_gdb_comm.SendPacketAndWaitForResponse(packet, response, true) == + GDBRemoteCommunication::PacketResult::Success) { + if (response.IsNormalResponse()) { + error.Clear(); + if (binary_memory_read) { + // The lower level GDBRemoteCommunication packet receive layer has + // already de-quoted any + // 0x7d character escaping that was present in the packet + + size_t data_received_size = response.GetBytesLeft(); + if (data_received_size > size) { + // Don't write past the end of BUF if the remote debug server gave us + // too + // much data for some reason. + data_received_size = size; } - else if (response.IsErrorResponse()) - error.SetErrorStringWithFormat("memory read failed for 0x%" PRIx64, addr); - else if (response.IsUnsupportedResponse()) - error.SetErrorStringWithFormat("GDB server does not support reading memory"); - else - error.SetErrorStringWithFormat("unexpected response to GDB server memory read packet '%s': '%s'", packet, response.GetStringRef().c_str()); - } + memcpy(buf, response.GetStringRef().data(), data_received_size); + return data_received_size; + } else { + return response.GetHexBytes( + llvm::MutableArrayRef<uint8_t>((uint8_t *)buf, size), '\xdd'); + } + } else if (response.IsErrorResponse()) + error.SetErrorStringWithFormat("memory read failed for 0x%" PRIx64, addr); + else if (response.IsUnsupportedResponse()) + error.SetErrorStringWithFormat( + "GDB server does not support reading memory"); else - { - error.SetErrorStringWithFormat("failed to send packet: '%s'", packet); - } - return 0; + error.SetErrorStringWithFormat( + "unexpected response to GDB server memory read packet '%s': '%s'", + packet, response.GetStringRef().c_str()); + } else { + error.SetErrorStringWithFormat("failed to send packet: '%s'", packet); + } + return 0; } -size_t -ProcessGDBRemote::DoWriteMemory (addr_t addr, const void *buf, size_t size, Error &error) -{ - GetMaxMemorySize (); - if (size > m_max_memory_size) - { - // Keep memory read sizes down to a sane limit. This function will be - // called multiple times in order to complete the task by - // lldb_private::Process so it is ok to do this. - size = m_max_memory_size; - } - - StreamString packet; - packet.Printf("M%" PRIx64 ",%" PRIx64 ":", addr, (uint64_t)size); - packet.PutBytesAsRawHex8(buf, size, endian::InlHostByteOrder(), endian::InlHostByteOrder()); - StringExtractorGDBRemote response; - if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetData(), packet.GetSize(), response, true) == GDBRemoteCommunication::PacketResult::Success) - { - if (response.IsOKResponse()) - { - error.Clear(); - return size; - } - else if (response.IsErrorResponse()) - error.SetErrorStringWithFormat("memory write failed for 0x%" PRIx64, addr); - else if (response.IsUnsupportedResponse()) - error.SetErrorStringWithFormat("GDB server does not support writing memory"); - else - error.SetErrorStringWithFormat("unexpected response to GDB server memory write packet '%s': '%s'", packet.GetString().c_str(), response.GetStringRef().c_str()); - } +size_t ProcessGDBRemote::DoWriteMemory(addr_t addr, const void *buf, + size_t size, Error &error) { + GetMaxMemorySize(); + if (size > m_max_memory_size) { + // Keep memory read sizes down to a sane limit. This function will be + // called multiple times in order to complete the task by + // lldb_private::Process so it is ok to do this. + size = m_max_memory_size; + } + + StreamString packet; + packet.Printf("M%" PRIx64 ",%" PRIx64 ":", addr, (uint64_t)size); + packet.PutBytesAsRawHex8(buf, size, endian::InlHostByteOrder(), + endian::InlHostByteOrder()); + StringExtractorGDBRemote response; + if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response, + true) == + GDBRemoteCommunication::PacketResult::Success) { + if (response.IsOKResponse()) { + error.Clear(); + return size; + } else if (response.IsErrorResponse()) + error.SetErrorStringWithFormat("memory write failed for 0x%" PRIx64, + addr); + else if (response.IsUnsupportedResponse()) + error.SetErrorStringWithFormat( + "GDB server does not support writing memory"); else - { - error.SetErrorStringWithFormat("failed to send packet: '%s'", packet.GetString().c_str()); - } - return 0; + error.SetErrorStringWithFormat( + "unexpected response to GDB server memory write packet '%s': '%s'", + packet.GetData(), response.GetStringRef().c_str()); + } else { + error.SetErrorStringWithFormat("failed to send packet: '%s'", + packet.GetData()); + } + return 0; } -lldb::addr_t -ProcessGDBRemote::DoAllocateMemory (size_t size, uint32_t permissions, Error &error) -{ - Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_EXPRESSIONS)); - addr_t allocated_addr = LLDB_INVALID_ADDRESS; - - if (m_gdb_comm.SupportsAllocDeallocMemory() != eLazyBoolNo) - { - allocated_addr = m_gdb_comm.AllocateMemory (size, permissions); - if (allocated_addr != LLDB_INVALID_ADDRESS || m_gdb_comm.SupportsAllocDeallocMemory() == eLazyBoolYes) - return allocated_addr; - } - - if (m_gdb_comm.SupportsAllocDeallocMemory() == eLazyBoolNo) - { - // Call mmap() to create memory in the inferior.. - unsigned prot = 0; - if (permissions & lldb::ePermissionsReadable) - prot |= eMmapProtRead; - if (permissions & lldb::ePermissionsWritable) - prot |= eMmapProtWrite; - if (permissions & lldb::ePermissionsExecutable) - prot |= eMmapProtExec; - - if (InferiorCallMmap(this, allocated_addr, 0, size, prot, - eMmapFlagsAnon | eMmapFlagsPrivate, -1, 0)) - m_addr_to_mmap_size[allocated_addr] = size; - else - { - allocated_addr = LLDB_INVALID_ADDRESS; - if (log) - log->Printf ("ProcessGDBRemote::%s no direct stub support for memory allocation, and InferiorCallMmap also failed - is stub missing register context save/restore capability?", __FUNCTION__); - } - } - - if (allocated_addr == LLDB_INVALID_ADDRESS) - error.SetErrorStringWithFormat("unable to allocate %" PRIu64 " bytes of memory with permissions %s", (uint64_t)size, GetPermissionsAsCString (permissions)); - else - error.Clear(); - return allocated_addr; +lldb::addr_t ProcessGDBRemote::DoAllocateMemory(size_t size, + uint32_t permissions, + Error &error) { + Log *log( + GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_EXPRESSIONS)); + addr_t allocated_addr = LLDB_INVALID_ADDRESS; + + if (m_gdb_comm.SupportsAllocDeallocMemory() != eLazyBoolNo) { + allocated_addr = m_gdb_comm.AllocateMemory(size, permissions); + if (allocated_addr != LLDB_INVALID_ADDRESS || + m_gdb_comm.SupportsAllocDeallocMemory() == eLazyBoolYes) + return allocated_addr; + } + + if (m_gdb_comm.SupportsAllocDeallocMemory() == eLazyBoolNo) { + // Call mmap() to create memory in the inferior.. + unsigned prot = 0; + if (permissions & lldb::ePermissionsReadable) + prot |= eMmapProtRead; + if (permissions & lldb::ePermissionsWritable) + prot |= eMmapProtWrite; + if (permissions & lldb::ePermissionsExecutable) + prot |= eMmapProtExec; + + if (InferiorCallMmap(this, allocated_addr, 0, size, prot, + eMmapFlagsAnon | eMmapFlagsPrivate, -1, 0)) + m_addr_to_mmap_size[allocated_addr] = size; + else { + allocated_addr = LLDB_INVALID_ADDRESS; + if (log) + log->Printf("ProcessGDBRemote::%s no direct stub support for memory " + "allocation, and InferiorCallMmap also failed - is stub " + "missing register context save/restore capability?", + __FUNCTION__); + } + } + + if (allocated_addr == LLDB_INVALID_ADDRESS) + error.SetErrorStringWithFormat( + "unable to allocate %" PRIu64 " bytes of memory with permissions %s", + (uint64_t)size, GetPermissionsAsCString(permissions)); + else + error.Clear(); + return allocated_addr; } -Error -ProcessGDBRemote::GetMemoryRegionInfo (addr_t load_addr, - MemoryRegionInfo ®ion_info) -{ +Error ProcessGDBRemote::GetMemoryRegionInfo(addr_t load_addr, + MemoryRegionInfo ®ion_info) { - Error error (m_gdb_comm.GetMemoryRegionInfo (load_addr, region_info)); - return error; + Error error(m_gdb_comm.GetMemoryRegionInfo(load_addr, region_info)); + return error; } -Error -ProcessGDBRemote::GetWatchpointSupportInfo (uint32_t &num) -{ +Error ProcessGDBRemote::GetWatchpointSupportInfo(uint32_t &num) { - Error error (m_gdb_comm.GetWatchpointSupportInfo (num)); - return error; + Error error(m_gdb_comm.GetWatchpointSupportInfo(num)); + return error; } -Error -ProcessGDBRemote::GetWatchpointSupportInfo (uint32_t &num, bool& after) -{ - Error error (m_gdb_comm.GetWatchpointSupportInfo (num, after, GetTarget().GetArchitecture())); - return error; +Error ProcessGDBRemote::GetWatchpointSupportInfo(uint32_t &num, bool &after) { + Error error(m_gdb_comm.GetWatchpointSupportInfo( + num, after, GetTarget().GetArchitecture())); + return error; } -Error -ProcessGDBRemote::DoDeallocateMemory (lldb::addr_t addr) -{ - Error error; - LazyBool supported = m_gdb_comm.SupportsAllocDeallocMemory(); - - switch (supported) - { - case eLazyBoolCalculate: - // We should never be deallocating memory without allocating memory - // first so we should never get eLazyBoolCalculate - error.SetErrorString ("tried to deallocate memory without ever allocating memory"); - break; - - case eLazyBoolYes: - if (!m_gdb_comm.DeallocateMemory (addr)) - error.SetErrorStringWithFormat("unable to deallocate memory at 0x%" PRIx64, addr); - break; - - case eLazyBoolNo: - // Call munmap() to deallocate memory in the inferior.. - { - MMapMap::iterator pos = m_addr_to_mmap_size.find(addr); - if (pos != m_addr_to_mmap_size.end() && - InferiorCallMunmap(this, addr, pos->second)) - m_addr_to_mmap_size.erase (pos); - else - error.SetErrorStringWithFormat("unable to deallocate memory at 0x%" PRIx64, addr); - } - break; - } - - return error; +Error ProcessGDBRemote::DoDeallocateMemory(lldb::addr_t addr) { + Error error; + LazyBool supported = m_gdb_comm.SupportsAllocDeallocMemory(); + + switch (supported) { + case eLazyBoolCalculate: + // We should never be deallocating memory without allocating memory + // first so we should never get eLazyBoolCalculate + error.SetErrorString( + "tried to deallocate memory without ever allocating memory"); + break; + + case eLazyBoolYes: + if (!m_gdb_comm.DeallocateMemory(addr)) + error.SetErrorStringWithFormat( + "unable to deallocate memory at 0x%" PRIx64, addr); + break; + + case eLazyBoolNo: + // Call munmap() to deallocate memory in the inferior.. + { + MMapMap::iterator pos = m_addr_to_mmap_size.find(addr); + if (pos != m_addr_to_mmap_size.end() && + InferiorCallMunmap(this, addr, pos->second)) + m_addr_to_mmap_size.erase(pos); + else + error.SetErrorStringWithFormat( + "unable to deallocate memory at 0x%" PRIx64, addr); + } + break; + } + + return error; } - //------------------------------------------------------------------ // Process STDIO //------------------------------------------------------------------ -size_t -ProcessGDBRemote::PutSTDIN (const char *src, size_t src_len, Error &error) -{ - if (m_stdio_communication.IsConnected()) - { - ConnectionStatus status; - m_stdio_communication.Write(src, src_len, status, NULL); - } - else if (m_stdin_forward) - { - m_gdb_comm.SendStdinNotification(src, src_len); - } - return 0; +size_t ProcessGDBRemote::PutSTDIN(const char *src, size_t src_len, + Error &error) { + if (m_stdio_communication.IsConnected()) { + ConnectionStatus status; + m_stdio_communication.Write(src, src_len, status, NULL); + } else if (m_stdin_forward) { + m_gdb_comm.SendStdinNotification(src, src_len); + } + return 0; } -Error -ProcessGDBRemote::EnableBreakpointSite (BreakpointSite *bp_site) -{ - Error error; - assert(bp_site != NULL); - - // Get logging info - Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_BREAKPOINTS)); - user_id_t site_id = bp_site->GetID(); - - // Get the breakpoint address - const addr_t addr = bp_site->GetLoadAddress(); - - // Log that a breakpoint was requested - if (log) - log->Printf("ProcessGDBRemote::EnableBreakpointSite (size_id = %" PRIu64 ") address = 0x%" PRIx64, site_id, (uint64_t)addr); - - // Breakpoint already exists and is enabled - if (bp_site->IsEnabled()) - { - if (log) - log->Printf("ProcessGDBRemote::EnableBreakpointSite (size_id = %" PRIu64 ") address = 0x%" PRIx64 " -- SUCCESS (already enabled)", site_id, (uint64_t)addr); - return error; - } +Error ProcessGDBRemote::EnableBreakpointSite(BreakpointSite *bp_site) { + Error error; + assert(bp_site != NULL); - // Get the software breakpoint trap opcode size - const size_t bp_op_size = GetSoftwareBreakpointTrapOpcode(bp_site); + // Get logging info + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_BREAKPOINTS)); + user_id_t site_id = bp_site->GetID(); - // SupportsGDBStoppointPacket() simply checks a boolean, indicating if this breakpoint type - // is supported by the remote stub. These are set to true by default, and later set to false - // only after we receive an unimplemented response when sending a breakpoint packet. This means - // initially that unless we were specifically instructed to use a hardware breakpoint, LLDB will - // attempt to set a software breakpoint. HardwareRequired() also queries a boolean variable which - // indicates if the user specifically asked for hardware breakpoints. If true then we will - // skip over software breakpoints. - if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointSoftware) && (!bp_site->HardwareRequired())) - { - // Try to send off a software breakpoint packet ($Z0) - uint8_t error_no = m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointSoftware, true, addr, bp_op_size); - if (error_no == 0) - { - // The breakpoint was placed successfully - bp_site->SetEnabled(true); - bp_site->SetType(BreakpointSite::eExternal); - return error; - } + // Get the breakpoint address + const addr_t addr = bp_site->GetLoadAddress(); - // SendGDBStoppointTypePacket() will return an error if it was unable to set this - // breakpoint. We need to differentiate between a error specific to placing this breakpoint - // or if we have learned that this breakpoint type is unsupported. To do this, we - // must test the support boolean for this breakpoint type to see if it now indicates that - // this breakpoint type is unsupported. If they are still supported then we should return - // with the error code. If they are now unsupported, then we would like to fall through - // and try another form of breakpoint. - if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointSoftware)) - { - if (error_no != UINT8_MAX) - error.SetErrorStringWithFormat("error: %d sending the breakpoint request", errno); - else - error.SetErrorString("error sending the breakpoint request"); - return error; - } - - // We reach here when software breakpoints have been found to be unsupported. For future - // calls to set a breakpoint, we will not attempt to set a breakpoint with a type that is - // known not to be supported. - if (log) - log->Printf("Software breakpoints are unsupported"); - - // So we will fall through and try a hardware breakpoint - } - - // The process of setting a hardware breakpoint is much the same as above. We check the - // supported boolean for this breakpoint type, and if it is thought to be supported then we - // will try to set this breakpoint with a hardware breakpoint. - if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointHardware)) - { - // Try to send off a hardware breakpoint packet ($Z1) - uint8_t error_no = m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointHardware, true, addr, bp_op_size); - if (error_no == 0) - { - // The breakpoint was placed successfully - bp_site->SetEnabled(true); - bp_site->SetType(BreakpointSite::eHardware); - return error; - } - - // Check if the error was something other then an unsupported breakpoint type - if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointHardware)) - { - // Unable to set this hardware breakpoint - if (error_no != UINT8_MAX) - error.SetErrorStringWithFormat("error: %d sending the hardware breakpoint request " - "(hardware breakpoint resources might be exhausted or unavailable)", - error_no); - else - error.SetErrorString("error sending the hardware breakpoint request (hardware breakpoint resources " - "might be exhausted or unavailable)"); - return error; - } + // Log that a breakpoint was requested + if (log) + log->Printf("ProcessGDBRemote::EnableBreakpointSite (size_id = %" PRIu64 + ") address = 0x%" PRIx64, + site_id, (uint64_t)addr); - // We will reach here when the stub gives an unsupported response to a hardware breakpoint - if (log) - log->Printf("Hardware breakpoints are unsupported"); + // Breakpoint already exists and is enabled + if (bp_site->IsEnabled()) { + if (log) + log->Printf("ProcessGDBRemote::EnableBreakpointSite (size_id = %" PRIu64 + ") address = 0x%" PRIx64 " -- SUCCESS (already enabled)", + site_id, (uint64_t)addr); + return error; + } + + // Get the software breakpoint trap opcode size + const size_t bp_op_size = GetSoftwareBreakpointTrapOpcode(bp_site); + + // SupportsGDBStoppointPacket() simply checks a boolean, indicating if this + // breakpoint type + // is supported by the remote stub. These are set to true by default, and + // later set to false + // only after we receive an unimplemented response when sending a breakpoint + // packet. This means + // initially that unless we were specifically instructed to use a hardware + // breakpoint, LLDB will + // attempt to set a software breakpoint. HardwareRequired() also queries a + // boolean variable which + // indicates if the user specifically asked for hardware breakpoints. If true + // then we will + // skip over software breakpoints. + if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointSoftware) && + (!bp_site->HardwareRequired())) { + // Try to send off a software breakpoint packet ($Z0) + uint8_t error_no = m_gdb_comm.SendGDBStoppointTypePacket( + eBreakpointSoftware, true, addr, bp_op_size); + if (error_no == 0) { + // The breakpoint was placed successfully + bp_site->SetEnabled(true); + bp_site->SetType(BreakpointSite::eExternal); + return error; + } + + // SendGDBStoppointTypePacket() will return an error if it was unable to set + // this + // breakpoint. We need to differentiate between a error specific to placing + // this breakpoint + // or if we have learned that this breakpoint type is unsupported. To do + // this, we + // must test the support boolean for this breakpoint type to see if it now + // indicates that + // this breakpoint type is unsupported. If they are still supported then we + // should return + // with the error code. If they are now unsupported, then we would like to + // fall through + // and try another form of breakpoint. + if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointSoftware)) { + if (error_no != UINT8_MAX) + error.SetErrorStringWithFormat( + "error: %d sending the breakpoint request", errno); + else + error.SetErrorString("error sending the breakpoint request"); + return error; + } + + // We reach here when software breakpoints have been found to be + // unsupported. For future + // calls to set a breakpoint, we will not attempt to set a breakpoint with a + // type that is + // known not to be supported. + if (log) + log->Printf("Software breakpoints are unsupported"); + + // So we will fall through and try a hardware breakpoint + } + + // The process of setting a hardware breakpoint is much the same as above. We + // check the + // supported boolean for this breakpoint type, and if it is thought to be + // supported then we + // will try to set this breakpoint with a hardware breakpoint. + if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointHardware)) { + // Try to send off a hardware breakpoint packet ($Z1) + uint8_t error_no = m_gdb_comm.SendGDBStoppointTypePacket( + eBreakpointHardware, true, addr, bp_op_size); + if (error_no == 0) { + // The breakpoint was placed successfully + bp_site->SetEnabled(true); + bp_site->SetType(BreakpointSite::eHardware); + return error; + } + + // Check if the error was something other then an unsupported breakpoint + // type + if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointHardware)) { + // Unable to set this hardware breakpoint + if (error_no != UINT8_MAX) + error.SetErrorStringWithFormat( + "error: %d sending the hardware breakpoint request " + "(hardware breakpoint resources might be exhausted or unavailable)", + error_no); + else + error.SetErrorString("error sending the hardware breakpoint request " + "(hardware breakpoint resources " + "might be exhausted or unavailable)"); + return error; + } + + // We will reach here when the stub gives an unsupported response to a + // hardware breakpoint + if (log) + log->Printf("Hardware breakpoints are unsupported"); - // Finally we will falling through to a #trap style breakpoint - } + // Finally we will falling through to a #trap style breakpoint + } - // Don't fall through when hardware breakpoints were specifically requested - if (bp_site->HardwareRequired()) - { - error.SetErrorString("hardware breakpoints are not supported"); - return error; - } + // Don't fall through when hardware breakpoints were specifically requested + if (bp_site->HardwareRequired()) { + error.SetErrorString("hardware breakpoints are not supported"); + return error; + } - // As a last resort we want to place a manual breakpoint. An instruction - // is placed into the process memory using memory write packets. - return EnableSoftwareBreakpoint(bp_site); + // As a last resort we want to place a manual breakpoint. An instruction + // is placed into the process memory using memory write packets. + return EnableSoftwareBreakpoint(bp_site); } -Error -ProcessGDBRemote::DisableBreakpointSite (BreakpointSite *bp_site) -{ - Error error; - assert (bp_site != NULL); - addr_t addr = bp_site->GetLoadAddress(); - user_id_t site_id = bp_site->GetID(); - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_BREAKPOINTS)); - if (log) - log->Printf ("ProcessGDBRemote::DisableBreakpointSite (site_id = %" PRIu64 ") addr = 0x%8.8" PRIx64, site_id, (uint64_t)addr); - - if (bp_site->IsEnabled()) - { - const size_t bp_op_size = GetSoftwareBreakpointTrapOpcode (bp_site); +Error ProcessGDBRemote::DisableBreakpointSite(BreakpointSite *bp_site) { + Error error; + assert(bp_site != NULL); + addr_t addr = bp_site->GetLoadAddress(); + user_id_t site_id = bp_site->GetID(); + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_BREAKPOINTS)); + if (log) + log->Printf("ProcessGDBRemote::DisableBreakpointSite (site_id = %" PRIu64 + ") addr = 0x%8.8" PRIx64, + site_id, (uint64_t)addr); + + if (bp_site->IsEnabled()) { + const size_t bp_op_size = GetSoftwareBreakpointTrapOpcode(bp_site); - BreakpointSite::Type bp_type = bp_site->GetType(); - switch (bp_type) - { - case BreakpointSite::eSoftware: - error = DisableSoftwareBreakpoint (bp_site); - break; + BreakpointSite::Type bp_type = bp_site->GetType(); + switch (bp_type) { + case BreakpointSite::eSoftware: + error = DisableSoftwareBreakpoint(bp_site); + break; - case BreakpointSite::eHardware: - if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointHardware, false, addr, bp_op_size)) - error.SetErrorToGenericError(); - break; + case BreakpointSite::eHardware: + if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointHardware, false, + addr, bp_op_size)) + error.SetErrorToGenericError(); + break; - case BreakpointSite::eExternal: - { - GDBStoppointType stoppoint_type; - if (bp_site->IsHardware()) - stoppoint_type = eBreakpointHardware; - else - stoppoint_type = eBreakpointSoftware; + case BreakpointSite::eExternal: { + GDBStoppointType stoppoint_type; + if (bp_site->IsHardware()) + stoppoint_type = eBreakpointHardware; + else + stoppoint_type = eBreakpointSoftware; - if (m_gdb_comm.SendGDBStoppointTypePacket(stoppoint_type, false, addr, bp_op_size)) - error.SetErrorToGenericError(); - } - break; - } - if (error.Success()) - bp_site->SetEnabled(false); - } - else - { - if (log) - log->Printf ("ProcessGDBRemote::DisableBreakpointSite (site_id = %" PRIu64 ") addr = 0x%8.8" PRIx64 " -- SUCCESS (already disabled)", site_id, (uint64_t)addr); - return error; + if (m_gdb_comm.SendGDBStoppointTypePacket(stoppoint_type, false, addr, + bp_op_size)) + error.SetErrorToGenericError(); + } break; } - if (error.Success()) - error.SetErrorToGenericError(); + bp_site->SetEnabled(false); + } else { + if (log) + log->Printf("ProcessGDBRemote::DisableBreakpointSite (site_id = %" PRIu64 + ") addr = 0x%8.8" PRIx64 " -- SUCCESS (already disabled)", + site_id, (uint64_t)addr); return error; + } + + if (error.Success()) + error.SetErrorToGenericError(); + return error; } // Pre-requisite: wp != NULL. -static GDBStoppointType -GetGDBStoppointType (Watchpoint *wp) -{ - assert(wp); - bool watch_read = wp->WatchpointRead(); - bool watch_write = wp->WatchpointWrite(); - - // watch_read and watch_write cannot both be false. - assert(watch_read || watch_write); - if (watch_read && watch_write) - return eWatchpointReadWrite; - else if (watch_read) - return eWatchpointRead; - else // Must be watch_write, then. - return eWatchpointWrite; +static GDBStoppointType GetGDBStoppointType(Watchpoint *wp) { + assert(wp); + bool watch_read = wp->WatchpointRead(); + bool watch_write = wp->WatchpointWrite(); + + // watch_read and watch_write cannot both be false. + assert(watch_read || watch_write); + if (watch_read && watch_write) + return eWatchpointReadWrite; + else if (watch_read) + return eWatchpointRead; + else // Must be watch_write, then. + return eWatchpointWrite; } -Error -ProcessGDBRemote::EnableWatchpoint (Watchpoint *wp, bool notify) -{ - Error error; - if (wp) - { - user_id_t watchID = wp->GetID(); - addr_t addr = wp->GetLoadAddress(); - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_WATCHPOINTS)); - if (log) - log->Printf ("ProcessGDBRemote::EnableWatchpoint(watchID = %" PRIu64 ")", watchID); - if (wp->IsEnabled()) - { - if (log) - log->Printf("ProcessGDBRemote::EnableWatchpoint(watchID = %" PRIu64 ") addr = 0x%8.8" PRIx64 ": watchpoint already enabled.", watchID, (uint64_t)addr); - return error; - } - - GDBStoppointType type = GetGDBStoppointType(wp); - // Pass down an appropriate z/Z packet... - if (m_gdb_comm.SupportsGDBStoppointPacket (type)) - { - if (m_gdb_comm.SendGDBStoppointTypePacket(type, true, addr, wp->GetByteSize()) == 0) - { - wp->SetEnabled(true, notify); - return error; - } - else - error.SetErrorString("sending gdb watchpoint packet failed"); - } - else - error.SetErrorString("watchpoints not supported"); - } - else - { - error.SetErrorString("Watchpoint argument was NULL."); - } - if (error.Success()) - error.SetErrorToGenericError(); - return error; +Error ProcessGDBRemote::EnableWatchpoint(Watchpoint *wp, bool notify) { + Error error; + if (wp) { + user_id_t watchID = wp->GetID(); + addr_t addr = wp->GetLoadAddress(); + Log *log( + ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_WATCHPOINTS)); + if (log) + log->Printf("ProcessGDBRemote::EnableWatchpoint(watchID = %" PRIu64 ")", + watchID); + if (wp->IsEnabled()) { + if (log) + log->Printf("ProcessGDBRemote::EnableWatchpoint(watchID = %" PRIu64 + ") addr = 0x%8.8" PRIx64 ": watchpoint already enabled.", + watchID, (uint64_t)addr); + return error; + } + + GDBStoppointType type = GetGDBStoppointType(wp); + // Pass down an appropriate z/Z packet... + if (m_gdb_comm.SupportsGDBStoppointPacket(type)) { + if (m_gdb_comm.SendGDBStoppointTypePacket(type, true, addr, + wp->GetByteSize()) == 0) { + wp->SetEnabled(true, notify); + return error; + } else + error.SetErrorString("sending gdb watchpoint packet failed"); + } else + error.SetErrorString("watchpoints not supported"); + } else { + error.SetErrorString("Watchpoint argument was NULL."); + } + if (error.Success()) + error.SetErrorToGenericError(); + return error; } -Error -ProcessGDBRemote::DisableWatchpoint (Watchpoint *wp, bool notify) -{ - Error error; - if (wp) - { - user_id_t watchID = wp->GetID(); - - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_WATCHPOINTS)); +Error ProcessGDBRemote::DisableWatchpoint(Watchpoint *wp, bool notify) { + Error error; + if (wp) { + user_id_t watchID = wp->GetID(); - addr_t addr = wp->GetLoadAddress(); + Log *log( + ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_WATCHPOINTS)); - if (log) - log->Printf ("ProcessGDBRemote::DisableWatchpoint (watchID = %" PRIu64 ") addr = 0x%8.8" PRIx64, watchID, (uint64_t)addr); - - if (!wp->IsEnabled()) - { - if (log) - log->Printf ("ProcessGDBRemote::DisableWatchpoint (watchID = %" PRIu64 ") addr = 0x%8.8" PRIx64 " -- SUCCESS (already disabled)", watchID, (uint64_t)addr); - // See also 'class WatchpointSentry' within StopInfo.cpp. - // This disabling attempt might come from the user-supplied actions, we'll route it in order for - // the watchpoint object to intelligently process this action. - wp->SetEnabled(false, notify); - return error; - } + addr_t addr = wp->GetLoadAddress(); - if (wp->IsHardware()) - { - GDBStoppointType type = GetGDBStoppointType(wp); - // Pass down an appropriate z/Z packet... - if (m_gdb_comm.SendGDBStoppointTypePacket(type, false, addr, wp->GetByteSize()) == 0) - { - wp->SetEnabled(false, notify); - return error; - } - else - error.SetErrorString("sending gdb watchpoint packet failed"); - } - // TODO: clear software watchpoints if we implement them - } - else - { - error.SetErrorString("Watchpoint argument was NULL."); - } - if (error.Success()) - error.SetErrorToGenericError(); - return error; + if (log) + log->Printf("ProcessGDBRemote::DisableWatchpoint (watchID = %" PRIu64 + ") addr = 0x%8.8" PRIx64, + watchID, (uint64_t)addr); + + if (!wp->IsEnabled()) { + if (log) + log->Printf("ProcessGDBRemote::DisableWatchpoint (watchID = %" PRIu64 + ") addr = 0x%8.8" PRIx64 " -- SUCCESS (already disabled)", + watchID, (uint64_t)addr); + // See also 'class WatchpointSentry' within StopInfo.cpp. + // This disabling attempt might come from the user-supplied actions, we'll + // route it in order for + // the watchpoint object to intelligently process this action. + wp->SetEnabled(false, notify); + return error; + } + + if (wp->IsHardware()) { + GDBStoppointType type = GetGDBStoppointType(wp); + // Pass down an appropriate z/Z packet... + if (m_gdb_comm.SendGDBStoppointTypePacket(type, false, addr, + wp->GetByteSize()) == 0) { + wp->SetEnabled(false, notify); + return error; + } else + error.SetErrorString("sending gdb watchpoint packet failed"); + } + // TODO: clear software watchpoints if we implement them + } else { + error.SetErrorString("Watchpoint argument was NULL."); + } + if (error.Success()) + error.SetErrorToGenericError(); + return error; } -void -ProcessGDBRemote::Clear() -{ - m_flags = 0; - m_thread_list_real.Clear(); - m_thread_list.Clear(); +void ProcessGDBRemote::Clear() { + m_flags = 0; + m_thread_list_real.Clear(); + m_thread_list.Clear(); } -Error -ProcessGDBRemote::DoSignal (int signo) -{ - Error error; - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); - if (log) - log->Printf ("ProcessGDBRemote::DoSignal (signal = %d)", signo); +Error ProcessGDBRemote::DoSignal(int signo) { + Error error; + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + if (log) + log->Printf("ProcessGDBRemote::DoSignal (signal = %d)", signo); - if (!m_gdb_comm.SendAsyncSignal (signo)) - error.SetErrorStringWithFormat("failed to send signal %i", signo); - return error; + if (!m_gdb_comm.SendAsyncSignal(signo)) + error.SetErrorStringWithFormat("failed to send signal %i", signo); + return error; } -Error -ProcessGDBRemote::EstablishConnectionIfNeeded (const ProcessInfo &process_info) -{ - // Make sure we aren't already connected? - if (m_gdb_comm.IsConnected()) - return Error(); - - PlatformSP platform_sp (GetTarget ().GetPlatform ()); - if (platform_sp && !platform_sp->IsHost ()) - return Error("Lost debug server connection"); +Error ProcessGDBRemote::EstablishConnectionIfNeeded( + const ProcessInfo &process_info) { + // Make sure we aren't already connected? + if (m_gdb_comm.IsConnected()) + return Error(); - auto error = LaunchAndConnectToDebugserver (process_info); - if (error.Fail()) - { - const char *error_string = error.AsCString(); - if (error_string == nullptr) - error_string = "unable to launch " DEBUGSERVER_BASENAME; - } - return error; + PlatformSP platform_sp(GetTarget().GetPlatform()); + if (platform_sp && !platform_sp->IsHost()) + return Error("Lost debug server connection"); + + auto error = LaunchAndConnectToDebugserver(process_info); + if (error.Fail()) { + const char *error_string = error.AsCString(); + if (error_string == nullptr) + error_string = "unable to launch " DEBUGSERVER_BASENAME; + } + return error; } +#if defined(__APPLE__) +#define USE_SOCKETPAIR_FOR_LOCAL_CONNECTION 1 +#endif -Error -ProcessGDBRemote::LaunchAndConnectToDebugserver (const ProcessInfo &process_info) -{ - using namespace std::placeholders; // For _1, _2, etc. - - Error error; - if (m_debugserver_pid == LLDB_INVALID_PROCESS_ID) - { - // If we locate debugserver, keep that located version around - static FileSpec g_debugserver_file_spec; - - ProcessLaunchInfo debugserver_launch_info; - // Make debugserver run in its own session so signals generated by - // special terminal key sequences (^C) don't affect debugserver. - debugserver_launch_info.SetLaunchInSeparateProcessGroup(true); - - const std::weak_ptr<ProcessGDBRemote> this_wp = std::static_pointer_cast<ProcessGDBRemote>(shared_from_this()); - debugserver_launch_info.SetMonitorProcessCallback(std::bind(MonitorDebugserverProcess, this_wp, _1, _2, _3, _4), - false); - debugserver_launch_info.SetUserID(process_info.GetUserID()); - -#if defined (__APPLE__) && (defined (__arm__) || defined (__arm64__) || defined (__aarch64__)) - // On iOS, still do a local connection using a random port - const char *hostname = "127.0.0.1"; - uint16_t port = get_random_port (); +#ifdef USE_SOCKETPAIR_FOR_LOCAL_CONNECTION +static bool SetCloexecFlag(int fd) { +#if defined(FD_CLOEXEC) + int flags = ::fcntl(fd, F_GETFD); + if (flags == -1) + return false; + return (::fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == 0); #else - // Set hostname being NULL to do the reverse connect where debugserver - // will bind to port zero and it will communicate back to us the port - // that we will connect to - const char *hostname = nullptr; - uint16_t port = 0; + return false; +#endif +} #endif - StreamString url_str; - const char* url = nullptr; - if (hostname != nullptr) - { - url_str.Printf("%s:%u", hostname, port); - url = url_str.GetData(); - } +Error ProcessGDBRemote::LaunchAndConnectToDebugserver( + const ProcessInfo &process_info) { + using namespace std::placeholders; // For _1, _2, etc. + + Error error; + if (m_debugserver_pid == LLDB_INVALID_PROCESS_ID) { + // If we locate debugserver, keep that located version around + static FileSpec g_debugserver_file_spec; + + ProcessLaunchInfo debugserver_launch_info; + // Make debugserver run in its own session so signals generated by + // special terminal key sequences (^C) don't affect debugserver. + debugserver_launch_info.SetLaunchInSeparateProcessGroup(true); + + const std::weak_ptr<ProcessGDBRemote> this_wp = + std::static_pointer_cast<ProcessGDBRemote>(shared_from_this()); + debugserver_launch_info.SetMonitorProcessCallback( + std::bind(MonitorDebugserverProcess, this_wp, _1, _2, _3, _4), false); + debugserver_launch_info.SetUserID(process_info.GetUserID()); + + int communication_fd = -1; +#ifdef USE_SOCKETPAIR_FOR_LOCAL_CONNECTION + // Auto close the sockets we might open up unless everything goes OK. This + // helps us not leak file descriptors when things go wrong. + lldb_utility::CleanUp<int, int> our_socket(-1, -1, close); + lldb_utility::CleanUp<int, int> gdb_socket(-1, -1, close); + + // Use a socketpair on Apple for now until other platforms can verify it + // works and is fast enough + { + int sockets[2]; /* the pair of socket descriptors */ + if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) == -1) { + error.SetErrorToErrno(); + return error; + } - error = m_gdb_comm.StartDebugserverProcess (url, - GetTarget().GetPlatform().get(), - debugserver_launch_info, - &port); + our_socket.set(sockets[0]); + gdb_socket.set(sockets[1]); + } - if (error.Success ()) - m_debugserver_pid = debugserver_launch_info.GetProcessID(); - else - m_debugserver_pid = LLDB_INVALID_PROCESS_ID; + // Don't let any child processes inherit our communication socket + SetCloexecFlag(our_socket.get()); + communication_fd = gdb_socket.get(); +#endif - if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID) - StartAsyncThread (); + error = m_gdb_comm.StartDebugserverProcess( + nullptr, GetTarget().GetPlatform().get(), debugserver_launch_info, + nullptr, nullptr, communication_fd); - if (error.Fail()) - { - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); + if (error.Success()) + m_debugserver_pid = debugserver_launch_info.GetProcessID(); + else + m_debugserver_pid = LLDB_INVALID_PROCESS_ID; + + if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID) { +#ifdef USE_SOCKETPAIR_FOR_LOCAL_CONNECTION + // Our process spawned correctly, we can now set our connection to use our + // end of the socket pair + m_gdb_comm.SetConnection( + new ConnectionFileDescriptor(our_socket.release(), true)); +#endif + StartAsyncThread(); + } - if (log) - log->Printf("failed to start debugserver process: %s", error.AsCString()); - return error; - } + if (error.Fail()) { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); - if (m_gdb_comm.IsConnected()) - { - // Finish the connection process by doing the handshake without connecting (send NULL URL) - ConnectToDebugserver (NULL); - } - else - { - StreamString connect_url; - connect_url.Printf("connect://%s:%u", hostname, port); - error = ConnectToDebugserver (connect_url.GetString().c_str()); - } + if (log) + log->Printf("failed to start debugserver process: %s", + error.AsCString()); + return error; + } + if (m_gdb_comm.IsConnected()) { + // Finish the connection process by doing the handshake without connecting + // (send NULL URL) + ConnectToDebugserver(""); + } else { + error.SetErrorString("connection failed"); } - return error; + } + return error; } -bool -ProcessGDBRemote::MonitorDebugserverProcess(std::weak_ptr<ProcessGDBRemote> process_wp, lldb::pid_t debugserver_pid, - bool exited, // True if the process did exit - int signo, // Zero for no signal - int exit_status // Exit value of process if signal is zero - ) -{ - // "debugserver_pid" argument passed in is the process ID for - // debugserver that we are tracking... - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); - const bool handled = true; - - if (log) - log->Printf("ProcessGDBRemote::%s(process_wp, pid=%" PRIu64 ", signo=%i (0x%x), exit_status=%i)", __FUNCTION__, - debugserver_pid, signo, signo, exit_status); - - std::shared_ptr<ProcessGDBRemote> process_sp = process_wp.lock(); - if (log) - log->Printf("ProcessGDBRemote::%s(process = %p)", __FUNCTION__, static_cast<void *>(process_sp.get())); - if (!process_sp || process_sp->m_debugserver_pid != debugserver_pid) - return handled; - - // Sleep for a half a second to make sure our inferior process has - // time to set its exit status before we set it incorrectly when - // both the debugserver and the inferior process shut down. - usleep(500000); - // If our process hasn't yet exited, debugserver might have died. - // If the process did exit, then we are reaping it. - const StateType state = process_sp->GetState(); - - if (state != eStateInvalid && state != eStateUnloaded && state != eStateExited && state != eStateDetached) - { - char error_str[1024]; - if (signo) - { - const char *signal_cstr = process_sp->GetUnixSignals()->GetSignalAsCString(signo); - if (signal_cstr) - ::snprintf(error_str, sizeof(error_str), DEBUGSERVER_BASENAME " died with signal %s", signal_cstr); - else - ::snprintf(error_str, sizeof(error_str), DEBUGSERVER_BASENAME " died with signal %i", signo); - } - else - { - ::snprintf(error_str, sizeof(error_str), DEBUGSERVER_BASENAME " died with an exit status of 0x%8.8x", - exit_status); - } +bool ProcessGDBRemote::MonitorDebugserverProcess( + std::weak_ptr<ProcessGDBRemote> process_wp, lldb::pid_t debugserver_pid, + bool exited, // True if the process did exit + int signo, // Zero for no signal + int exit_status // Exit value of process if signal is zero + ) { + // "debugserver_pid" argument passed in is the process ID for + // debugserver that we are tracking... + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + const bool handled = true; + + if (log) + log->Printf("ProcessGDBRemote::%s(process_wp, pid=%" PRIu64 + ", signo=%i (0x%x), exit_status=%i)", + __FUNCTION__, debugserver_pid, signo, signo, exit_status); + + std::shared_ptr<ProcessGDBRemote> process_sp = process_wp.lock(); + if (log) + log->Printf("ProcessGDBRemote::%s(process = %p)", __FUNCTION__, + static_cast<void *>(process_sp.get())); + if (!process_sp || process_sp->m_debugserver_pid != debugserver_pid) + return handled; - process_sp->SetExitStatus(-1, error_str); + // Sleep for a half a second to make sure our inferior process has + // time to set its exit status before we set it incorrectly when + // both the debugserver and the inferior process shut down. + usleep(500000); + // If our process hasn't yet exited, debugserver might have died. + // If the process did exit, then we are reaping it. + const StateType state = process_sp->GetState(); + + if (state != eStateInvalid && state != eStateUnloaded && + state != eStateExited && state != eStateDetached) { + char error_str[1024]; + if (signo) { + const char *signal_cstr = + process_sp->GetUnixSignals()->GetSignalAsCString(signo); + if (signal_cstr) + ::snprintf(error_str, sizeof(error_str), + DEBUGSERVER_BASENAME " died with signal %s", signal_cstr); + else + ::snprintf(error_str, sizeof(error_str), + DEBUGSERVER_BASENAME " died with signal %i", signo); + } else { + ::snprintf(error_str, sizeof(error_str), + DEBUGSERVER_BASENAME " died with an exit status of 0x%8.8x", + exit_status); } - // Debugserver has exited we need to let our ProcessGDBRemote - // know that it no longer has a debugserver instance - process_sp->m_debugserver_pid = LLDB_INVALID_PROCESS_ID; - return handled; + + process_sp->SetExitStatus(-1, error_str); + } + // Debugserver has exited we need to let our ProcessGDBRemote + // know that it no longer has a debugserver instance + process_sp->m_debugserver_pid = LLDB_INVALID_PROCESS_ID; + return handled; } -void -ProcessGDBRemote::KillDebugserverProcess () -{ - m_gdb_comm.Disconnect(); - if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID) - { - Host::Kill (m_debugserver_pid, SIGINT); - m_debugserver_pid = LLDB_INVALID_PROCESS_ID; - } +void ProcessGDBRemote::KillDebugserverProcess() { + m_gdb_comm.Disconnect(); + if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID) { + Host::Kill(m_debugserver_pid, SIGINT); + m_debugserver_pid = LLDB_INVALID_PROCESS_ID; + } } -void -ProcessGDBRemote::Initialize() -{ - static std::once_flag g_once_flag; +void ProcessGDBRemote::Initialize() { + static std::once_flag g_once_flag; - std::call_once(g_once_flag, []() - { - PluginManager::RegisterPlugin (GetPluginNameStatic(), - GetPluginDescriptionStatic(), - CreateInstance, - DebuggerInitialize); - }); + std::call_once(g_once_flag, []() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance, + DebuggerInitialize); + }); } -void -ProcessGDBRemote::DebuggerInitialize (Debugger &debugger) -{ - if (!PluginManager::GetSettingForProcessPlugin(debugger, PluginProperties::GetSettingName())) - { - const bool is_global_setting = true; - PluginManager::CreateSettingForProcessPlugin (debugger, - GetGlobalPluginProperties()->GetValueProperties(), - ConstString ("Properties for the gdb-remote process plug-in."), - is_global_setting); - } +void ProcessGDBRemote::DebuggerInitialize(Debugger &debugger) { + if (!PluginManager::GetSettingForProcessPlugin( + debugger, PluginProperties::GetSettingName())) { + const bool is_global_setting = true; + PluginManager::CreateSettingForProcessPlugin( + debugger, GetGlobalPluginProperties()->GetValueProperties(), + ConstString("Properties for the gdb-remote process plug-in."), + is_global_setting); + } } -bool -ProcessGDBRemote::StartAsyncThread () -{ - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); +bool ProcessGDBRemote::StartAsyncThread() { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); - if (log) - log->Printf ("ProcessGDBRemote::%s ()", __FUNCTION__); + if (log) + log->Printf("ProcessGDBRemote::%s ()", __FUNCTION__); - std::lock_guard<std::recursive_mutex> guard(m_async_thread_state_mutex); - if (!m_async_thread.IsJoinable()) - { - // Create a thread that watches our internal state and controls which - // events make it to clients (into the DCProcess event queue). + std::lock_guard<std::recursive_mutex> guard(m_async_thread_state_mutex); + if (!m_async_thread.IsJoinable()) { + // Create a thread that watches our internal state and controls which + // events make it to clients (into the DCProcess event queue). - m_async_thread = ThreadLauncher::LaunchThread("<lldb.process.gdb-remote.async>", ProcessGDBRemote::AsyncThread, this, NULL); - } - else if (log) - log->Printf("ProcessGDBRemote::%s () - Called when Async thread was already running.", __FUNCTION__); + m_async_thread = + ThreadLauncher::LaunchThread("<lldb.process.gdb-remote.async>", + ProcessGDBRemote::AsyncThread, this, NULL); + } else if (log) + log->Printf("ProcessGDBRemote::%s () - Called when Async thread was " + "already running.", + __FUNCTION__); - return m_async_thread.IsJoinable(); + return m_async_thread.IsJoinable(); } -void -ProcessGDBRemote::StopAsyncThread () -{ - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); +void ProcessGDBRemote::StopAsyncThread() { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); - if (log) - log->Printf ("ProcessGDBRemote::%s ()", __FUNCTION__); + if (log) + log->Printf("ProcessGDBRemote::%s ()", __FUNCTION__); - std::lock_guard<std::recursive_mutex> guard(m_async_thread_state_mutex); - if (m_async_thread.IsJoinable()) - { - m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncThreadShouldExit); + std::lock_guard<std::recursive_mutex> guard(m_async_thread_state_mutex); + if (m_async_thread.IsJoinable()) { + m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncThreadShouldExit); - // This will shut down the async thread. - m_gdb_comm.Disconnect(); // Disconnect from the debug server. + // This will shut down the async thread. + m_gdb_comm.Disconnect(); // Disconnect from the debug server. - // Stop the stdio thread - m_async_thread.Join(nullptr); - m_async_thread.Reset(); - } - else if (log) - log->Printf("ProcessGDBRemote::%s () - Called when Async thread was not running.", __FUNCTION__); + // Stop the stdio thread + m_async_thread.Join(nullptr); + m_async_thread.Reset(); + } else if (log) + log->Printf( + "ProcessGDBRemote::%s () - Called when Async thread was not running.", + __FUNCTION__); } -bool -ProcessGDBRemote::HandleNotifyPacket (StringExtractorGDBRemote &packet) -{ - // get the packet at a string - const std::string &pkt = packet.GetStringRef(); - // skip %stop: - StringExtractorGDBRemote stop_info(pkt.c_str() + 5); - - // pass as a thread stop info packet - SetLastStopPacket(stop_info); - - // check for more stop reasons - HandleStopReplySequence(); - - // if the process is stopped then we need to fake a resume - // so that we can stop properly with the new break. This - // is possible due to SetPrivateState() broadcasting the - // state change as a side effect. - if (GetPrivateState() == lldb::StateType::eStateStopped) - { - SetPrivateState(lldb::StateType::eStateRunning); - } +bool ProcessGDBRemote::HandleNotifyPacket(StringExtractorGDBRemote &packet) { + // get the packet at a string + const std::string &pkt = packet.GetStringRef(); + // skip %stop: + StringExtractorGDBRemote stop_info(pkt.c_str() + 5); - // since we have some stopped packets we can halt the process - SetPrivateState(lldb::StateType::eStateStopped); + // pass as a thread stop info packet + SetLastStopPacket(stop_info); - return true; + // check for more stop reasons + HandleStopReplySequence(); + + // if the process is stopped then we need to fake a resume + // so that we can stop properly with the new break. This + // is possible due to SetPrivateState() broadcasting the + // state change as a side effect. + if (GetPrivateState() == lldb::StateType::eStateStopped) { + SetPrivateState(lldb::StateType::eStateRunning); + } + + // since we have some stopped packets we can halt the process + SetPrivateState(lldb::StateType::eStateStopped); + + return true; } -thread_result_t -ProcessGDBRemote::AsyncThread (void *arg) -{ - ProcessGDBRemote *process = (ProcessGDBRemote*) arg; +thread_result_t ProcessGDBRemote::AsyncThread(void *arg) { + ProcessGDBRemote *process = (ProcessGDBRemote *)arg; - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); - if (log) - log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") thread starting...", __FUNCTION__, arg, process->GetID()); + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + if (log) + log->Printf("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 + ") thread starting...", + __FUNCTION__, arg, process->GetID()); - EventSP event_sp; - bool done = false; - while (!done) - { + EventSP event_sp; + bool done = false; + while (!done) { + if (log) + log->Printf("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 + ") listener.WaitForEvent (NULL, event_sp)...", + __FUNCTION__, arg, process->GetID()); + if (process->m_async_listener_sp->GetEvent(event_sp, llvm::None)) { + const uint32_t event_type = event_sp->GetType(); + if (event_sp->BroadcasterIs(&process->m_async_broadcaster)) { if (log) - log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") listener.WaitForEvent (NULL, event_sp)...", __FUNCTION__, arg, process->GetID()); - if (process->m_async_listener_sp->WaitForEvent (NULL, event_sp)) - { - const uint32_t event_type = event_sp->GetType(); - if (event_sp->BroadcasterIs (&process->m_async_broadcaster)) - { - if (log) - log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") Got an event of type: %d...", __FUNCTION__, arg, process->GetID(), event_type); - - switch (event_type) - { - case eBroadcastBitAsyncContinue: - { - const EventDataBytes *continue_packet = EventDataBytes::GetEventDataFromEvent(event_sp.get()); - - if (continue_packet) - { - const char *continue_cstr = (const char *)continue_packet->GetBytes (); - const size_t continue_cstr_len = continue_packet->GetByteSize (); - if (log) - log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") got eBroadcastBitAsyncContinue: %s", __FUNCTION__, arg, process->GetID(), continue_cstr); - - if (::strstr (continue_cstr, "vAttach") == NULL) - process->SetPrivateState(eStateRunning); - StringExtractorGDBRemote response; - - // If in Non-Stop-Mode - if (process->GetTarget().GetNonStopModeEnabled()) - { - // send the vCont packet - if (!process->GetGDBRemote().SendvContPacket(process, continue_cstr, continue_cstr_len, response)) - { - // Something went wrong - done = true; - break; - } - } - // If in All-Stop-Mode - else - { - StateType stop_state = process->GetGDBRemote().SendContinuePacketAndWaitForResponse (process, continue_cstr, continue_cstr_len, response); - - // We need to immediately clear the thread ID list so we are sure to get a valid list of threads. - // The thread ID list might be contained within the "response", or the stop reply packet that - // caused the stop. So clear it now before we give the stop reply packet to the process - // using the process->SetLastStopPacket()... - process->ClearThreadIDList (); - - switch (stop_state) - { - case eStateStopped: - case eStateCrashed: - case eStateSuspended: - process->SetLastStopPacket (response); - process->SetPrivateState (stop_state); - break; - - case eStateExited: - { - process->SetLastStopPacket (response); - process->ClearThreadIDList(); - response.SetFilePos(1); - - int exit_status = response.GetHexU8(); - const char *desc_cstr = NULL; - StringExtractor extractor; - std::string desc_string; - if (response.GetBytesLeft() > 0 && response.GetChar('-') == ';') - { - std::string desc_token; - while (response.GetNameColonValue (desc_token, desc_string)) - { - if (desc_token == "description") - { - extractor.GetStringRef().swap(desc_string); - extractor.SetFilePos(0); - extractor.GetHexByteString (desc_string); - desc_cstr = desc_string.c_str(); - } - } - } - process->SetExitStatus(exit_status, desc_cstr); - done = true; - break; - } - case eStateInvalid: - { - // Check to see if we were trying to attach and if we got back - // the "E87" error code from debugserver -- this indicates that - // the process is not debuggable. Return a slightly more helpful - // error message about why the attach failed. - if (::strstr (continue_cstr, "vAttach") != NULL - && response.GetError() == 0x87) - { - process->SetExitStatus(-1, "cannot attach to process due to System Integrity Protection"); - } - // E01 code from vAttach means that the attach failed - if (::strstr (continue_cstr, "vAttach") != NULL - && response.GetError() == 0x1) - { - process->SetExitStatus(-1, "unable to attach"); - } - else - { - process->SetExitStatus(-1, "lost connection"); - } - break; - } - - default: - process->SetPrivateState (stop_state); - break; - } // switch(stop_state) - } // else // if in All-stop-mode - } // if (continue_packet) - } // case eBroadcastBitAysncContinue - break; - - case eBroadcastBitAsyncThreadShouldExit: - if (log) - log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") got eBroadcastBitAsyncThreadShouldExit...", __FUNCTION__, arg, process->GetID()); - done = true; - break; - - default: - if (log) - log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") got unknown event 0x%8.8x", __FUNCTION__, arg, process->GetID(), event_type); - done = true; - break; - } + log->Printf("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 + ") Got an event of type: %d...", + __FUNCTION__, arg, process->GetID(), event_type); + + switch (event_type) { + case eBroadcastBitAsyncContinue: { + const EventDataBytes *continue_packet = + EventDataBytes::GetEventDataFromEvent(event_sp.get()); + + if (continue_packet) { + const char *continue_cstr = + (const char *)continue_packet->GetBytes(); + const size_t continue_cstr_len = continue_packet->GetByteSize(); + if (log) + log->Printf("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 + ") got eBroadcastBitAsyncContinue: %s", + __FUNCTION__, arg, process->GetID(), continue_cstr); + + if (::strstr(continue_cstr, "vAttach") == NULL) + process->SetPrivateState(eStateRunning); + StringExtractorGDBRemote response; + + // If in Non-Stop-Mode + if (process->GetTarget().GetNonStopModeEnabled()) { + // send the vCont packet + if (!process->GetGDBRemote().SendvContPacket( + llvm::StringRef(continue_cstr, continue_cstr_len), + response)) { + // Something went wrong + done = true; + break; + } } - else if (event_sp->BroadcasterIs (&process->m_gdb_comm)) - { - switch (event_type) - { - case Communication::eBroadcastBitReadThreadDidExit: - process->SetExitStatus (-1, "lost connection"); - done = true; - break; - - case GDBRemoteCommunication::eBroadcastBitGdbReadThreadGotNotify: - { - lldb_private::Event *event = event_sp.get(); - const EventDataBytes *continue_packet = EventDataBytes::GetEventDataFromEvent(event); - StringExtractorGDBRemote notify((const char*)continue_packet->GetBytes()); - // Hand this over to the process to handle - process->HandleNotifyPacket(notify); - break; - } - - default: - if (log) - log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") got unknown event 0x%8.8x", __FUNCTION__, arg, process->GetID(), event_type); - done = true; - break; + // If in All-Stop-Mode + else { + StateType stop_state = + process->GetGDBRemote().SendContinuePacketAndWaitForResponse( + *process, *process->GetUnixSignals(), + llvm::StringRef(continue_cstr, continue_cstr_len), + response); + + // We need to immediately clear the thread ID list so we are sure + // to get a valid list of threads. + // The thread ID list might be contained within the "response", or + // the stop reply packet that + // caused the stop. So clear it now before we give the stop reply + // packet to the process + // using the process->SetLastStopPacket()... + process->ClearThreadIDList(); + + switch (stop_state) { + case eStateStopped: + case eStateCrashed: + case eStateSuspended: + process->SetLastStopPacket(response); + process->SetPrivateState(stop_state); + break; + + case eStateExited: { + process->SetLastStopPacket(response); + process->ClearThreadIDList(); + response.SetFilePos(1); + + int exit_status = response.GetHexU8(); + std::string desc_string; + if (response.GetBytesLeft() > 0 && + response.GetChar('-') == ';') { + llvm::StringRef desc_str; + llvm::StringRef desc_token; + while (response.GetNameColonValue(desc_token, desc_str)) { + if (desc_token != "description") + continue; + StringExtractor extractor(desc_str); + extractor.GetHexByteString(desc_string); + } } - } + process->SetExitStatus(exit_status, desc_string.c_str()); + done = true; + break; + } + case eStateInvalid: { + // Check to see if we were trying to attach and if we got back + // the "E87" error code from debugserver -- this indicates that + // the process is not debuggable. Return a slightly more + // helpful + // error message about why the attach failed. + if (::strstr(continue_cstr, "vAttach") != NULL && + response.GetError() == 0x87) { + process->SetExitStatus(-1, "cannot attach to process due to " + "System Integrity Protection"); + } + // E01 code from vAttach means that the attach failed + if (::strstr(continue_cstr, "vAttach") != NULL && + response.GetError() == 0x1) { + process->SetExitStatus(-1, "unable to attach"); + } else { + process->SetExitStatus(-1, "lost connection"); + } + break; + } + + default: + process->SetPrivateState(stop_state); + break; + } // switch(stop_state) + } // else // if in All-stop-mode + } // if (continue_packet) + } // case eBroadcastBitAysncContinue + break; + + case eBroadcastBitAsyncThreadShouldExit: + if (log) + log->Printf("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 + ") got eBroadcastBitAsyncThreadShouldExit...", + __FUNCTION__, arg, process->GetID()); + done = true; + break; + + default: + if (log) + log->Printf("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 + ") got unknown event 0x%8.8x", + __FUNCTION__, arg, process->GetID(), event_type); + done = true; + break; } - else - { - if (log) - log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") listener.WaitForEvent (NULL, event_sp) => false", __FUNCTION__, arg, process->GetID()); - done = true; + } else if (event_sp->BroadcasterIs(&process->m_gdb_comm)) { + switch (event_type) { + case Communication::eBroadcastBitReadThreadDidExit: + process->SetExitStatus(-1, "lost connection"); + done = true; + break; + + case GDBRemoteCommunication::eBroadcastBitGdbReadThreadGotNotify: { + lldb_private::Event *event = event_sp.get(); + const EventDataBytes *continue_packet = + EventDataBytes::GetEventDataFromEvent(event); + StringExtractorGDBRemote notify( + (const char *)continue_packet->GetBytes()); + // Hand this over to the process to handle + process->HandleNotifyPacket(notify); + break; + } + + default: + if (log) + log->Printf("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 + ") got unknown event 0x%8.8x", + __FUNCTION__, arg, process->GetID(), event_type); + done = true; + break; } + } + } else { + if (log) + log->Printf("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 + ") listener.WaitForEvent (NULL, event_sp) => false", + __FUNCTION__, arg, process->GetID()); + done = true; } + } - if (log) - log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") thread exiting...", __FUNCTION__, arg, process->GetID()); + if (log) + log->Printf("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 + ") thread exiting...", + __FUNCTION__, arg, process->GetID()); - return NULL; + return NULL; } -//uint32_t -//ProcessGDBRemote::ListProcessesMatchingName (const char *name, StringList &matches, std::vector<lldb::pid_t> &pids) +// uint32_t +// ProcessGDBRemote::ListProcessesMatchingName (const char *name, StringList +// &matches, std::vector<lldb::pid_t> &pids) //{ -// // If we are planning to launch the debugserver remotely, then we need to fire up a debugserver -// // process and ask it for the list of processes. But if we are local, we can let the Host do it. +// // If we are planning to launch the debugserver remotely, then we need to +// fire up a debugserver +// // process and ask it for the list of processes. But if we are local, we +// can let the Host do it. // if (m_local_debugserver) // { // return Host::ListProcessesMatchingName (name, matches, pids); @@ -4070,189 +3729,240 @@ ProcessGDBRemote::AsyncThread (void *arg) // //} // -bool -ProcessGDBRemote::NewThreadNotifyBreakpointHit (void *baton, - StoppointCallbackContext *context, - lldb::user_id_t break_id, - lldb::user_id_t break_loc_id) -{ - // I don't think I have to do anything here, just make sure I notice the new thread when it starts to - // run so I can stop it if that's what I want to do. - Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - if (log) - log->Printf("Hit New Thread Notification breakpoint."); - return false; +bool ProcessGDBRemote::NewThreadNotifyBreakpointHit( + void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id, + lldb::user_id_t break_loc_id) { + // I don't think I have to do anything here, just make sure I notice the new + // thread when it starts to + // run so I can stop it if that's what I want to do. + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + if (log) + log->Printf("Hit New Thread Notification breakpoint."); + return false; } - -bool -ProcessGDBRemote::StartNoticingNewThreads() -{ - Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - if (m_thread_create_bp_sp) - { +bool ProcessGDBRemote::StartNoticingNewThreads() { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + if (m_thread_create_bp_sp) { + if (log && log->GetVerbose()) + log->Printf("Enabled noticing new thread breakpoint."); + m_thread_create_bp_sp->SetEnabled(true); + } else { + PlatformSP platform_sp(GetTarget().GetPlatform()); + if (platform_sp) { + m_thread_create_bp_sp = + platform_sp->SetThreadCreationBreakpoint(GetTarget()); + if (m_thread_create_bp_sp) { if (log && log->GetVerbose()) - log->Printf("Enabled noticing new thread breakpoint."); - m_thread_create_bp_sp->SetEnabled(true); - } - else - { - PlatformSP platform_sp (GetTarget().GetPlatform()); - if (platform_sp) - { - m_thread_create_bp_sp = platform_sp->SetThreadCreationBreakpoint(GetTarget()); - if (m_thread_create_bp_sp) - { - if (log && log->GetVerbose()) - log->Printf("Successfully created new thread notification breakpoint %i", m_thread_create_bp_sp->GetID()); - m_thread_create_bp_sp->SetCallback (ProcessGDBRemote::NewThreadNotifyBreakpointHit, this, true); - } - else - { - if (log) - log->Printf("Failed to create new thread notification breakpoint."); - } - } + log->Printf( + "Successfully created new thread notification breakpoint %i", + m_thread_create_bp_sp->GetID()); + m_thread_create_bp_sp->SetCallback( + ProcessGDBRemote::NewThreadNotifyBreakpointHit, this, true); + } else { + if (log) + log->Printf("Failed to create new thread notification breakpoint."); + } } - return m_thread_create_bp_sp.get() != NULL; + } + return m_thread_create_bp_sp.get() != NULL; } -bool -ProcessGDBRemote::StopNoticingNewThreads() -{ - Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - if (log && log->GetVerbose()) - log->Printf ("Disabling new thread notification breakpoint."); +bool ProcessGDBRemote::StopNoticingNewThreads() { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + if (log && log->GetVerbose()) + log->Printf("Disabling new thread notification breakpoint."); - if (m_thread_create_bp_sp) - m_thread_create_bp_sp->SetEnabled(false); + if (m_thread_create_bp_sp) + m_thread_create_bp_sp->SetEnabled(false); - return true; + return true; } -DynamicLoader * -ProcessGDBRemote::GetDynamicLoader () -{ - if (m_dyld_ap.get() == NULL) - m_dyld_ap.reset (DynamicLoader::FindPlugin(this, NULL)); - return m_dyld_ap.get(); +DynamicLoader *ProcessGDBRemote::GetDynamicLoader() { + if (m_dyld_ap.get() == NULL) + m_dyld_ap.reset(DynamicLoader::FindPlugin(this, NULL)); + return m_dyld_ap.get(); } -Error -ProcessGDBRemote::SendEventData(const char *data) -{ - int return_value; - bool was_supported; +Error ProcessGDBRemote::SendEventData(const char *data) { + int return_value; + bool was_supported; - Error error; + Error error; - return_value = m_gdb_comm.SendLaunchEventDataPacket (data, &was_supported); - if (return_value != 0) - { - if (!was_supported) - error.SetErrorString("Sending events is not supported for this process."); - else - error.SetErrorStringWithFormat("Error sending event data: %d.", return_value); - } - return error; + return_value = m_gdb_comm.SendLaunchEventDataPacket(data, &was_supported); + if (return_value != 0) { + if (!was_supported) + error.SetErrorString("Sending events is not supported for this process."); + else + error.SetErrorStringWithFormat("Error sending event data: %d.", + return_value); + } + return error; } -const DataBufferSP -ProcessGDBRemote::GetAuxvData() -{ - DataBufferSP buf; - if (m_gdb_comm.GetQXferAuxvReadSupported()) - { - std::string response_string; - if (m_gdb_comm.SendPacketsAndConcatenateResponses("qXfer:auxv:read::", response_string) == GDBRemoteCommunication::PacketResult::Success) - buf.reset(new DataBufferHeap(response_string.c_str(), response_string.length())); - } - return buf; +const DataBufferSP ProcessGDBRemote::GetAuxvData() { + DataBufferSP buf; + if (m_gdb_comm.GetQXferAuxvReadSupported()) { + std::string response_string; + if (m_gdb_comm.SendPacketsAndConcatenateResponses("qXfer:auxv:read::", + response_string) == + GDBRemoteCommunication::PacketResult::Success) + buf.reset(new DataBufferHeap(response_string.c_str(), + response_string.length())); + } + return buf; } StructuredData::ObjectSP -ProcessGDBRemote::GetExtendedInfoForThread (lldb::tid_t tid) -{ - StructuredData::ObjectSP object_sp; +ProcessGDBRemote::GetExtendedInfoForThread(lldb::tid_t tid) { + StructuredData::ObjectSP object_sp; - if (m_gdb_comm.GetThreadExtendedInfoSupported()) - { - StructuredData::ObjectSP args_dict(new StructuredData::Dictionary()); - SystemRuntime *runtime = GetSystemRuntime(); - if (runtime) - { - runtime->AddThreadExtendedInfoPacketHints (args_dict); - } - args_dict->GetAsDictionary()->AddIntegerItem ("thread", tid); + if (m_gdb_comm.GetThreadExtendedInfoSupported()) { + StructuredData::ObjectSP args_dict(new StructuredData::Dictionary()); + SystemRuntime *runtime = GetSystemRuntime(); + if (runtime) { + runtime->AddThreadExtendedInfoPacketHints(args_dict); + } + args_dict->GetAsDictionary()->AddIntegerItem("thread", tid); - StreamString packet; - packet << "jThreadExtendedInfo:"; - args_dict->Dump (packet); + StreamString packet; + packet << "jThreadExtendedInfo:"; + args_dict->Dump(packet, false); - // FIXME the final character of a JSON dictionary, '}', is the escape - // character in gdb-remote binary mode. lldb currently doesn't escape - // these characters in its packet output -- so we add the quoted version - // of the } character here manually in case we talk to a debugserver which - // un-escapes the characters at packet read time. - packet << (char) (0x7d ^ 0x20); + // FIXME the final character of a JSON dictionary, '}', is the escape + // character in gdb-remote binary mode. lldb currently doesn't escape + // these characters in its packet output -- so we add the quoted version + // of the } character here manually in case we talk to a debugserver which + // un-escapes the characters at packet read time. + packet << (char)(0x7d ^ 0x20); - StringExtractorGDBRemote response; - response.SetResponseValidatorToJSON(); - if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetData(), packet.GetSize(), response, false) == GDBRemoteCommunication::PacketResult::Success) - { - StringExtractorGDBRemote::ResponseType response_type = response.GetResponseType(); - if (response_type == StringExtractorGDBRemote::eResponse) - { - if (!response.Empty()) - { - object_sp = StructuredData::ParseJSON (response.GetStringRef()); - } - } + StringExtractorGDBRemote response; + response.SetResponseValidatorToJSON(); + if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response, + false) == + GDBRemoteCommunication::PacketResult::Success) { + StringExtractorGDBRemote::ResponseType response_type = + response.GetResponseType(); + if (response_type == StringExtractorGDBRemote::eResponse) { + if (!response.Empty()) { + object_sp = StructuredData::ParseJSON(response.GetStringRef()); } + } } - return object_sp; + } + return object_sp; +} + +StructuredData::ObjectSP ProcessGDBRemote::GetLoadedDynamicLibrariesInfos( + lldb::addr_t image_list_address, lldb::addr_t image_count) { + + StructuredData::ObjectSP args_dict(new StructuredData::Dictionary()); + args_dict->GetAsDictionary()->AddIntegerItem("image_list_address", + image_list_address); + args_dict->GetAsDictionary()->AddIntegerItem("image_count", image_count); + + return GetLoadedDynamicLibrariesInfos_sender(args_dict); +} + +StructuredData::ObjectSP ProcessGDBRemote::GetLoadedDynamicLibrariesInfos() { + StructuredData::ObjectSP args_dict(new StructuredData::Dictionary()); + + args_dict->GetAsDictionary()->AddBooleanItem("fetch_all_solibs", true); + + return GetLoadedDynamicLibrariesInfos_sender(args_dict); +} + +StructuredData::ObjectSP ProcessGDBRemote::GetLoadedDynamicLibrariesInfos( + const std::vector<lldb::addr_t> &load_addresses) { + StructuredData::ObjectSP args_dict(new StructuredData::Dictionary()); + StructuredData::ArraySP addresses(new StructuredData::Array); + + for (auto addr : load_addresses) { + StructuredData::ObjectSP addr_sp(new StructuredData::Integer(addr)); + addresses->AddItem(addr_sp); + } + + args_dict->GetAsDictionary()->AddItem("solib_addresses", addresses); + + return GetLoadedDynamicLibrariesInfos_sender(args_dict); } StructuredData::ObjectSP -ProcessGDBRemote::GetLoadedDynamicLibrariesInfos (lldb::addr_t image_list_address, lldb::addr_t image_count) -{ - StructuredData::ObjectSP object_sp; +ProcessGDBRemote::GetLoadedDynamicLibrariesInfos_sender( + StructuredData::ObjectSP args_dict) { + StructuredData::ObjectSP object_sp; - if (m_gdb_comm.GetLoadedDynamicLibrariesInfosSupported()) - { - // Scope for the scoped timeout object - GDBRemoteCommunication::ScopedTimeout timeout (m_gdb_comm, 10); + if (m_gdb_comm.GetLoadedDynamicLibrariesInfosSupported()) { + // Scope for the scoped timeout object + GDBRemoteCommunication::ScopedTimeout timeout(m_gdb_comm, + std::chrono::seconds(10)); - StructuredData::ObjectSP args_dict(new StructuredData::Dictionary()); - args_dict->GetAsDictionary()->AddIntegerItem ("image_list_address", image_list_address); - args_dict->GetAsDictionary()->AddIntegerItem ("image_count", image_count); + StreamString packet; + packet << "jGetLoadedDynamicLibrariesInfos:"; + args_dict->Dump(packet, false); - StreamString packet; - packet << "jGetLoadedDynamicLibrariesInfos:"; - args_dict->Dump (packet); + // FIXME the final character of a JSON dictionary, '}', is the escape + // character in gdb-remote binary mode. lldb currently doesn't escape + // these characters in its packet output -- so we add the quoted version + // of the } character here manually in case we talk to a debugserver which + // un-escapes the characters at packet read time. + packet << (char)(0x7d ^ 0x20); - // FIXME the final character of a JSON dictionary, '}', is the escape - // character in gdb-remote binary mode. lldb currently doesn't escape - // these characters in its packet output -- so we add the quoted version - // of the } character here manually in case we talk to a debugserver which - // un-escapes the characters at packet read time. - packet << (char) (0x7d ^ 0x20); + StringExtractorGDBRemote response; + response.SetResponseValidatorToJSON(); + if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response, + false) == + GDBRemoteCommunication::PacketResult::Success) { + StringExtractorGDBRemote::ResponseType response_type = + response.GetResponseType(); + if (response_type == StringExtractorGDBRemote::eResponse) { + if (!response.Empty()) { + object_sp = StructuredData::ParseJSON(response.GetStringRef()); + } + } + } + } + return object_sp; +} - StringExtractorGDBRemote response; - response.SetResponseValidatorToJSON(); - if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetData(), packet.GetSize(), response, false) == GDBRemoteCommunication::PacketResult::Success) - { - StringExtractorGDBRemote::ResponseType response_type = response.GetResponseType(); - if (response_type == StringExtractorGDBRemote::eResponse) - { - if (!response.Empty()) - { - object_sp = StructuredData::ParseJSON (response.GetStringRef()); - } - } +StructuredData::ObjectSP ProcessGDBRemote::GetSharedCacheInfo() { + StructuredData::ObjectSP object_sp; + StructuredData::ObjectSP args_dict(new StructuredData::Dictionary()); + + if (m_gdb_comm.GetSharedCacheInfoSupported()) { + StreamString packet; + packet << "jGetSharedCacheInfo:"; + args_dict->Dump(packet, false); + + // FIXME the final character of a JSON dictionary, '}', is the escape + // character in gdb-remote binary mode. lldb currently doesn't escape + // these characters in its packet output -- so we add the quoted version + // of the } character here manually in case we talk to a debugserver which + // un-escapes the characters at packet read time. + packet << (char)(0x7d ^ 0x20); + + StringExtractorGDBRemote response; + response.SetResponseValidatorToJSON(); + if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response, + false) == + GDBRemoteCommunication::PacketResult::Success) { + StringExtractorGDBRemote::ResponseType response_type = + response.GetResponseType(); + if (response_type == StringExtractorGDBRemote::eResponse) { + if (!response.Empty()) { + object_sp = StructuredData::ParseJSON(response.GetStringRef()); } + } } - return object_sp; + } + return object_sp; +} + +Error ProcessGDBRemote::ConfigureStructuredData( + const ConstString &type_name, const StructuredData::ObjectSP &config_sp) { + return m_gdb_comm.ConfigureRemoteStructuredData(type_name, config_sp); } // Establish the largest memory read/write payloads we should use. @@ -4264,100 +3974,103 @@ ProcessGDBRemote::GetLoadedDynamicLibrariesInfos (lldb::addr_t image_list_addres // If the remote stub doesn't advertise a max packet size, use a // conservative default. -void -ProcessGDBRemote::GetMaxMemorySize() -{ - const uint64_t reasonable_largeish_default = 128 * 1024; - const uint64_t conservative_default = 512; +void ProcessGDBRemote::GetMaxMemorySize() { + const uint64_t reasonable_largeish_default = 128 * 1024; + const uint64_t conservative_default = 512; - if (m_max_memory_size == 0) - { - uint64_t stub_max_size = m_gdb_comm.GetRemoteMaxPacketSize(); - if (stub_max_size != UINT64_MAX && stub_max_size != 0) - { - // Save the stub's claimed maximum packet size - m_remote_stub_max_memory_size = stub_max_size; + if (m_max_memory_size == 0) { + uint64_t stub_max_size = m_gdb_comm.GetRemoteMaxPacketSize(); + if (stub_max_size != UINT64_MAX && stub_max_size != 0) { + // Save the stub's claimed maximum packet size + m_remote_stub_max_memory_size = stub_max_size; - // Even if the stub says it can support ginormous packets, - // don't exceed our reasonable largeish default packet size. - if (stub_max_size > reasonable_largeish_default) - { - stub_max_size = reasonable_largeish_default; - } + // Even if the stub says it can support ginormous packets, + // don't exceed our reasonable largeish default packet size. + if (stub_max_size > reasonable_largeish_default) { + stub_max_size = reasonable_largeish_default; + } - m_max_memory_size = stub_max_size; - } - else - { - m_max_memory_size = conservative_default; - } + m_max_memory_size = stub_max_size; + } else { + m_max_memory_size = conservative_default; } + } } -void -ProcessGDBRemote::SetUserSpecifiedMaxMemoryTransferSize (uint64_t user_specified_max) -{ - if (user_specified_max != 0) - { - GetMaxMemorySize (); - - if (m_remote_stub_max_memory_size != 0) - { - if (m_remote_stub_max_memory_size < user_specified_max) - { - m_max_memory_size = m_remote_stub_max_memory_size; // user specified a packet size too big, go as big - // as the remote stub says we can go. - } - else - { - m_max_memory_size = user_specified_max; // user's packet size is good - } - } - else - { - m_max_memory_size = user_specified_max; // user's packet size is probably fine - } +void ProcessGDBRemote::SetUserSpecifiedMaxMemoryTransferSize( + uint64_t user_specified_max) { + if (user_specified_max != 0) { + GetMaxMemorySize(); + + if (m_remote_stub_max_memory_size != 0) { + if (m_remote_stub_max_memory_size < user_specified_max) { + m_max_memory_size = m_remote_stub_max_memory_size; // user specified a + // packet size too + // big, go as big + // as the remote stub says we can go. + } else { + m_max_memory_size = user_specified_max; // user's packet size is good + } + } else { + m_max_memory_size = + user_specified_max; // user's packet size is probably fine } + } } -bool -ProcessGDBRemote::GetModuleSpec(const FileSpec& module_file_spec, - const ArchSpec& arch, - ModuleSpec &module_spec) -{ - Log *log = GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PLATFORM); +bool ProcessGDBRemote::GetModuleSpec(const FileSpec &module_file_spec, + const ArchSpec &arch, + ModuleSpec &module_spec) { + Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM); - if (!m_gdb_comm.GetModuleInfo (module_file_spec, arch, module_spec)) - { - if (log) - log->Printf ("ProcessGDBRemote::%s - failed to get module info for %s:%s", - __FUNCTION__, module_file_spec.GetPath ().c_str (), - arch.GetTriple ().getTriple ().c_str ()); - return false; - } + const ModuleCacheKey key(module_file_spec.GetPath(), + arch.GetTriple().getTriple()); + auto cached = m_cached_module_specs.find(key); + if (cached != m_cached_module_specs.end()) { + module_spec = cached->second; + return bool(module_spec); + } + if (!m_gdb_comm.GetModuleInfo(module_file_spec, arch, module_spec)) { if (log) - { - StreamString stream; - module_spec.Dump (stream); - log->Printf ("ProcessGDBRemote::%s - got module info for (%s:%s) : %s", - __FUNCTION__, module_file_spec.GetPath ().c_str (), - arch.GetTriple ().getTriple ().c_str (), stream.GetString ().c_str ()); - } + log->Printf("ProcessGDBRemote::%s - failed to get module info for %s:%s", + __FUNCTION__, module_file_spec.GetPath().c_str(), + arch.GetTriple().getTriple().c_str()); + return false; + } + + if (log) { + StreamString stream; + module_spec.Dump(stream); + log->Printf("ProcessGDBRemote::%s - got module info for (%s:%s) : %s", + __FUNCTION__, module_file_spec.GetPath().c_str(), + arch.GetTriple().getTriple().c_str(), stream.GetData()); + } + + m_cached_module_specs[key] = module_spec; + return true; +} - return true; +void ProcessGDBRemote::PrefetchModuleSpecs( + llvm::ArrayRef<FileSpec> module_file_specs, const llvm::Triple &triple) { + auto module_specs = m_gdb_comm.GetModulesInfo(module_file_specs, triple); + if (module_specs) { + for (const FileSpec &spec : module_file_specs) + m_cached_module_specs[ModuleCacheKey(spec.GetPath(), + triple.getTriple())] = ModuleSpec(); + for (const ModuleSpec &spec : *module_specs) + m_cached_module_specs[ModuleCacheKey(spec.GetFileSpec().GetPath(), + triple.getTriple())] = spec; + } } -bool -ProcessGDBRemote::GetHostOSVersion(uint32_t &major, - uint32_t &minor, - uint32_t &update) -{ - if (m_gdb_comm.GetOSVersion(major, minor, update)) - return true; - // We failed to get the host OS version, defer to the base - // implementation to correctly invalidate the arguments. - return Process::GetHostOSVersion(major, minor, update); +bool ProcessGDBRemote::GetHostOSVersion(uint32_t &major, uint32_t &minor, + uint32_t &update) { + if (m_gdb_comm.GetOSVersion(major, minor, update)) + return true; + // We failed to get the host OS version, defer to the base + // implementation to correctly invalidate the arguments. + return Process::GetHostOSVersion(major, minor, update); } namespace { @@ -4365,29 +4078,29 @@ namespace { typedef std::vector<std::string> stringVec; typedef std::vector<struct GdbServerRegisterInfo> GDBServerRegisterVec; -struct RegisterSetInfo -{ - ConstString name; +struct RegisterSetInfo { + ConstString name; }; typedef std::map<uint32_t, RegisterSetInfo> RegisterSetMap; -struct GdbServerTargetInfo -{ - std::string arch; - std::string osabi; - stringVec includes; - RegisterSetMap reg_set_map; - XMLNode feature_node; +struct GdbServerTargetInfo { + std::string arch; + std::string osabi; + stringVec includes; + RegisterSetMap reg_set_map; + XMLNode feature_node; }; -bool -ParseRegisters (XMLNode feature_node, GdbServerTargetInfo &target_info, GDBRemoteDynamicRegisterInfo &dyn_reg_info, ABISP abi_sp, uint32_t &cur_reg_num, uint32_t ®_offset) -{ - if (!feature_node) - return false; +bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info, + GDBRemoteDynamicRegisterInfo &dyn_reg_info, ABISP abi_sp, + uint32_t &cur_reg_num, uint32_t ®_offset) { + if (!feature_node) + return false; - feature_node.ForEachChildElementWithName("reg", [&target_info, &dyn_reg_info, &cur_reg_num, ®_offset, &abi_sp](const XMLNode ®_node) -> bool { + feature_node.ForEachChildElementWithName( + "reg", [&target_info, &dyn_reg_info, &cur_reg_num, ®_offset, + &abi_sp](const XMLNode ®_node) -> bool { std::string gdb_group; std::string gdb_type; ConstString reg_name; @@ -4398,931 +4111,1038 @@ ParseRegisters (XMLNode feature_node, GdbServerTargetInfo &target_info, GDBRemot std::vector<uint8_t> dwarf_opcode_bytes; bool encoding_set = false; bool format_set = false; - RegisterInfo reg_info = { NULL, // Name - NULL, // Alt name - 0, // byte size - reg_offset, // offset - eEncodingUint, // encoding - eFormatHex, // format + RegisterInfo reg_info = { + NULL, // Name + NULL, // Alt name + 0, // byte size + reg_offset, // offset + eEncodingUint, // encoding + eFormatHex, // format { LLDB_INVALID_REGNUM, // eh_frame reg num LLDB_INVALID_REGNUM, // DWARF reg num LLDB_INVALID_REGNUM, // generic reg num - cur_reg_num, // process plugin reg num - cur_reg_num // native register number + cur_reg_num, // process plugin reg num + cur_reg_num // native register number }, NULL, NULL, - NULL, // Dwarf Expression opcode bytes pointer - 0 // Dwarf Expression opcode bytes length + NULL, // Dwarf Expression opcode bytes pointer + 0 // Dwarf Expression opcode bytes length }; - reg_node.ForEachAttribute([&target_info, &gdb_group, &gdb_type, ®_name, &alt_name, &set_name, &value_regs, &invalidate_regs, &encoding_set, &format_set, ®_info, &cur_reg_num, ®_offset, &dwarf_opcode_bytes](const llvm::StringRef &name, const llvm::StringRef &value) -> bool { - if (name == "name") - { - reg_name.SetString(value); - } - else if (name == "bitsize") - { - reg_info.byte_size = StringConvert::ToUInt32(value.data(), 0, 0) / CHAR_BIT; - } - else if (name == "type") - { - gdb_type = value.str(); - } - else if (name == "group") - { - gdb_group = value.str(); - } - else if (name == "regnum") - { - const uint32_t regnum = StringConvert::ToUInt32(value.data(), LLDB_INVALID_REGNUM, 0); - if (regnum != LLDB_INVALID_REGNUM) - { - reg_info.kinds[eRegisterKindProcessPlugin] = regnum; - } - } - else if (name == "offset") - { - reg_offset = StringConvert::ToUInt32(value.data(), UINT32_MAX, 0); - } - else if (name == "altname") - { - alt_name.SetString(value); - } - else if (name == "encoding") - { - encoding_set = true; - reg_info.encoding = Args::StringToEncoding (value.data(), eEncodingUint); - } - else if (name == "format") - { - format_set = true; - Format format = eFormatInvalid; - if (Args::StringToFormat (value.data(), format, NULL).Success()) - reg_info.format = format; - else if (value == "vector-sint8") - reg_info.format = eFormatVectorOfSInt8; - else if (value == "vector-uint8") - reg_info.format = eFormatVectorOfUInt8; - else if (value == "vector-sint16") - reg_info.format = eFormatVectorOfSInt16; - else if (value == "vector-uint16") - reg_info.format = eFormatVectorOfUInt16; - else if (value == "vector-sint32") - reg_info.format = eFormatVectorOfSInt32; - else if (value == "vector-uint32") - reg_info.format = eFormatVectorOfUInt32; - else if (value == "vector-float32") - reg_info.format = eFormatVectorOfFloat32; - else if (value == "vector-uint128") - reg_info.format = eFormatVectorOfUInt128; - } - else if (name == "group_id") - { - const uint32_t set_id = StringConvert::ToUInt32(value.data(), UINT32_MAX, 0); - RegisterSetMap::const_iterator pos = target_info.reg_set_map.find(set_id); - if (pos != target_info.reg_set_map.end()) - set_name = pos->second.name; - } - else if (name == "gcc_regnum" || name == "ehframe_regnum") - { - reg_info.kinds[eRegisterKindEHFrame] = StringConvert::ToUInt32(value.data(), LLDB_INVALID_REGNUM, 0); - } - else if (name == "dwarf_regnum") - { - reg_info.kinds[eRegisterKindDWARF] = StringConvert::ToUInt32(value.data(), LLDB_INVALID_REGNUM, 0); - } - else if (name == "generic") - { - reg_info.kinds[eRegisterKindGeneric] = Args::StringToGenericRegister(value.data()); - } - else if (name == "value_regnums") - { - SplitCommaSeparatedRegisterNumberString(value, value_regs, 0); - } - else if (name == "invalidate_regnums") - { - SplitCommaSeparatedRegisterNumberString(value, invalidate_regs, 0); - } - else if (name == "dynamic_size_dwarf_expr_bytes") - { - StringExtractor opcode_extractor; - std::string opcode_string = value.str (); - size_t dwarf_opcode_len = opcode_string.length () / 2; - assert (dwarf_opcode_len > 0); - - dwarf_opcode_bytes.resize (dwarf_opcode_len); - reg_info.dynamic_size_dwarf_len = dwarf_opcode_len; - opcode_extractor.GetStringRef ().swap (opcode_string); - uint32_t ret_val = opcode_extractor.GetHexBytesAvail (dwarf_opcode_bytes.data (), - dwarf_opcode_len); - assert (dwarf_opcode_len == ret_val); - - reg_info.dynamic_size_dwarf_expr_bytes = dwarf_opcode_bytes.data (); - } - else - { - printf("unhandled attribute %s = %s\n", name.data(), value.data()); + reg_node.ForEachAttribute([&target_info, &gdb_group, &gdb_type, + ®_name, &alt_name, &set_name, &value_regs, + &invalidate_regs, &encoding_set, &format_set, + ®_info, &cur_reg_num, ®_offset, + &dwarf_opcode_bytes]( + const llvm::StringRef &name, + const llvm::StringRef &value) -> bool { + if (name == "name") { + reg_name.SetString(value); + } else if (name == "bitsize") { + reg_info.byte_size = + StringConvert::ToUInt32(value.data(), 0, 0) / CHAR_BIT; + } else if (name == "type") { + gdb_type = value.str(); + } else if (name == "group") { + gdb_group = value.str(); + } else if (name == "regnum") { + const uint32_t regnum = + StringConvert::ToUInt32(value.data(), LLDB_INVALID_REGNUM, 0); + if (regnum != LLDB_INVALID_REGNUM) { + reg_info.kinds[eRegisterKindProcessPlugin] = regnum; } - return true; // Keep iterating through all attributes + } else if (name == "offset") { + reg_offset = StringConvert::ToUInt32(value.data(), UINT32_MAX, 0); + } else if (name == "altname") { + alt_name.SetString(value); + } else if (name == "encoding") { + encoding_set = true; + reg_info.encoding = Args::StringToEncoding(value, eEncodingUint); + } else if (name == "format") { + format_set = true; + Format format = eFormatInvalid; + if (Args::StringToFormat(value.data(), format, NULL).Success()) + reg_info.format = format; + else if (value == "vector-sint8") + reg_info.format = eFormatVectorOfSInt8; + else if (value == "vector-uint8") + reg_info.format = eFormatVectorOfUInt8; + else if (value == "vector-sint16") + reg_info.format = eFormatVectorOfSInt16; + else if (value == "vector-uint16") + reg_info.format = eFormatVectorOfUInt16; + else if (value == "vector-sint32") + reg_info.format = eFormatVectorOfSInt32; + else if (value == "vector-uint32") + reg_info.format = eFormatVectorOfUInt32; + else if (value == "vector-float32") + reg_info.format = eFormatVectorOfFloat32; + else if (value == "vector-uint64") + reg_info.format = eFormatVectorOfUInt64; + else if (value == "vector-uint128") + reg_info.format = eFormatVectorOfUInt128; + } else if (name == "group_id") { + const uint32_t set_id = + StringConvert::ToUInt32(value.data(), UINT32_MAX, 0); + RegisterSetMap::const_iterator pos = + target_info.reg_set_map.find(set_id); + if (pos != target_info.reg_set_map.end()) + set_name = pos->second.name; + } else if (name == "gcc_regnum" || name == "ehframe_regnum") { + reg_info.kinds[eRegisterKindEHFrame] = + StringConvert::ToUInt32(value.data(), LLDB_INVALID_REGNUM, 0); + } else if (name == "dwarf_regnum") { + reg_info.kinds[eRegisterKindDWARF] = + StringConvert::ToUInt32(value.data(), LLDB_INVALID_REGNUM, 0); + } else if (name == "generic") { + reg_info.kinds[eRegisterKindGeneric] = + Args::StringToGenericRegister(value); + } else if (name == "value_regnums") { + SplitCommaSeparatedRegisterNumberString(value, value_regs, 0); + } else if (name == "invalidate_regnums") { + SplitCommaSeparatedRegisterNumberString(value, invalidate_regs, 0); + } else if (name == "dynamic_size_dwarf_expr_bytes") { + StringExtractor opcode_extractor; + std::string opcode_string = value.str(); + size_t dwarf_opcode_len = opcode_string.length() / 2; + assert(dwarf_opcode_len > 0); + + dwarf_opcode_bytes.resize(dwarf_opcode_len); + reg_info.dynamic_size_dwarf_len = dwarf_opcode_len; + opcode_extractor.GetStringRef().swap(opcode_string); + uint32_t ret_val = + opcode_extractor.GetHexBytesAvail(dwarf_opcode_bytes); + assert(dwarf_opcode_len == ret_val); + + reg_info.dynamic_size_dwarf_expr_bytes = dwarf_opcode_bytes.data(); + } else { + printf("unhandled attribute %s = %s\n", name.data(), value.data()); + } + return true; // Keep iterating through all attributes }); - if (!gdb_type.empty() && !(encoding_set || format_set)) - { - if (gdb_type.find("int") == 0) - { - reg_info.format = eFormatHex; - reg_info.encoding = eEncodingUint; - } - else if (gdb_type == "data_ptr" || gdb_type == "code_ptr") - { - reg_info.format = eFormatAddressInfo; - reg_info.encoding = eEncodingUint; - } - else if (gdb_type == "i387_ext" || gdb_type == "float") - { - reg_info.format = eFormatFloat; - reg_info.encoding = eEncodingIEEE754; - } + if (!gdb_type.empty() && !(encoding_set || format_set)) { + if (gdb_type.find("int") == 0) { + reg_info.format = eFormatHex; + reg_info.encoding = eEncodingUint; + } else if (gdb_type == "data_ptr" || gdb_type == "code_ptr") { + reg_info.format = eFormatAddressInfo; + reg_info.encoding = eEncodingUint; + } else if (gdb_type == "i387_ext" || gdb_type == "float") { + reg_info.format = eFormatFloat; + reg_info.encoding = eEncodingIEEE754; + } } - // Only update the register set name if we didn't get a "reg_set" attribute. + // Only update the register set name if we didn't get a "reg_set" + // attribute. // "set_name" will be empty if we didn't have a "reg_set" attribute. if (!set_name && !gdb_group.empty()) - set_name.SetCString(gdb_group.c_str()); + set_name.SetCString(gdb_group.c_str()); reg_info.byte_offset = reg_offset; - assert (reg_info.byte_size != 0); + assert(reg_info.byte_size != 0); reg_offset += reg_info.byte_size; - if (!value_regs.empty()) - { - value_regs.push_back(LLDB_INVALID_REGNUM); - reg_info.value_regs = value_regs.data(); + if (!value_regs.empty()) { + value_regs.push_back(LLDB_INVALID_REGNUM); + reg_info.value_regs = value_regs.data(); } - if (!invalidate_regs.empty()) - { - invalidate_regs.push_back(LLDB_INVALID_REGNUM); - reg_info.invalidate_regs = invalidate_regs.data(); + if (!invalidate_regs.empty()) { + invalidate_regs.push_back(LLDB_INVALID_REGNUM); + reg_info.invalidate_regs = invalidate_regs.data(); } ++cur_reg_num; - AugmentRegisterInfoViaABI (reg_info, reg_name, abi_sp); + AugmentRegisterInfoViaABI(reg_info, reg_name, abi_sp); dyn_reg_info.AddRegister(reg_info, reg_name, alt_name, set_name); return true; // Keep iterating through all "reg" elements - }); - return true; + }); + return true; } } // namespace {} - // query the target of gdb-remote for extended target information // return: 'true' on success // 'false' on failure -bool -ProcessGDBRemote::GetGDBServerRegisterInfo (ArchSpec &arch_to_use) -{ - // Make sure LLDB has an XML parser it can use first - if (!XMLDocument::XMLEnabled()) - return false; - - // redirect libxml2's error handler since the default prints to stdout - - GDBRemoteCommunicationClient & comm = m_gdb_comm; - - // check that we have extended feature read support - if ( !comm.GetQXferFeaturesReadSupported( ) ) - return false; - - // request the target xml file - std::string raw; - lldb_private::Error lldberr; - if (!comm.ReadExtFeature(ConstString("features"), - ConstString("target.xml"), - raw, - lldberr)) - { - return false; - } +bool ProcessGDBRemote::GetGDBServerRegisterInfo(ArchSpec &arch_to_use) { + // Make sure LLDB has an XML parser it can use first + if (!XMLDocument::XMLEnabled()) + return false; + // redirect libxml2's error handler since the default prints to stdout - XMLDocument xml_document; + GDBRemoteCommunicationClient &comm = m_gdb_comm; - if (xml_document.ParseMemory(raw.c_str(), raw.size(), "target.xml")) - { - GdbServerTargetInfo target_info; + // check that we have extended feature read support + if (!comm.GetQXferFeaturesReadSupported()) + return false; - XMLNode target_node = xml_document.GetRootElement("target"); - if (target_node) - { - XMLNode feature_node; - target_node.ForEachChildElement([&target_info, this, &feature_node](const XMLNode &node) -> bool - { - llvm::StringRef name = node.GetName(); - if (name == "architecture") - { - node.GetElementText(target_info.arch); - } - else if (name == "osabi") - { - node.GetElementText(target_info.osabi); - } - else if (name == "xi:include" || name == "include") - { - llvm::StringRef href = node.GetAttributeValue("href"); - if (!href.empty()) - target_info.includes.push_back(href.str()); - } - else if (name == "feature") - { - feature_node = node; - } - else if (name == "groups") - { - node.ForEachChildElementWithName("group", [&target_info](const XMLNode &node) -> bool { - uint32_t set_id = UINT32_MAX; - RegisterSetInfo set_info; - - node.ForEachAttribute([&set_id, &set_info](const llvm::StringRef &name, const llvm::StringRef &value) -> bool { - if (name == "id") - set_id = StringConvert::ToUInt32(value.data(), UINT32_MAX, 0); - if (name == "name") - set_info.name = ConstString(value); - return true; // Keep iterating through all attributes - }); - - if (set_id != UINT32_MAX) - target_info.reg_set_map[set_id] = set_info; - return true; // Keep iterating through all "group" elements + // request the target xml file + std::string raw; + lldb_private::Error lldberr; + if (!comm.ReadExtFeature(ConstString("features"), ConstString("target.xml"), + raw, lldberr)) { + return false; + } + + XMLDocument xml_document; + + if (xml_document.ParseMemory(raw.c_str(), raw.size(), "target.xml")) { + GdbServerTargetInfo target_info; + + XMLNode target_node = xml_document.GetRootElement("target"); + if (target_node) { + XMLNode feature_node; + target_node.ForEachChildElement([&target_info, this, &feature_node]( + const XMLNode &node) -> bool { + llvm::StringRef name = node.GetName(); + if (name == "architecture") { + node.GetElementText(target_info.arch); + } else if (name == "osabi") { + node.GetElementText(target_info.osabi); + } else if (name == "xi:include" || name == "include") { + llvm::StringRef href = node.GetAttributeValue("href"); + if (!href.empty()) + target_info.includes.push_back(href.str()); + } else if (name == "feature") { + feature_node = node; + } else if (name == "groups") { + node.ForEachChildElementWithName( + "group", [&target_info](const XMLNode &node) -> bool { + uint32_t set_id = UINT32_MAX; + RegisterSetInfo set_info; + + node.ForEachAttribute( + [&set_id, &set_info](const llvm::StringRef &name, + const llvm::StringRef &value) -> bool { + if (name == "id") + set_id = StringConvert::ToUInt32(value.data(), + UINT32_MAX, 0); + if (name == "name") + set_info.name = ConstString(value); + return true; // Keep iterating through all attributes }); - } - return true; // Keep iterating through all children of the target_node - }); - - // Initialize these outside of ParseRegisters, since they should not be reset inside each include feature - uint32_t cur_reg_num = 0; - uint32_t reg_offset = 0; - - // Don't use Process::GetABI, this code gets called from DidAttach, and in that context we haven't - // set the Target's architecture yet, so the ABI is also potentially incorrect. - ABISP abi_to_use_sp = ABI::FindPlugin(arch_to_use); - if (feature_node) - { - ParseRegisters(feature_node, target_info, this->m_register_info, abi_to_use_sp, cur_reg_num, reg_offset); - } - for (const auto &include : target_info.includes) - { - // request register file - std::string xml_data; - if (!comm.ReadExtFeature(ConstString("features"), - ConstString(include), - xml_data, - lldberr)) - continue; - - XMLDocument include_xml_document; - include_xml_document.ParseMemory(xml_data.data(), xml_data.size(), include.c_str()); - XMLNode include_feature_node = include_xml_document.GetRootElement("feature"); - if (include_feature_node) - { - ParseRegisters(include_feature_node, target_info, this->m_register_info, abi_to_use_sp, cur_reg_num, reg_offset); - } - } - this->m_register_info.Finalize(arch_to_use); + if (set_id != UINT32_MAX) + target_info.reg_set_map[set_id] = set_info; + return true; // Keep iterating through all "group" elements + }); + } + return true; // Keep iterating through all children of the target_node + }); + + // Initialize these outside of ParseRegisters, since they should not be + // reset inside each include feature + uint32_t cur_reg_num = 0; + uint32_t reg_offset = 0; + + // Don't use Process::GetABI, this code gets called from DidAttach, and in + // that context we haven't + // set the Target's architecture yet, so the ABI is also potentially + // incorrect. + ABISP abi_to_use_sp = ABI::FindPlugin(arch_to_use); + if (feature_node) { + ParseRegisters(feature_node, target_info, this->m_register_info, + abi_to_use_sp, cur_reg_num, reg_offset); + } + + for (const auto &include : target_info.includes) { + // request register file + std::string xml_data; + if (!comm.ReadExtFeature(ConstString("features"), ConstString(include), + xml_data, lldberr)) + continue; + + XMLDocument include_xml_document; + include_xml_document.ParseMemory(xml_data.data(), xml_data.size(), + include.c_str()); + XMLNode include_feature_node = + include_xml_document.GetRootElement("feature"); + if (include_feature_node) { + ParseRegisters(include_feature_node, target_info, + this->m_register_info, abi_to_use_sp, cur_reg_num, + reg_offset); } + } + this->m_register_info.Finalize(arch_to_use); } + } - return m_register_info.GetNumRegisters() > 0; + return m_register_info.GetNumRegisters() > 0; } -Error -ProcessGDBRemote::GetLoadedModuleList (LoadedModuleInfoList & list) -{ - // Make sure LLDB has an XML parser it can use first - if (!XMLDocument::XMLEnabled()) - return Error (0, ErrorType::eErrorTypeGeneric); +Error ProcessGDBRemote::GetLoadedModuleList(LoadedModuleInfoList &list) { + // Make sure LLDB has an XML parser it can use first + if (!XMLDocument::XMLEnabled()) + return Error(0, ErrorType::eErrorTypeGeneric); - Log *log = GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS); - if (log) - log->Printf ("ProcessGDBRemote::%s", __FUNCTION__); + Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS); + if (log) + log->Printf("ProcessGDBRemote::%s", __FUNCTION__); - GDBRemoteCommunicationClient & comm = m_gdb_comm; + GDBRemoteCommunicationClient &comm = m_gdb_comm; - // check that we have extended feature read support - if (comm.GetQXferLibrariesSVR4ReadSupported ()) { - list.clear (); + // check that we have extended feature read support + if (comm.GetQXferLibrariesSVR4ReadSupported()) { + list.clear(); - // request the loaded library list - std::string raw; - lldb_private::Error lldberr; + // request the loaded library list + std::string raw; + lldb_private::Error lldberr; - if (!comm.ReadExtFeature (ConstString ("libraries-svr4"), ConstString (""), raw, lldberr)) - return Error (0, ErrorType::eErrorTypeGeneric); + if (!comm.ReadExtFeature(ConstString("libraries-svr4"), ConstString(""), + raw, lldberr)) + return Error(0, ErrorType::eErrorTypeGeneric); - // parse the xml file in memory - if (log) - log->Printf ("parsing: %s", raw.c_str()); - XMLDocument doc; + // parse the xml file in memory + if (log) + log->Printf("parsing: %s", raw.c_str()); + XMLDocument doc; - if (!doc.ParseMemory(raw.c_str(), raw.size(), "noname.xml")) - return Error (0, ErrorType::eErrorTypeGeneric); + if (!doc.ParseMemory(raw.c_str(), raw.size(), "noname.xml")) + return Error(0, ErrorType::eErrorTypeGeneric); - XMLNode root_element = doc.GetRootElement("library-list-svr4"); - if (!root_element) - return Error(); + XMLNode root_element = doc.GetRootElement("library-list-svr4"); + if (!root_element) + return Error(); - // main link map structure - llvm::StringRef main_lm = root_element.GetAttributeValue("main-lm"); - if (!main_lm.empty()) - { - list.m_link_map = StringConvert::ToUInt64(main_lm.data(), LLDB_INVALID_ADDRESS, 0); - } + // main link map structure + llvm::StringRef main_lm = root_element.GetAttributeValue("main-lm"); + if (!main_lm.empty()) { + list.m_link_map = + StringConvert::ToUInt64(main_lm.data(), LLDB_INVALID_ADDRESS, 0); + } - root_element.ForEachChildElementWithName("library", [log, &list](const XMLNode &library) -> bool { + root_element.ForEachChildElementWithName( + "library", [log, &list](const XMLNode &library) -> bool { - LoadedModuleInfoList::LoadedModuleInfo module; + LoadedModuleInfoList::LoadedModuleInfo module; - library.ForEachAttribute([log, &module](const llvm::StringRef &name, const llvm::StringRef &value) -> bool { + library.ForEachAttribute( + [log, &module](const llvm::StringRef &name, + const llvm::StringRef &value) -> bool { if (name == "name") - module.set_name (value.str()); - else if (name == "lm") - { - // the address of the link_map struct. - module.set_link_map(StringConvert::ToUInt64(value.data(), LLDB_INVALID_ADDRESS, 0)); - } - else if (name == "l_addr") - { - // the displacement as read from the field 'l_addr' of the link_map struct. - module.set_base(StringConvert::ToUInt64(value.data(), LLDB_INVALID_ADDRESS, 0)); - // base address is always a displacement, not an absolute value. - module.set_base_is_offset(true); - } - else if (name == "l_ld") - { - // the memory address of the libraries PT_DYAMIC section. - module.set_dynamic(StringConvert::ToUInt64(value.data(), LLDB_INVALID_ADDRESS, 0)); + module.set_name(value.str()); + else if (name == "lm") { + // the address of the link_map struct. + module.set_link_map(StringConvert::ToUInt64( + value.data(), LLDB_INVALID_ADDRESS, 0)); + } else if (name == "l_addr") { + // the displacement as read from the field 'l_addr' of the + // link_map struct. + module.set_base(StringConvert::ToUInt64( + value.data(), LLDB_INVALID_ADDRESS, 0)); + // base address is always a displacement, not an absolute + // value. + module.set_base_is_offset(true); + } else if (name == "l_ld") { + // the memory address of the libraries PT_DYAMIC section. + module.set_dynamic(StringConvert::ToUInt64( + value.data(), LLDB_INVALID_ADDRESS, 0)); } return true; // Keep iterating over all properties of "library" - }); - - if (log) - { - std::string name; - lldb::addr_t lm=0, base=0, ld=0; - bool base_is_offset; - - module.get_name (name); - module.get_link_map (lm); - module.get_base (base); - module.get_base_is_offset (base_is_offset); - module.get_dynamic (ld); - - log->Printf ("found (link_map:0x%08" PRIx64 ", base:0x%08" PRIx64 "[%s], ld:0x%08" PRIx64 ", name:'%s')", lm, base, (base_is_offset ? "offset" : "absolute"), ld, name.c_str()); - } - - list.add (module); - return true; // Keep iterating over all "library" elements in the root node + }); + + if (log) { + std::string name; + lldb::addr_t lm = 0, base = 0, ld = 0; + bool base_is_offset; + + module.get_name(name); + module.get_link_map(lm); + module.get_base(base); + module.get_base_is_offset(base_is_offset); + module.get_dynamic(ld); + + log->Printf("found (link_map:0x%08" PRIx64 ", base:0x%08" PRIx64 + "[%s], ld:0x%08" PRIx64 ", name:'%s')", + lm, base, (base_is_offset ? "offset" : "absolute"), ld, + name.c_str()); + } + + list.add(module); + return true; // Keep iterating over all "library" elements in the root + // node }); - if (log) - log->Printf ("found %" PRId32 " modules in total", (int) list.m_list.size()); - } else if (comm.GetQXferLibrariesReadSupported ()) { - list.clear (); - - // request the loaded library list - std::string raw; - lldb_private::Error lldberr; - - if (!comm.ReadExtFeature (ConstString ("libraries"), ConstString (""), raw, lldberr)) - return Error (0, ErrorType::eErrorTypeGeneric); - - if (log) - log->Printf ("parsing: %s", raw.c_str()); - XMLDocument doc; - - if (!doc.ParseMemory(raw.c_str(), raw.size(), "noname.xml")) - return Error (0, ErrorType::eErrorTypeGeneric); - - XMLNode root_element = doc.GetRootElement("library-list"); - if (!root_element) - return Error(); - - root_element.ForEachChildElementWithName("library", [log, &list](const XMLNode &library) -> bool { - LoadedModuleInfoList::LoadedModuleInfo module; - - llvm::StringRef name = library.GetAttributeValue("name"); - module.set_name(name.str()); + if (log) + log->Printf("found %" PRId32 " modules in total", + (int)list.m_list.size()); + } else if (comm.GetQXferLibrariesReadSupported()) { + list.clear(); - // The base address of a given library will be the address of its - // first section. Most remotes send only one section for Windows - // targets for example. - const XMLNode §ion = library.FindFirstChildElementWithName("section"); - llvm::StringRef address = section.GetAttributeValue("address"); - module.set_base(StringConvert::ToUInt64(address.data(), LLDB_INVALID_ADDRESS, 0)); - // These addresses are absolute values. - module.set_base_is_offset(false); + // request the loaded library list + std::string raw; + lldb_private::Error lldberr; - if (log) - { - std::string name; - lldb::addr_t base = 0; - bool base_is_offset; - module.get_name (name); - module.get_base (base); - module.get_base_is_offset (base_is_offset); - - log->Printf ("found (base:0x%08" PRIx64 "[%s], name:'%s')", base, (base_is_offset ? "offset" : "absolute"), name.c_str()); - } + if (!comm.ReadExtFeature(ConstString("libraries"), ConstString(""), raw, + lldberr)) + return Error(0, ErrorType::eErrorTypeGeneric); - list.add (module); - return true; // Keep iterating over all "library" elements in the root node + if (log) + log->Printf("parsing: %s", raw.c_str()); + XMLDocument doc; + + if (!doc.ParseMemory(raw.c_str(), raw.size(), "noname.xml")) + return Error(0, ErrorType::eErrorTypeGeneric); + + XMLNode root_element = doc.GetRootElement("library-list"); + if (!root_element) + return Error(); + + root_element.ForEachChildElementWithName( + "library", [log, &list](const XMLNode &library) -> bool { + LoadedModuleInfoList::LoadedModuleInfo module; + + llvm::StringRef name = library.GetAttributeValue("name"); + module.set_name(name.str()); + + // The base address of a given library will be the address of its + // first section. Most remotes send only one section for Windows + // targets for example. + const XMLNode §ion = + library.FindFirstChildElementWithName("section"); + llvm::StringRef address = section.GetAttributeValue("address"); + module.set_base( + StringConvert::ToUInt64(address.data(), LLDB_INVALID_ADDRESS, 0)); + // These addresses are absolute values. + module.set_base_is_offset(false); + + if (log) { + std::string name; + lldb::addr_t base = 0; + bool base_is_offset; + module.get_name(name); + module.get_base(base); + module.get_base_is_offset(base_is_offset); + + log->Printf("found (base:0x%08" PRIx64 "[%s], name:'%s')", base, + (base_is_offset ? "offset" : "absolute"), name.c_str()); + } + + list.add(module); + return true; // Keep iterating over all "library" elements in the root + // node }); - if (log) - log->Printf ("found %" PRId32 " modules in total", (int) list.m_list.size()); - } else { - return Error (0, ErrorType::eErrorTypeGeneric); - } + if (log) + log->Printf("found %" PRId32 " modules in total", + (int)list.m_list.size()); + } else { + return Error(0, ErrorType::eErrorTypeGeneric); + } - return Error(); + return Error(); } -lldb::ModuleSP -ProcessGDBRemote::LoadModuleAtAddress (const FileSpec &file, lldb::addr_t link_map, - lldb::addr_t base_addr, bool value_is_offset) -{ - DynamicLoader *loader = GetDynamicLoader(); - if (!loader) - return nullptr; +lldb::ModuleSP ProcessGDBRemote::LoadModuleAtAddress(const FileSpec &file, + lldb::addr_t link_map, + lldb::addr_t base_addr, + bool value_is_offset) { + DynamicLoader *loader = GetDynamicLoader(); + if (!loader) + return nullptr; - return loader->LoadModuleAtAddress(file, link_map, base_addr, value_is_offset); + return loader->LoadModuleAtAddress(file, link_map, base_addr, + value_is_offset); } -size_t -ProcessGDBRemote::LoadModules (LoadedModuleInfoList &module_list) -{ - using lldb_private::process_gdb_remote::ProcessGDBRemote; - - // request a list of loaded libraries from GDBServer - if (GetLoadedModuleList (module_list).Fail()) - return 0; +size_t ProcessGDBRemote::LoadModules(LoadedModuleInfoList &module_list) { + using lldb_private::process_gdb_remote::ProcessGDBRemote; - // get a list of all the modules - ModuleList new_modules; + // request a list of loaded libraries from GDBServer + if (GetLoadedModuleList(module_list).Fail()) + return 0; - for (LoadedModuleInfoList::LoadedModuleInfo & modInfo : module_list.m_list) - { - std::string mod_name; - lldb::addr_t mod_base; - lldb::addr_t link_map; - bool mod_base_is_offset; - - bool valid = true; - valid &= modInfo.get_name (mod_name); - valid &= modInfo.get_base (mod_base); - valid &= modInfo.get_base_is_offset (mod_base_is_offset); - if (!valid) - continue; - - if (!modInfo.get_link_map (link_map)) - link_map = LLDB_INVALID_ADDRESS; - - FileSpec file (mod_name.c_str(), true); - lldb::ModuleSP module_sp = LoadModuleAtAddress (file, link_map, mod_base, - mod_base_is_offset); - - if (module_sp.get()) - new_modules.Append (module_sp); - } + // get a list of all the modules + ModuleList new_modules; + + for (LoadedModuleInfoList::LoadedModuleInfo &modInfo : module_list.m_list) { + std::string mod_name; + lldb::addr_t mod_base; + lldb::addr_t link_map; + bool mod_base_is_offset; + + bool valid = true; + valid &= modInfo.get_name(mod_name); + valid &= modInfo.get_base(mod_base); + valid &= modInfo.get_base_is_offset(mod_base_is_offset); + if (!valid) + continue; + + if (!modInfo.get_link_map(link_map)) + link_map = LLDB_INVALID_ADDRESS; + + FileSpec file(mod_name, true); + lldb::ModuleSP module_sp = + LoadModuleAtAddress(file, link_map, mod_base, mod_base_is_offset); + + if (module_sp.get()) + new_modules.Append(module_sp); + } + + if (new_modules.GetSize() > 0) { + ModuleList removed_modules; + Target &target = GetTarget(); + ModuleList &loaded_modules = m_process->GetTarget().GetImages(); + + for (size_t i = 0; i < loaded_modules.GetSize(); ++i) { + const lldb::ModuleSP loaded_module = loaded_modules.GetModuleAtIndex(i); + + bool found = false; + for (size_t j = 0; j < new_modules.GetSize(); ++j) { + if (new_modules.GetModuleAtIndex(j).get() == loaded_module.get()) + found = true; + } + + // The main executable will never be included in libraries-svr4, don't + // remove it + if (!found && + loaded_module.get() != target.GetExecutableModulePointer()) { + removed_modules.Append(loaded_module); + } + } + + loaded_modules.Remove(removed_modules); + m_process->GetTarget().ModulesDidUnload(removed_modules, false); + + new_modules.ForEach([&target](const lldb::ModuleSP module_sp) -> bool { + lldb_private::ObjectFile *obj = module_sp->GetObjectFile(); + if (!obj) + return true; - if (new_modules.GetSize() > 0) - { - ModuleList removed_modules; - Target &target = GetTarget(); - ModuleList &loaded_modules = m_process->GetTarget().GetImages(); + if (obj->GetType() != ObjectFile::Type::eTypeExecutable) + return true; - for (size_t i = 0; i < loaded_modules.GetSize(); ++i) - { - const lldb::ModuleSP loaded_module = loaded_modules.GetModuleAtIndex(i); + lldb::ModuleSP module_copy_sp = module_sp; + target.SetExecutableModule(module_copy_sp, false); + return false; + }); - bool found = false; - for (size_t j = 0; j < new_modules.GetSize(); ++j) - { - if (new_modules.GetModuleAtIndex(j).get() == loaded_module.get()) - found = true; - } + loaded_modules.AppendIfNeeded(new_modules); + m_process->GetTarget().ModulesDidLoad(new_modules); + } - // The main executable will never be included in libraries-svr4, don't remove it - if (!found && loaded_module.get() != target.GetExecutableModulePointer()) - { - removed_modules.Append (loaded_module); - } - } - - loaded_modules.Remove (removed_modules); - m_process->GetTarget().ModulesDidUnload (removed_modules, false); + return new_modules.GetSize(); +} - new_modules.ForEach ([&target](const lldb::ModuleSP module_sp) -> bool - { - lldb_private::ObjectFile * obj = module_sp->GetObjectFile (); - if (!obj) - return true; +size_t ProcessGDBRemote::LoadModules() { + LoadedModuleInfoList module_list; + return LoadModules(module_list); +} - if (obj->GetType () != ObjectFile::Type::eTypeExecutable) - return true; +Error ProcessGDBRemote::GetFileLoadAddress(const FileSpec &file, + bool &is_loaded, + lldb::addr_t &load_addr) { + is_loaded = false; + load_addr = LLDB_INVALID_ADDRESS; + + std::string file_path = file.GetPath(false); + if (file_path.empty()) + return Error("Empty file name specified"); + + StreamString packet; + packet.PutCString("qFileLoadAddress:"); + packet.PutCStringAsRawHex8(file_path.c_str()); + + StringExtractorGDBRemote response; + if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response, + false) != + GDBRemoteCommunication::PacketResult::Success) + return Error("Sending qFileLoadAddress packet failed"); + + if (response.IsErrorResponse()) { + if (response.GetError() == 1) { + // The file is not loaded into the inferior + is_loaded = false; + load_addr = LLDB_INVALID_ADDRESS; + return Error(); + } + + return Error( + "Fetching file load address from remote server returned an error"); + } + + if (response.IsNormalResponse()) { + is_loaded = true; + load_addr = response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS); + return Error(); + } - lldb::ModuleSP module_copy_sp = module_sp; - target.SetExecutableModule (module_copy_sp, false); - return false; - }); + return Error("Unknown error happened during sending the load address packet"); +} - loaded_modules.AppendIfNeeded (new_modules); - m_process->GetTarget().ModulesDidLoad (new_modules); - } +void ProcessGDBRemote::ModulesDidLoad(ModuleList &module_list) { + // We must call the lldb_private::Process::ModulesDidLoad () first before we + // do anything + Process::ModulesDidLoad(module_list); - return new_modules.GetSize(); + // After loading shared libraries, we can ask our remote GDB server if + // it needs any symbols. + m_gdb_comm.ServeSymbolLookups(this); } -size_t -ProcessGDBRemote::LoadModules () -{ - LoadedModuleInfoList module_list; - return LoadModules (module_list); +void ProcessGDBRemote::HandleAsyncStdout(llvm::StringRef out) { + AppendSTDOUT(out.data(), out.size()); } -Error -ProcessGDBRemote::GetFileLoadAddress(const FileSpec& file, bool& is_loaded, lldb::addr_t& load_addr) -{ - is_loaded = false; - load_addr = LLDB_INVALID_ADDRESS; - - std::string file_path = file.GetPath(false); - if (file_path.empty ()) - return Error("Empty file name specified"); - - StreamString packet; - packet.PutCString("qFileLoadAddress:"); - packet.PutCStringAsRawHex8(file_path.c_str()); - - StringExtractorGDBRemote response; - if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), response, false) != GDBRemoteCommunication::PacketResult::Success) - return Error("Sending qFileLoadAddress packet failed"); +static const char *end_delimiter = "--end--;"; +static const int end_delimiter_len = 8; + +void ProcessGDBRemote::HandleAsyncMisc(llvm::StringRef data) { + std::string input = data.str(); // '1' to move beyond 'A' + if (m_partial_profile_data.length() > 0) { + m_partial_profile_data.append(input); + input = m_partial_profile_data; + m_partial_profile_data.clear(); + } + + size_t found, pos = 0, len = input.length(); + while ((found = input.find(end_delimiter, pos)) != std::string::npos) { + StringExtractorGDBRemote profileDataExtractor( + input.substr(pos, found).c_str()); + std::string profile_data = + HarmonizeThreadIdsForProfileData(profileDataExtractor); + BroadcastAsyncProfileData(profile_data); + + pos = found + end_delimiter_len; + } + + if (pos < len) { + // Last incomplete chunk. + m_partial_profile_data = input.substr(pos); + } +} - if (response.IsErrorResponse()) - { - if (response.GetError() == 1) - { - // The file is not loaded into the inferior - is_loaded = false; - load_addr = LLDB_INVALID_ADDRESS; - return Error(); +std::string ProcessGDBRemote::HarmonizeThreadIdsForProfileData( + StringExtractorGDBRemote &profileDataExtractor) { + std::map<uint64_t, uint32_t> new_thread_id_to_used_usec_map; + std::string output; + llvm::raw_string_ostream output_stream(output); + llvm::StringRef name, value; + + // Going to assuming thread_used_usec comes first, else bail out. + while (profileDataExtractor.GetNameColonValue(name, value)) { + if (name.compare("thread_used_id") == 0) { + StringExtractor threadIDHexExtractor(value); + uint64_t thread_id = threadIDHexExtractor.GetHexMaxU64(false, 0); + + bool has_used_usec = false; + uint32_t curr_used_usec = 0; + llvm::StringRef usec_name, usec_value; + uint32_t input_file_pos = profileDataExtractor.GetFilePos(); + if (profileDataExtractor.GetNameColonValue(usec_name, usec_value)) { + if (usec_name.equals("thread_used_usec")) { + has_used_usec = true; + usec_value.getAsInteger(0, curr_used_usec); + } else { + // We didn't find what we want, it is probably + // an older version. Bail out. + profileDataExtractor.SetFilePos(input_file_pos); + } + } + + if (has_used_usec) { + uint32_t prev_used_usec = 0; + std::map<uint64_t, uint32_t>::iterator iterator = + m_thread_id_to_used_usec_map.find(thread_id); + if (iterator != m_thread_id_to_used_usec_map.end()) { + prev_used_usec = m_thread_id_to_used_usec_map[thread_id]; } - return Error("Fetching file load address from remote server returned an error"); - } + uint32_t real_used_usec = curr_used_usec - prev_used_usec; + // A good first time record is one that runs for at least 0.25 sec + bool good_first_time = + (prev_used_usec == 0) && (real_used_usec > 250000); + bool good_subsequent_time = + (prev_used_usec > 0) && + ((real_used_usec > 0) || (HasAssignedIndexIDToThread(thread_id))); + + if (good_first_time || good_subsequent_time) { + // We try to avoid doing too many index id reservation, + // resulting in fast increase of index ids. + + output_stream << name << ":"; + int32_t index_id = AssignIndexIDToThread(thread_id); + output_stream << index_id << ";"; + + output_stream << usec_name << ":" << usec_value << ";"; + } else { + // Skip past 'thread_used_name'. + llvm::StringRef local_name, local_value; + profileDataExtractor.GetNameColonValue(local_name, local_value); + } - if (response.IsNormalResponse()) - { - is_loaded = true; - load_addr = response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS); - return Error(); + // Store current time as previous time so that they can be compared + // later. + new_thread_id_to_used_usec_map[thread_id] = curr_used_usec; + } else { + // Bail out and use old string. + output_stream << name << ":" << value << ";"; + } + } else { + output_stream << name << ":" << value << ";"; } + } + output_stream << end_delimiter; + m_thread_id_to_used_usec_map = new_thread_id_to_used_usec_map; - return Error("Unknown error happened during sending the load address packet"); + return output_stream.str(); } +void ProcessGDBRemote::HandleStopReply() { + if (GetStopID() != 0) + return; -void -ProcessGDBRemote::ModulesDidLoad (ModuleList &module_list) -{ - // We must call the lldb_private::Process::ModulesDidLoad () first before we do anything - Process::ModulesDidLoad (module_list); - - // After loading shared libraries, we can ask our remote GDB server if - // it needs any symbols. - m_gdb_comm.ServeSymbolLookups(this); + if (GetID() == LLDB_INVALID_PROCESS_ID) { + lldb::pid_t pid = m_gdb_comm.GetCurrentProcessID(); + if (pid != LLDB_INVALID_PROCESS_ID) + SetID(pid); + } + BuildDynamicRegisterInfo(true); } - -class CommandObjectProcessGDBRemoteSpeedTest: public CommandObjectParsed -{ -public: - CommandObjectProcessGDBRemoteSpeedTest(CommandInterpreter &interpreter) : - CommandObjectParsed (interpreter, - "process plugin packet speed-test", - "Tests packet speeds of various sizes to determine the performance characteristics of the GDB remote connection. ", - NULL), - m_option_group (interpreter), - m_num_packets (LLDB_OPT_SET_1, false, "count", 'c', 0, eArgTypeCount, "The number of packets to send of each varying size (default is 1000).", 1000), - m_max_send (LLDB_OPT_SET_1, false, "max-send", 's', 0, eArgTypeCount, "The maximum number of bytes to send in a packet. Sizes increase in powers of 2 while the size is less than or equal to this option value. (default 1024).", 1024), - m_max_recv (LLDB_OPT_SET_1, false, "max-receive", 'r', 0, eArgTypeCount, "The maximum number of bytes to receive in a packet. Sizes increase in powers of 2 while the size is less than or equal to this option value. (default 1024).", 1024), - m_json (LLDB_OPT_SET_1, false, "json", 'j', "Print the output as JSON data for easy parsing.", false, true) - { - m_option_group.Append (&m_num_packets, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); - m_option_group.Append (&m_max_send, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); - m_option_group.Append (&m_max_recv, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); - m_option_group.Append (&m_json, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); - m_option_group.Finalize(); - } - - ~CommandObjectProcessGDBRemoteSpeedTest () - { +static const char *const s_async_json_packet_prefix = "JSON-async:"; + +static StructuredData::ObjectSP +ParseStructuredDataPacket(llvm::StringRef packet) { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + + if (!packet.consume_front(s_async_json_packet_prefix)) { + if (log) { + log->Printf( + "GDBRemoteCommmunicationClientBase::%s() received $J packet " + "but was not a StructuredData packet: packet starts with " + "%s", + __FUNCTION__, + packet.slice(0, strlen(s_async_json_packet_prefix)).str().c_str()); + } + return StructuredData::ObjectSP(); + } + + // This is an asynchronous JSON packet, destined for a + // StructuredDataPlugin. + StructuredData::ObjectSP json_sp = StructuredData::ParseJSON(packet); + if (log) { + if (json_sp) { + StreamString json_str; + json_sp->Dump(json_str); + json_str.Flush(); + log->Printf("ProcessGDBRemote::%s() " + "received Async StructuredData packet: %s", + __FUNCTION__, json_str.GetData()); + } else { + log->Printf("ProcessGDBRemote::%s" + "() received StructuredData packet:" + " parse failure", + __FUNCTION__); } + } + return json_sp; +} +void ProcessGDBRemote::HandleAsyncStructuredDataPacket(llvm::StringRef data) { + auto structured_data_sp = ParseStructuredDataPacket(data); + if (structured_data_sp) + RouteAsyncStructuredData(structured_data_sp); +} - Options * - GetOptions () override - { - return &m_option_group; +class CommandObjectProcessGDBRemoteSpeedTest : public CommandObjectParsed { +public: + CommandObjectProcessGDBRemoteSpeedTest(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "process plugin packet speed-test", + "Tests packet speeds of various sizes to determine " + "the performance characteristics of the GDB remote " + "connection. ", + NULL), + m_option_group(), + m_num_packets(LLDB_OPT_SET_1, false, "count", 'c', 0, eArgTypeCount, + "The number of packets to send of each varying size " + "(default is 1000).", + 1000), + m_max_send(LLDB_OPT_SET_1, false, "max-send", 's', 0, eArgTypeCount, + "The maximum number of bytes to send in a packet. Sizes " + "increase in powers of 2 while the size is less than or " + "equal to this option value. (default 1024).", + 1024), + m_max_recv(LLDB_OPT_SET_1, false, "max-receive", 'r', 0, eArgTypeCount, + "The maximum number of bytes to receive in a packet. Sizes " + "increase in powers of 2 while the size is less than or " + "equal to this option value. (default 1024).", + 1024), + m_json(LLDB_OPT_SET_1, false, "json", 'j', + "Print the output as JSON data for easy parsing.", false, true) { + m_option_group.Append(&m_num_packets, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); + m_option_group.Append(&m_max_send, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); + m_option_group.Append(&m_max_recv, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); + m_option_group.Append(&m_json, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); + m_option_group.Finalize(); + } + + ~CommandObjectProcessGDBRemoteSpeedTest() {} + + Options *GetOptions() override { return &m_option_group; } + + bool DoExecute(Args &command, CommandReturnObject &result) override { + const size_t argc = command.GetArgumentCount(); + if (argc == 0) { + ProcessGDBRemote *process = + (ProcessGDBRemote *)m_interpreter.GetExecutionContext() + .GetProcessPtr(); + if (process) { + StreamSP output_stream_sp( + m_interpreter.GetDebugger().GetAsyncOutputStream()); + result.SetImmediateOutputStream(output_stream_sp); + + const uint32_t num_packets = + (uint32_t)m_num_packets.GetOptionValue().GetCurrentValue(); + const uint64_t max_send = m_max_send.GetOptionValue().GetCurrentValue(); + const uint64_t max_recv = m_max_recv.GetOptionValue().GetCurrentValue(); + const bool json = m_json.GetOptionValue().GetCurrentValue(); + const uint64_t k_recv_amount = + 4 * 1024 * 1024; // Receive amount in bytes + process->GetGDBRemote().TestPacketSpeed( + num_packets, max_send, max_recv, k_recv_amount, json, + output_stream_sp ? *output_stream_sp : result.GetOutputStream()); + result.SetStatus(eReturnStatusSuccessFinishResult); + return true; + } + } else { + result.AppendErrorWithFormat("'%s' takes no arguments", + m_cmd_name.c_str()); } + result.SetStatus(eReturnStatusFailed); + return false; + } - bool - DoExecute (Args& command, CommandReturnObject &result) override - { - const size_t argc = command.GetArgumentCount(); - if (argc == 0) - { - ProcessGDBRemote *process = (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr(); - if (process) - { - StreamSP output_stream_sp (m_interpreter.GetDebugger().GetAsyncOutputStream()); - result.SetImmediateOutputStream (output_stream_sp); - - const uint32_t num_packets = (uint32_t)m_num_packets.GetOptionValue().GetCurrentValue(); - const uint64_t max_send = m_max_send.GetOptionValue().GetCurrentValue(); - const uint64_t max_recv = m_max_recv.GetOptionValue().GetCurrentValue(); - const bool json = m_json.GetOptionValue().GetCurrentValue(); - if (output_stream_sp) - process->GetGDBRemote().TestPacketSpeed (num_packets, max_send, max_recv, json, *output_stream_sp); - else - { - process->GetGDBRemote().TestPacketSpeed (num_packets, max_send, max_recv, json, result.GetOutputStream()); - } - result.SetStatus (eReturnStatusSuccessFinishResult); - return true; - } - } - else - { - result.AppendErrorWithFormat ("'%s' takes no arguments", m_cmd_name.c_str()); - } - result.SetStatus (eReturnStatusFailed); - return false; - } protected: - OptionGroupOptions m_option_group; - OptionGroupUInt64 m_num_packets; - OptionGroupUInt64 m_max_send; - OptionGroupUInt64 m_max_recv; - OptionGroupBoolean m_json; - + OptionGroupOptions m_option_group; + OptionGroupUInt64 m_num_packets; + OptionGroupUInt64 m_max_send; + OptionGroupUInt64 m_max_recv; + OptionGroupBoolean m_json; }; -class CommandObjectProcessGDBRemotePacketHistory : public CommandObjectParsed -{ +class CommandObjectProcessGDBRemotePacketHistory : public CommandObjectParsed { private: - public: - CommandObjectProcessGDBRemotePacketHistory(CommandInterpreter &interpreter) : - CommandObjectParsed (interpreter, - "process plugin packet history", - "Dumps the packet history buffer. ", - NULL) - { - } - - ~CommandObjectProcessGDBRemotePacketHistory () - { - } - - bool - DoExecute (Args& command, CommandReturnObject &result) override - { - const size_t argc = command.GetArgumentCount(); - if (argc == 0) - { - ProcessGDBRemote *process = (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr(); - if (process) - { - process->GetGDBRemote().DumpHistory(result.GetOutputStream()); - result.SetStatus (eReturnStatusSuccessFinishResult); - return true; - } - } - else - { - result.AppendErrorWithFormat ("'%s' takes no arguments", m_cmd_name.c_str()); - } - result.SetStatus (eReturnStatusFailed); - return false; + CommandObjectProcessGDBRemotePacketHistory(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "process plugin packet history", + "Dumps the packet history buffer. ", NULL) {} + + ~CommandObjectProcessGDBRemotePacketHistory() {} + + bool DoExecute(Args &command, CommandReturnObject &result) override { + const size_t argc = command.GetArgumentCount(); + if (argc == 0) { + ProcessGDBRemote *process = + (ProcessGDBRemote *)m_interpreter.GetExecutionContext() + .GetProcessPtr(); + if (process) { + process->GetGDBRemote().DumpHistory(result.GetOutputStream()); + result.SetStatus(eReturnStatusSuccessFinishResult); + return true; + } + } else { + result.AppendErrorWithFormat("'%s' takes no arguments", + m_cmd_name.c_str()); } + result.SetStatus(eReturnStatusFailed); + return false; + } }; -class CommandObjectProcessGDBRemotePacketXferSize : public CommandObjectParsed -{ +class CommandObjectProcessGDBRemotePacketXferSize : public CommandObjectParsed { private: - public: - CommandObjectProcessGDBRemotePacketXferSize(CommandInterpreter &interpreter) : - CommandObjectParsed (interpreter, - "process plugin packet xfer-size", - "Maximum size that lldb will try to read/write one one chunk.", - NULL) - { - } - - ~CommandObjectProcessGDBRemotePacketXferSize () - { - } - - bool - DoExecute (Args& command, CommandReturnObject &result) override - { - const size_t argc = command.GetArgumentCount(); - if (argc == 0) - { - result.AppendErrorWithFormat ("'%s' takes an argument to specify the max amount to be transferred when reading/writing", m_cmd_name.c_str()); - result.SetStatus (eReturnStatusFailed); - return false; - } - - ProcessGDBRemote *process = (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr(); - if (process) - { - const char *packet_size = command.GetArgumentAtIndex(0); - errno = 0; - uint64_t user_specified_max = strtoul (packet_size, NULL, 10); - if (errno == 0 && user_specified_max != 0) - { - process->SetUserSpecifiedMaxMemoryTransferSize (user_specified_max); - result.SetStatus (eReturnStatusSuccessFinishResult); - return true; - } - } - result.SetStatus (eReturnStatusFailed); - return false; + CommandObjectProcessGDBRemotePacketXferSize(CommandInterpreter &interpreter) + : CommandObjectParsed( + interpreter, "process plugin packet xfer-size", + "Maximum size that lldb will try to read/write one one chunk.", + NULL) {} + + ~CommandObjectProcessGDBRemotePacketXferSize() {} + + bool DoExecute(Args &command, CommandReturnObject &result) override { + const size_t argc = command.GetArgumentCount(); + if (argc == 0) { + result.AppendErrorWithFormat("'%s' takes an argument to specify the max " + "amount to be transferred when " + "reading/writing", + m_cmd_name.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + + ProcessGDBRemote *process = + (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr(); + if (process) { + const char *packet_size = command.GetArgumentAtIndex(0); + errno = 0; + uint64_t user_specified_max = strtoul(packet_size, NULL, 10); + if (errno == 0 && user_specified_max != 0) { + process->SetUserSpecifiedMaxMemoryTransferSize(user_specified_max); + result.SetStatus(eReturnStatusSuccessFinishResult); + return true; + } } + result.SetStatus(eReturnStatusFailed); + return false; + } }; - -class CommandObjectProcessGDBRemotePacketSend : public CommandObjectParsed -{ +class CommandObjectProcessGDBRemotePacketSend : public CommandObjectParsed { private: - public: - CommandObjectProcessGDBRemotePacketSend(CommandInterpreter &interpreter) : - CommandObjectParsed (interpreter, - "process plugin packet send", - "Send a custom packet through the GDB remote protocol and print the answer. " - "The packet header and footer will automatically be added to the packet prior to sending and stripped from the result.", - NULL) - { - } - - ~CommandObjectProcessGDBRemotePacketSend () - { - } - - bool - DoExecute (Args& command, CommandReturnObject &result) override - { - const size_t argc = command.GetArgumentCount(); - if (argc == 0) - { - result.AppendErrorWithFormat ("'%s' takes a one or more packet content arguments", m_cmd_name.c_str()); - result.SetStatus (eReturnStatusFailed); - return false; + CommandObjectProcessGDBRemotePacketSend(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "process plugin packet send", + "Send a custom packet through the GDB remote " + "protocol and print the answer. " + "The packet header and footer will automatically " + "be added to the packet prior to sending and " + "stripped from the result.", + NULL) {} + + ~CommandObjectProcessGDBRemotePacketSend() {} + + bool DoExecute(Args &command, CommandReturnObject &result) override { + const size_t argc = command.GetArgumentCount(); + if (argc == 0) { + result.AppendErrorWithFormat( + "'%s' takes a one or more packet content arguments", + m_cmd_name.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + + ProcessGDBRemote *process = + (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr(); + if (process) { + for (size_t i = 0; i < argc; ++i) { + const char *packet_cstr = command.GetArgumentAtIndex(0); + bool send_async = true; + StringExtractorGDBRemote response; + process->GetGDBRemote().SendPacketAndWaitForResponse( + packet_cstr, response, send_async); + result.SetStatus(eReturnStatusSuccessFinishResult); + Stream &output_strm = result.GetOutputStream(); + output_strm.Printf(" packet: %s\n", packet_cstr); + std::string &response_str = response.GetStringRef(); + + if (strstr(packet_cstr, "qGetProfileData") != NULL) { + response_str = process->HarmonizeThreadIdsForProfileData(response); } - ProcessGDBRemote *process = (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr(); - if (process) - { - for (size_t i=0; i<argc; ++ i) - { - const char *packet_cstr = command.GetArgumentAtIndex(0); - bool send_async = true; - StringExtractorGDBRemote response; - process->GetGDBRemote().SendPacketAndWaitForResponse(packet_cstr, response, send_async); - result.SetStatus (eReturnStatusSuccessFinishResult); - Stream &output_strm = result.GetOutputStream(); - output_strm.Printf (" packet: %s\n", packet_cstr); - std::string &response_str = response.GetStringRef(); - - if (strstr(packet_cstr, "qGetProfileData") != NULL) - { - response_str = process->GetGDBRemote().HarmonizeThreadIdsForProfileData(process, response); - } - - if (response_str.empty()) - output_strm.PutCString ("response: \nerror: UNIMPLEMENTED\n"); - else - output_strm.Printf ("response: %s\n", response.GetStringRef().c_str()); - } - } - return true; + if (response_str.empty()) + output_strm.PutCString("response: \nerror: UNIMPLEMENTED\n"); + else + output_strm.Printf("response: %s\n", response.GetStringRef().c_str()); + } } + return true; + } }; -class CommandObjectProcessGDBRemotePacketMonitor : public CommandObjectRaw -{ +class CommandObjectProcessGDBRemotePacketMonitor : public CommandObjectRaw { private: - public: - CommandObjectProcessGDBRemotePacketMonitor(CommandInterpreter &interpreter) : - CommandObjectRaw (interpreter, - "process plugin packet monitor", - "Send a qRcmd packet through the GDB remote protocol and print the response." - "The argument passed to this command will be hex encoded into a valid 'qRcmd' packet, sent and the response will be printed.", - NULL) - { - } - - ~CommandObjectProcessGDBRemotePacketMonitor () - { - } - - bool - DoExecute (const char *command, CommandReturnObject &result) override - { - if (command == NULL || command[0] == '\0') - { - result.AppendErrorWithFormat ("'%s' takes a command string argument", m_cmd_name.c_str()); - result.SetStatus (eReturnStatusFailed); - return false; - } - - ProcessGDBRemote *process = (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr(); - if (process) - { - StreamString packet; - packet.PutCString("qRcmd,"); - packet.PutBytesAsRawHex8(command, strlen(command)); - const char *packet_cstr = packet.GetString().c_str(); - - bool send_async = true; - StringExtractorGDBRemote response; - process->GetGDBRemote().SendPacketAndWaitForResponse(packet_cstr, response, send_async); - result.SetStatus (eReturnStatusSuccessFinishResult); - Stream &output_strm = result.GetOutputStream(); - output_strm.Printf (" packet: %s\n", packet_cstr); - const std::string &response_str = response.GetStringRef(); - - if (response_str.empty()) - output_strm.PutCString ("response: \nerror: UNIMPLEMENTED\n"); - else - output_strm.Printf ("response: %s\n", response.GetStringRef().c_str()); - } - return true; + CommandObjectProcessGDBRemotePacketMonitor(CommandInterpreter &interpreter) + : CommandObjectRaw(interpreter, "process plugin packet monitor", + "Send a qRcmd packet through the GDB remote protocol " + "and print the response." + "The argument passed to this command will be hex " + "encoded into a valid 'qRcmd' packet, sent and the " + "response will be printed.") {} + + ~CommandObjectProcessGDBRemotePacketMonitor() {} + + bool DoExecute(const char *command, CommandReturnObject &result) override { + if (command == NULL || command[0] == '\0') { + result.AppendErrorWithFormat("'%s' takes a command string argument", + m_cmd_name.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + + ProcessGDBRemote *process = + (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr(); + if (process) { + StreamString packet; + packet.PutCString("qRcmd,"); + packet.PutBytesAsRawHex8(command, strlen(command)); + + bool send_async = true; + StringExtractorGDBRemote response; + process->GetGDBRemote().SendPacketAndWaitForResponse( + packet.GetString(), response, send_async); + result.SetStatus(eReturnStatusSuccessFinishResult); + Stream &output_strm = result.GetOutputStream(); + output_strm.Printf(" packet: %s\n", packet.GetData()); + const std::string &response_str = response.GetStringRef(); + + if (response_str.empty()) + output_strm.PutCString("response: \nerror: UNIMPLEMENTED\n"); + else + output_strm.Printf("response: %s\n", response.GetStringRef().c_str()); } + return true; + } }; -class CommandObjectProcessGDBRemotePacket : public CommandObjectMultiword -{ +class CommandObjectProcessGDBRemotePacket : public CommandObjectMultiword { private: - public: - CommandObjectProcessGDBRemotePacket(CommandInterpreter &interpreter) : - CommandObjectMultiword (interpreter, - "process plugin packet", - "Commands that deal with GDB remote packets.", - NULL) - { - LoadSubCommand ("history", CommandObjectSP (new CommandObjectProcessGDBRemotePacketHistory (interpreter))); - LoadSubCommand ("send", CommandObjectSP (new CommandObjectProcessGDBRemotePacketSend (interpreter))); - LoadSubCommand ("monitor", CommandObjectSP (new CommandObjectProcessGDBRemotePacketMonitor (interpreter))); - LoadSubCommand ("xfer-size", CommandObjectSP (new CommandObjectProcessGDBRemotePacketXferSize (interpreter))); - LoadSubCommand ("speed-test", CommandObjectSP (new CommandObjectProcessGDBRemoteSpeedTest (interpreter))); - } - - ~CommandObjectProcessGDBRemotePacket () - { - } + CommandObjectProcessGDBRemotePacket(CommandInterpreter &interpreter) + : CommandObjectMultiword(interpreter, "process plugin packet", + "Commands that deal with GDB remote packets.", + NULL) { + LoadSubCommand( + "history", + CommandObjectSP( + new CommandObjectProcessGDBRemotePacketHistory(interpreter))); + LoadSubCommand( + "send", CommandObjectSP( + new CommandObjectProcessGDBRemotePacketSend(interpreter))); + LoadSubCommand( + "monitor", + CommandObjectSP( + new CommandObjectProcessGDBRemotePacketMonitor(interpreter))); + LoadSubCommand( + "xfer-size", + CommandObjectSP( + new CommandObjectProcessGDBRemotePacketXferSize(interpreter))); + LoadSubCommand("speed-test", + CommandObjectSP(new CommandObjectProcessGDBRemoteSpeedTest( + interpreter))); + } + + ~CommandObjectProcessGDBRemotePacket() {} }; -class CommandObjectMultiwordProcessGDBRemote : public CommandObjectMultiword -{ +class CommandObjectMultiwordProcessGDBRemote : public CommandObjectMultiword { public: - CommandObjectMultiwordProcessGDBRemote(CommandInterpreter &interpreter) - : CommandObjectMultiword(interpreter, "process plugin", "Commands for operating on a ProcessGDBRemote process.", - "process plugin <subcommand> [<subcommand-options>]") - { - LoadSubCommand ("packet", CommandObjectSP (new CommandObjectProcessGDBRemotePacket (interpreter))); - } - - ~CommandObjectMultiwordProcessGDBRemote () - { - } + CommandObjectMultiwordProcessGDBRemote(CommandInterpreter &interpreter) + : CommandObjectMultiword( + interpreter, "process plugin", + "Commands for operating on a ProcessGDBRemote process.", + "process plugin <subcommand> [<subcommand-options>]") { + LoadSubCommand( + "packet", + CommandObjectSP(new CommandObjectProcessGDBRemotePacket(interpreter))); + } + + ~CommandObjectMultiwordProcessGDBRemote() {} }; -CommandObject * -ProcessGDBRemote::GetPluginCommandObject() -{ - if (!m_command_sp) - m_command_sp.reset (new CommandObjectMultiwordProcessGDBRemote (GetTarget().GetDebugger().GetCommandInterpreter())); - return m_command_sp.get(); +CommandObject *ProcessGDBRemote::GetPluginCommandObject() { + if (!m_command_sp) + m_command_sp.reset(new CommandObjectMultiwordProcessGDBRemote( + GetTarget().GetDebugger().GetCommandInterpreter())); + return m_command_sp.get(); } diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 6d37396..6423abc 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -24,462 +24,425 @@ #include "lldb/Core/Broadcaster.h" #include "lldb/Core/ConstString.h" #include "lldb/Core/Error.h" +#include "lldb/Core/LoadedModuleInfoList.h" +#include "lldb/Core/ModuleSpec.h" #include "lldb/Core/StreamString.h" #include "lldb/Core/StringList.h" #include "lldb/Core/StructuredData.h" #include "lldb/Core/ThreadSafeValue.h" -#include "lldb/Core/LoadedModuleInfoList.h" #include "lldb/Host/HostThread.h" -#include "lldb/lldb-private-forward.h" -#include "lldb/Utility/StringExtractor.h" #include "lldb/Target/Process.h" #include "lldb/Target/Thread.h" +#include "lldb/Utility/StringExtractor.h" +#include "lldb/lldb-private-forward.h" #include "GDBRemoteCommunicationClient.h" #include "GDBRemoteRegisterContext.h" +#include "llvm/ADT/DenseMap.h" + namespace lldb_private { namespace process_gdb_remote { class ThreadGDBRemote; -class ProcessGDBRemote : public Process -{ +class ProcessGDBRemote : public Process, + private GDBRemoteClientBase::ContinueDelegate { public: - ProcessGDBRemote(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp); + ProcessGDBRemote(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp); - ~ProcessGDBRemote() override; + ~ProcessGDBRemote() override; - static lldb::ProcessSP - CreateInstance (lldb::TargetSP target_sp, - lldb::ListenerSP listener_sp, - const FileSpec *crash_file_path); + static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp, + lldb::ListenerSP listener_sp, + const FileSpec *crash_file_path); - static void - Initialize(); + static void Initialize(); - static void - DebuggerInitialize (Debugger &debugger); + static void DebuggerInitialize(Debugger &debugger); - static void - Terminate(); + static void Terminate(); - static ConstString - GetPluginNameStatic(); + static ConstString GetPluginNameStatic(); - static const char * - GetPluginDescriptionStatic(); + static const char *GetPluginDescriptionStatic(); - //------------------------------------------------------------------ - // Check if a given Process - //------------------------------------------------------------------ - bool - CanDebug (lldb::TargetSP target_sp, bool plugin_specified_by_name) override; + //------------------------------------------------------------------ + // Check if a given Process + //------------------------------------------------------------------ + bool CanDebug(lldb::TargetSP target_sp, + bool plugin_specified_by_name) override; - CommandObject * - GetPluginCommandObject() override; + CommandObject *GetPluginCommandObject() override; - //------------------------------------------------------------------ - // Creating a new process, or attaching to an existing one - //------------------------------------------------------------------ - Error - WillLaunch (Module* module) override; + //------------------------------------------------------------------ + // Creating a new process, or attaching to an existing one + //------------------------------------------------------------------ + Error WillLaunch(Module *module) override; - Error - DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info) override; + Error DoLaunch(Module *exe_module, ProcessLaunchInfo &launch_info) override; - void - DidLaunch () override; - - Error - WillAttachToProcessWithID (lldb::pid_t pid) override; - - Error - WillAttachToProcessWithName (const char *process_name, bool wait_for_launch) override; + void DidLaunch() override; - Error - DoConnectRemote (Stream *strm, const char *remote_url) override; - - Error - WillLaunchOrAttach (); - - Error - DoAttachToProcessWithID (lldb::pid_t pid, const ProcessAttachInfo &attach_info) override; - - Error - DoAttachToProcessWithName (const char *process_name, - const ProcessAttachInfo &attach_info) override; - - void - DidAttach (ArchSpec &process_arch) override; - - //------------------------------------------------------------------ - // PluginInterface protocol - //------------------------------------------------------------------ - ConstString - GetPluginName() override; - - uint32_t - GetPluginVersion() override; - - //------------------------------------------------------------------ - // Process Control - //------------------------------------------------------------------ - Error - WillResume () override; - - Error - DoResume () override; - - Error - DoHalt (bool &caused_stop) override; - - Error - DoDetach (bool keep_stopped) override; - - bool - DetachRequiresHalt() override { return true; } - - Error - DoSignal (int signal) override; - - Error - DoDestroy () override; - - void - RefreshStateAfterStop() override; - - void - SetUnixSignals(const lldb::UnixSignalsSP &signals_sp); - - //------------------------------------------------------------------ - // Process Queries - //------------------------------------------------------------------ - bool - IsAlive () override; - - lldb::addr_t - GetImageInfoAddress() override; - - void - WillPublicStop () override; - - //------------------------------------------------------------------ - // Process Memory - //------------------------------------------------------------------ - size_t - DoReadMemory (lldb::addr_t addr, void *buf, size_t size, Error &error) override; - - size_t - DoWriteMemory (lldb::addr_t addr, const void *buf, size_t size, Error &error) override; - - lldb::addr_t - DoAllocateMemory (size_t size, uint32_t permissions, Error &error) override; - - Error - GetMemoryRegionInfo (lldb::addr_t load_addr, MemoryRegionInfo ®ion_info) override; - - Error - DoDeallocateMemory (lldb::addr_t ptr) override; - - //------------------------------------------------------------------ - // Process STDIO - //------------------------------------------------------------------ - size_t - PutSTDIN (const char *buf, size_t buf_size, Error &error) override; - - //---------------------------------------------------------------------- - // Process Breakpoints - //---------------------------------------------------------------------- - Error - EnableBreakpointSite (BreakpointSite *bp_site) override; - - Error - DisableBreakpointSite (BreakpointSite *bp_site) override; - - //---------------------------------------------------------------------- - // Process Watchpoints - //---------------------------------------------------------------------- - Error - EnableWatchpoint (Watchpoint *wp, bool notify = true) override; - - Error - DisableWatchpoint (Watchpoint *wp, bool notify = true) override; - - Error - GetWatchpointSupportInfo (uint32_t &num) override; - - Error - GetWatchpointSupportInfo (uint32_t &num, bool& after) override; - - bool - StartNoticingNewThreads() override; - - bool - StopNoticingNewThreads() override; - - GDBRemoteCommunicationClient & - GetGDBRemote() - { - return m_gdb_comm; - } - - Error - SendEventData(const char *data) override; + Error WillAttachToProcessWithID(lldb::pid_t pid) override; + + Error WillAttachToProcessWithName(const char *process_name, + bool wait_for_launch) override; + + Error DoConnectRemote(Stream *strm, llvm::StringRef remote_url) override; + + Error WillLaunchOrAttach(); + + Error DoAttachToProcessWithID(lldb::pid_t pid, + const ProcessAttachInfo &attach_info) override; + + Error + DoAttachToProcessWithName(const char *process_name, + const ProcessAttachInfo &attach_info) override; + + void DidAttach(ArchSpec &process_arch) override; + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + ConstString GetPluginName() override; + + uint32_t GetPluginVersion() override; + + //------------------------------------------------------------------ + // Process Control + //------------------------------------------------------------------ + Error WillResume() override; + + Error DoResume() override; + + Error DoHalt(bool &caused_stop) override; + + Error DoDetach(bool keep_stopped) override; + + bool DetachRequiresHalt() override { return true; } + + Error DoSignal(int signal) override; + + Error DoDestroy() override; + + void RefreshStateAfterStop() override; + + void SetUnixSignals(const lldb::UnixSignalsSP &signals_sp); + + //------------------------------------------------------------------ + // Process Queries + //------------------------------------------------------------------ + bool IsAlive() override; + + lldb::addr_t GetImageInfoAddress() override; + + void WillPublicStop() override; + + //------------------------------------------------------------------ + // Process Memory + //------------------------------------------------------------------ + size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size, + Error &error) override; + + size_t DoWriteMemory(lldb::addr_t addr, const void *buf, size_t size, + Error &error) override; + + lldb::addr_t DoAllocateMemory(size_t size, uint32_t permissions, + Error &error) override; + + Error GetMemoryRegionInfo(lldb::addr_t load_addr, + MemoryRegionInfo ®ion_info) override; - //---------------------------------------------------------------------- - // Override DidExit so we can disconnect from the remote GDB server - //---------------------------------------------------------------------- - void - DidExit () override; + Error DoDeallocateMemory(lldb::addr_t ptr) override; - void - SetUserSpecifiedMaxMemoryTransferSize (uint64_t user_specified_max); + //------------------------------------------------------------------ + // Process STDIO + //------------------------------------------------------------------ + size_t PutSTDIN(const char *buf, size_t buf_size, Error &error) override; - bool - GetModuleSpec(const FileSpec& module_file_spec, - const ArchSpec& arch, - ModuleSpec &module_spec) override; + //---------------------------------------------------------------------- + // Process Breakpoints + //---------------------------------------------------------------------- + Error EnableBreakpointSite(BreakpointSite *bp_site) override; - bool - GetHostOSVersion(uint32_t &major, - uint32_t &minor, - uint32_t &update) override; + Error DisableBreakpointSite(BreakpointSite *bp_site) override; - size_t - LoadModules(LoadedModuleInfoList &module_list) override; + //---------------------------------------------------------------------- + // Process Watchpoints + //---------------------------------------------------------------------- + Error EnableWatchpoint(Watchpoint *wp, bool notify = true) override; - size_t - LoadModules() override; + Error DisableWatchpoint(Watchpoint *wp, bool notify = true) override; - Error - GetFileLoadAddress(const FileSpec& file, bool& is_loaded, lldb::addr_t& load_addr) override; + Error GetWatchpointSupportInfo(uint32_t &num) override; - void - ModulesDidLoad (ModuleList &module_list) override; + Error GetWatchpointSupportInfo(uint32_t &num, bool &after) override; - StructuredData::ObjectSP - GetLoadedDynamicLibrariesInfos (lldb::addr_t image_list_address, lldb::addr_t image_count) override; + bool StartNoticingNewThreads() override; + + bool StopNoticingNewThreads() override; + + GDBRemoteCommunicationClient &GetGDBRemote() { return m_gdb_comm; } + + Error SendEventData(const char *data) override; + + //---------------------------------------------------------------------- + // Override DidExit so we can disconnect from the remote GDB server + //---------------------------------------------------------------------- + void DidExit() override; + + void SetUserSpecifiedMaxMemoryTransferSize(uint64_t user_specified_max); + + bool GetModuleSpec(const FileSpec &module_file_spec, const ArchSpec &arch, + ModuleSpec &module_spec) override; + + void PrefetchModuleSpecs(llvm::ArrayRef<FileSpec> module_file_specs, + const llvm::Triple &triple) override; + + bool GetHostOSVersion(uint32_t &major, uint32_t &minor, + uint32_t &update) override; + + size_t LoadModules(LoadedModuleInfoList &module_list) override; + + size_t LoadModules() override; + + Error GetFileLoadAddress(const FileSpec &file, bool &is_loaded, + lldb::addr_t &load_addr) override; + + void ModulesDidLoad(ModuleList &module_list) override; + + StructuredData::ObjectSP + GetLoadedDynamicLibrariesInfos(lldb::addr_t image_list_address, + lldb::addr_t image_count) override; + + Error + ConfigureStructuredData(const ConstString &type_name, + const StructuredData::ObjectSP &config_sp) override; + + StructuredData::ObjectSP GetLoadedDynamicLibrariesInfos() override; + + StructuredData::ObjectSP GetLoadedDynamicLibrariesInfos( + const std::vector<lldb::addr_t> &load_addresses) override; + + StructuredData::ObjectSP + GetLoadedDynamicLibrariesInfos_sender(StructuredData::ObjectSP args); + + StructuredData::ObjectSP GetSharedCacheInfo() override; + + std::string HarmonizeThreadIdsForProfileData( + StringExtractorGDBRemote &inputStringExtractor); protected: - friend class ThreadGDBRemote; - friend class GDBRemoteCommunicationClient; - friend class GDBRemoteRegisterContext; - - //------------------------------------------------------------------ - /// Broadcaster event bits definitions. - //------------------------------------------------------------------ - enum - { - eBroadcastBitAsyncContinue = (1 << 0), - eBroadcastBitAsyncThreadShouldExit = (1 << 1), - eBroadcastBitAsyncThreadDidExit = (1 << 2) - }; - - Flags m_flags; // Process specific flags (see eFlags enums) - GDBRemoteCommunicationClient m_gdb_comm; - std::atomic<lldb::pid_t> m_debugserver_pid; - std::vector<StringExtractorGDBRemote> m_stop_packet_stack; // The stop packet stack replaces the last stop packet variable - std::recursive_mutex m_last_stop_packet_mutex; - GDBRemoteDynamicRegisterInfo m_register_info; - Broadcaster m_async_broadcaster; - lldb::ListenerSP m_async_listener_sp; - HostThread m_async_thread; - std::recursive_mutex m_async_thread_state_mutex; - typedef std::vector<lldb::tid_t> tid_collection; - typedef std::vector< std::pair<lldb::tid_t,int> > tid_sig_collection; - typedef std::map<lldb::addr_t, lldb::addr_t> MMapMap; - typedef std::map<uint32_t, std::string> ExpeditedRegisterMap; - tid_collection m_thread_ids; // Thread IDs for all threads. This list gets updated after stopping - std::vector<lldb::addr_t> m_thread_pcs; // PC values for all the threads. - StructuredData::ObjectSP m_jstopinfo_sp; // Stop info only for any threads that have valid stop infos - StructuredData::ObjectSP m_jthreadsinfo_sp; // Full stop info, expedited registers and memory for all threads if "jThreadsInfo" packet is supported - tid_collection m_continue_c_tids; // 'c' for continue - tid_sig_collection m_continue_C_tids; // 'C' for continue with signal - tid_collection m_continue_s_tids; // 's' for step - tid_sig_collection m_continue_S_tids; // 'S' for step with signal - uint64_t m_max_memory_size; // The maximum number of bytes to read/write when reading and writing memory - uint64_t m_remote_stub_max_memory_size; // The maximum memory size the remote gdb stub can handle - MMapMap m_addr_to_mmap_size; - lldb::BreakpointSP m_thread_create_bp_sp; - bool m_waiting_for_attach; - bool m_destroy_tried_resuming; - lldb::CommandObjectSP m_command_sp; - int64_t m_breakpoint_pc_offset; - lldb::tid_t m_initial_tid; // The initial thread ID, given by stub on attach - - //---------------------------------------------------------------------- - // Accessors - //---------------------------------------------------------------------- - bool - IsRunning ( lldb::StateType state ) - { - return state == lldb::eStateRunning || IsStepping(state); - } + friend class ThreadGDBRemote; + friend class GDBRemoteCommunicationClient; + friend class GDBRemoteRegisterContext; + + //------------------------------------------------------------------ + /// Broadcaster event bits definitions. + //------------------------------------------------------------------ + enum { + eBroadcastBitAsyncContinue = (1 << 0), + eBroadcastBitAsyncThreadShouldExit = (1 << 1), + eBroadcastBitAsyncThreadDidExit = (1 << 2) + }; - bool - IsStepping ( lldb::StateType state) - { - return state == lldb::eStateStepping; - } + Flags m_flags; // Process specific flags (see eFlags enums) + GDBRemoteCommunicationClient m_gdb_comm; + std::atomic<lldb::pid_t> m_debugserver_pid; + std::vector<StringExtractorGDBRemote> m_stop_packet_stack; // The stop packet + // stack replaces + // the last stop + // packet variable + std::recursive_mutex m_last_stop_packet_mutex; + GDBRemoteDynamicRegisterInfo m_register_info; + Broadcaster m_async_broadcaster; + lldb::ListenerSP m_async_listener_sp; + HostThread m_async_thread; + std::recursive_mutex m_async_thread_state_mutex; + typedef std::vector<lldb::tid_t> tid_collection; + typedef std::vector<std::pair<lldb::tid_t, int>> tid_sig_collection; + typedef std::map<lldb::addr_t, lldb::addr_t> MMapMap; + typedef std::map<uint32_t, std::string> ExpeditedRegisterMap; + tid_collection m_thread_ids; // Thread IDs for all threads. This list gets + // updated after stopping + std::vector<lldb::addr_t> m_thread_pcs; // PC values for all the threads. + StructuredData::ObjectSP m_jstopinfo_sp; // Stop info only for any threads + // that have valid stop infos + StructuredData::ObjectSP m_jthreadsinfo_sp; // Full stop info, expedited + // registers and memory for all + // threads if "jThreadsInfo" + // packet is supported + tid_collection m_continue_c_tids; // 'c' for continue + tid_sig_collection m_continue_C_tids; // 'C' for continue with signal + tid_collection m_continue_s_tids; // 's' for step + tid_sig_collection m_continue_S_tids; // 'S' for step with signal + uint64_t m_max_memory_size; // The maximum number of bytes to read/write when + // reading and writing memory + uint64_t m_remote_stub_max_memory_size; // The maximum memory size the remote + // gdb stub can handle + MMapMap m_addr_to_mmap_size; + lldb::BreakpointSP m_thread_create_bp_sp; + bool m_waiting_for_attach; + bool m_destroy_tried_resuming; + lldb::CommandObjectSP m_command_sp; + int64_t m_breakpoint_pc_offset; + lldb::tid_t m_initial_tid; // The initial thread ID, given by stub on attach - bool - CanResume ( lldb::StateType state) - { - return state == lldb::eStateStopped; - } + //---------------------------------------------------------------------- + // Accessors + //---------------------------------------------------------------------- + bool IsRunning(lldb::StateType state) { + return state == lldb::eStateRunning || IsStepping(state); + } - bool - HasExited (lldb::StateType state) - { - return state == lldb::eStateExited; - } + bool IsStepping(lldb::StateType state) { + return state == lldb::eStateStepping; + } - bool - ProcessIDIsValid ( ) const; + bool CanResume(lldb::StateType state) { return state == lldb::eStateStopped; } - void - Clear ( ); + bool HasExited(lldb::StateType state) { return state == lldb::eStateExited; } - Flags & - GetFlags () - { - return m_flags; - } + bool ProcessIDIsValid() const; - const Flags & - GetFlags () const - { - return m_flags; - } + void Clear(); + + Flags &GetFlags() { return m_flags; } - bool - UpdateThreadList (ThreadList &old_thread_list, - ThreadList &new_thread_list) override; + const Flags &GetFlags() const { return m_flags; } - Error - EstablishConnectionIfNeeded (const ProcessInfo &process_info); + bool UpdateThreadList(ThreadList &old_thread_list, + ThreadList &new_thread_list) override; - Error - LaunchAndConnectToDebugserver (const ProcessInfo &process_info); + Error EstablishConnectionIfNeeded(const ProcessInfo &process_info); - void - KillDebugserverProcess (); + Error LaunchAndConnectToDebugserver(const ProcessInfo &process_info); - void - BuildDynamicRegisterInfo (bool force); + void KillDebugserverProcess(); - void - SetLastStopPacket (const StringExtractorGDBRemote &response); + void BuildDynamicRegisterInfo(bool force); - bool - ParsePythonTargetDefinition(const FileSpec &target_definition_fspec); + void SetLastStopPacket(const StringExtractorGDBRemote &response); - const lldb::DataBufferSP - GetAuxvData() override; + bool ParsePythonTargetDefinition(const FileSpec &target_definition_fspec); - StructuredData::ObjectSP - GetExtendedInfoForThread (lldb::tid_t tid); + const lldb::DataBufferSP GetAuxvData() override; - void - GetMaxMemorySize(); + StructuredData::ObjectSP GetExtendedInfoForThread(lldb::tid_t tid); - bool - CalculateThreadStopInfo (ThreadGDBRemote *thread); + void GetMaxMemorySize(); - size_t - UpdateThreadPCsFromStopReplyThreadsValue (std::string &value); + bool CalculateThreadStopInfo(ThreadGDBRemote *thread); - size_t - UpdateThreadIDsFromStopReplyThreadsValue (std::string &value); + size_t UpdateThreadPCsFromStopReplyThreadsValue(std::string &value); - bool - HandleNotifyPacket(StringExtractorGDBRemote &packet); + size_t UpdateThreadIDsFromStopReplyThreadsValue(std::string &value); - bool - StartAsyncThread (); + bool HandleNotifyPacket(StringExtractorGDBRemote &packet); - void - StopAsyncThread (); + bool StartAsyncThread(); - static lldb::thread_result_t - AsyncThread (void *arg); + void StopAsyncThread(); - static bool - MonitorDebugserverProcess(std::weak_ptr<ProcessGDBRemote> process_wp, lldb::pid_t pid, bool exited, int signo, - int exit_status); + static lldb::thread_result_t AsyncThread(void *arg); - lldb::StateType - SetThreadStopInfo (StringExtractor& stop_packet); + static bool + MonitorDebugserverProcess(std::weak_ptr<ProcessGDBRemote> process_wp, + lldb::pid_t pid, bool exited, int signo, + int exit_status); - bool - GetThreadStopInfoFromJSON (ThreadGDBRemote *thread, const StructuredData::ObjectSP &thread_infos_sp); + lldb::StateType SetThreadStopInfo(StringExtractor &stop_packet); - lldb::ThreadSP - SetThreadStopInfo (StructuredData::Dictionary *thread_dict); + bool + GetThreadStopInfoFromJSON(ThreadGDBRemote *thread, + const StructuredData::ObjectSP &thread_infos_sp); - lldb::ThreadSP - SetThreadStopInfo (lldb::tid_t tid, - ExpeditedRegisterMap &expedited_register_map, - uint8_t signo, - const std::string &thread_name, - const std::string &reason, - const std::string &description, - uint32_t exc_type, - const std::vector<lldb::addr_t> &exc_data, - lldb::addr_t thread_dispatch_qaddr, - bool queue_vars_valid, - lldb_private::LazyBool associated_with_libdispatch_queue, - lldb::addr_t dispatch_queue_t, - std::string &queue_name, - lldb::QueueKind queue_kind, - uint64_t queue_serial); + lldb::ThreadSP SetThreadStopInfo(StructuredData::Dictionary *thread_dict); - void - HandleStopReplySequence (); + lldb::ThreadSP + SetThreadStopInfo(lldb::tid_t tid, + ExpeditedRegisterMap &expedited_register_map, uint8_t signo, + const std::string &thread_name, const std::string &reason, + const std::string &description, uint32_t exc_type, + const std::vector<lldb::addr_t> &exc_data, + lldb::addr_t thread_dispatch_qaddr, bool queue_vars_valid, + lldb_private::LazyBool associated_with_libdispatch_queue, + lldb::addr_t dispatch_queue_t, std::string &queue_name, + lldb::QueueKind queue_kind, uint64_t queue_serial); - void - ClearThreadIDList (); + void HandleStopReplySequence(); - bool - UpdateThreadIDList (); + void ClearThreadIDList(); - void - DidLaunchOrAttach (ArchSpec& process_arch); + bool UpdateThreadIDList(); - Error - ConnectToDebugserver (const char *host_port); + void DidLaunchOrAttach(ArchSpec &process_arch); - const char * - GetDispatchQueueNameForThread (lldb::addr_t thread_dispatch_qaddr, - std::string &dispatch_queue_name); + Error ConnectToDebugserver(llvm::StringRef host_port); - DynamicLoader * - GetDynamicLoader () override; + const char *GetDispatchQueueNameForThread(lldb::addr_t thread_dispatch_qaddr, + std::string &dispatch_queue_name); - // Query remote GDBServer for register information - bool - GetGDBServerRegisterInfo (ArchSpec &arch); + DynamicLoader *GetDynamicLoader() override; - // Query remote GDBServer for a detailed loaded library list - Error - GetLoadedModuleList (LoadedModuleInfoList &); + // Query remote GDBServer for register information + bool GetGDBServerRegisterInfo(ArchSpec &arch); - lldb::ModuleSP - LoadModuleAtAddress (const FileSpec &file, lldb::addr_t link_map, lldb::addr_t base_addr, - bool value_is_offset); + // Query remote GDBServer for a detailed loaded library list + Error GetLoadedModuleList(LoadedModuleInfoList &); + + lldb::ModuleSP LoadModuleAtAddress(const FileSpec &file, + lldb::addr_t link_map, + lldb::addr_t base_addr, + bool value_is_offset); private: - //------------------------------------------------------------------ - // For ProcessGDBRemote only - //------------------------------------------------------------------ - static bool - NewThreadNotifyBreakpointHit (void *baton, - StoppointCallbackContext *context, - lldb::user_id_t break_id, - lldb::user_id_t break_loc_id); - - DISALLOW_COPY_AND_ASSIGN (ProcessGDBRemote); + //------------------------------------------------------------------ + // For ProcessGDBRemote only + //------------------------------------------------------------------ + std::string m_partial_profile_data; + std::map<uint64_t, uint32_t> m_thread_id_to_used_usec_map; + + static bool NewThreadNotifyBreakpointHit(void *baton, + StoppointCallbackContext *context, + lldb::user_id_t break_id, + lldb::user_id_t break_loc_id); + + //------------------------------------------------------------------ + // ContinueDelegate interface + //------------------------------------------------------------------ + void HandleAsyncStdout(llvm::StringRef out) override; + void HandleAsyncMisc(llvm::StringRef data) override; + void HandleStopReply() override; + void HandleAsyncStructuredDataPacket(llvm::StringRef data) override; + + using ModuleCacheKey = std::pair<std::string, std::string>; + // KeyInfo for the cached module spec DenseMap. + // The invariant is that all real keys will have the file and architecture + // set. + // The empty key has an empty file and an empty arch. + // The tombstone key has an invalid arch and an empty file. + // The comparison and hash functions take the file name and architecture + // triple into account. + struct ModuleCacheInfo { + static ModuleCacheKey getEmptyKey() { return ModuleCacheKey(); } + + static ModuleCacheKey getTombstoneKey() { return ModuleCacheKey("", "T"); } + + static unsigned getHashValue(const ModuleCacheKey &key) { + return llvm::hash_combine(key.first, key.second); + } + + static bool isEqual(const ModuleCacheKey &LHS, const ModuleCacheKey &RHS) { + return LHS == RHS; + } + }; + + llvm::DenseMap<ModuleCacheKey, ModuleSpec, ModuleCacheInfo> + m_cached_module_specs; + + DISALLOW_COPY_AND_ASSIGN(ProcessGDBRemote); }; } // namespace process_gdb_remote diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp index d4726ad..899037a 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp @@ -11,8 +11,8 @@ #include <mutex> -#include "lldb/Interpreter/Args.h" #include "lldb/Core/StreamFile.h" +#include "lldb/Interpreter/Args.h" #include "ProcessGDBRemote.h" @@ -20,196 +20,198 @@ using namespace lldb; using namespace lldb_private; using namespace lldb_private::process_gdb_remote; - // We want to avoid global constructors where code needs to be run so here we // control access to our static g_log_sp by hiding it in a singleton function -// that will construct the static g_lob_sp the first time this function is +// that will construct the static g_lob_sp the first time this function is // called. static bool g_log_enabled = false; -static Log * g_log = NULL; -static Log * -GetLog () -{ - if (!g_log_enabled) - return NULL; - return g_log; +static Log *g_log = NULL; +static Log *GetLog() { + if (!g_log_enabled) + return NULL; + return g_log; } -void -ProcessGDBRemoteLog::Initialize() -{ - static ConstString g_name("gdb-remote"); - static std::once_flag g_once_flag; - - std::call_once(g_once_flag, [](){ - Log::Callbacks log_callbacks = { - DisableLog, - EnableLog, - ListLogCategories - }; - - Log::RegisterLogChannel (g_name, log_callbacks); - }); -} +void ProcessGDBRemoteLog::Initialize() { + static ConstString g_name("gdb-remote"); + static std::once_flag g_once_flag; -Log * -ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (uint32_t mask) -{ - Log *log(GetLog ()); - if (log && mask) - { - uint32_t log_mask = log->GetMask().Get(); - if ((log_mask & mask) != mask) - return NULL; - } - return log; + std::call_once(g_once_flag, []() { + Log::Callbacks log_callbacks = {DisableLog, EnableLog, ListLogCategories}; + + Log::RegisterLogChannel(g_name, log_callbacks); + }); } -Log * -ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (uint32_t mask) -{ - Log *log(GetLog ()); - if (log && log->GetMask().Get() & mask) - return log; - return NULL; +Log *ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(uint32_t mask) { + Log *log(GetLog()); + if (log && mask) { + uint32_t log_mask = log->GetMask().Get(); + if ((log_mask & mask) != mask) + return NULL; + } + return log; } -void -ProcessGDBRemoteLog::DisableLog (const char **categories, Stream *feedback_strm) -{ - Log *log (GetLog ()); - if (log) - { - uint32_t flag_bits = 0; - - if (categories[0] != NULL) - { - flag_bits = log->GetMask().Get(); - for (size_t i = 0; categories[i] != NULL; ++i) - { - const char *arg = categories[i]; - - - if (::strcasecmp (arg, "all") == 0 ) flag_bits &= ~GDBR_LOG_ALL; - else if (::strcasecmp (arg, "async") == 0 ) flag_bits &= ~GDBR_LOG_ASYNC; - else if (::strncasecmp (arg, "break", 5) == 0 ) flag_bits &= ~GDBR_LOG_BREAKPOINTS; - else if (::strncasecmp (arg, "comm", 4) == 0 ) flag_bits &= ~GDBR_LOG_COMM; - else if (::strcasecmp (arg, "default") == 0 ) flag_bits &= ~GDBR_LOG_DEFAULT; - else if (::strcasecmp (arg, "packets") == 0 ) flag_bits &= ~GDBR_LOG_PACKETS; - else if (::strcasecmp (arg, "memory") == 0 ) flag_bits &= ~GDBR_LOG_MEMORY; - else if (::strcasecmp (arg, "data-short") == 0 ) flag_bits &= ~GDBR_LOG_MEMORY_DATA_SHORT; - else if (::strcasecmp (arg, "data-long") == 0 ) flag_bits &= ~GDBR_LOG_MEMORY_DATA_LONG; - else if (::strcasecmp (arg, "process") == 0 ) flag_bits &= ~GDBR_LOG_PROCESS; - else if (::strcasecmp (arg, "step") == 0 ) flag_bits &= ~GDBR_LOG_STEP; - else if (::strcasecmp (arg, "thread") == 0 ) flag_bits &= ~GDBR_LOG_THREAD; - else if (::strcasecmp (arg, "verbose") == 0 ) flag_bits &= ~GDBR_LOG_VERBOSE; - else if (::strncasecmp (arg, "watch", 5) == 0 ) flag_bits &= ~GDBR_LOG_WATCHPOINTS; - else - { - feedback_strm->Printf("error: unrecognized log category '%s'\n", arg); - ListLogCategories (feedback_strm); - } - - } - } - - if (flag_bits == 0) - g_log_enabled = false; - else - log->GetMask().Reset (flag_bits); - } - - return; +Log *ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(uint32_t mask) { + Log *log(GetLog()); + if (log && log->GetMask().Get() & mask) + return log; + return NULL; } -Log * -ProcessGDBRemoteLog::EnableLog (StreamSP &log_stream_sp, uint32_t log_options, const char **categories, Stream *feedback_strm) -{ - // Try see if there already is a log - that way we can reuse its settings. - // We could reuse the log in toto, but we don't know that the stream is the same. +void ProcessGDBRemoteLog::DisableLog(const char **categories, + Stream *feedback_strm) { + Log *log(GetLog()); + if (log) { uint32_t flag_bits = 0; - if (g_log) - flag_bits = g_log->GetMask().Get(); - - // Now make a new log with this stream if one was provided - if (log_stream_sp) - { - if (g_log) - g_log->SetStream(log_stream_sp); - else - g_log = new Log(log_stream_sp); + + if (categories && categories[0]) { + flag_bits = log->GetMask().Get(); + for (size_t i = 0; categories[i] != NULL; ++i) { + const char *arg = categories[i]; + + if (::strcasecmp(arg, "all") == 0) + flag_bits &= ~GDBR_LOG_ALL; + else if (::strcasecmp(arg, "async") == 0) + flag_bits &= ~GDBR_LOG_ASYNC; + else if (::strncasecmp(arg, "break", 5) == 0) + flag_bits &= ~GDBR_LOG_BREAKPOINTS; + else if (::strncasecmp(arg, "comm", 4) == 0) + flag_bits &= ~GDBR_LOG_COMM; + else if (::strcasecmp(arg, "default") == 0) + flag_bits &= ~GDBR_LOG_DEFAULT; + else if (::strcasecmp(arg, "packets") == 0) + flag_bits &= ~GDBR_LOG_PACKETS; + else if (::strcasecmp(arg, "memory") == 0) + flag_bits &= ~GDBR_LOG_MEMORY; + else if (::strcasecmp(arg, "data-short") == 0) + flag_bits &= ~GDBR_LOG_MEMORY_DATA_SHORT; + else if (::strcasecmp(arg, "data-long") == 0) + flag_bits &= ~GDBR_LOG_MEMORY_DATA_LONG; + else if (::strcasecmp(arg, "process") == 0) + flag_bits &= ~GDBR_LOG_PROCESS; + else if (::strcasecmp(arg, "step") == 0) + flag_bits &= ~GDBR_LOG_STEP; + else if (::strcasecmp(arg, "thread") == 0) + flag_bits &= ~GDBR_LOG_THREAD; + else if (::strcasecmp(arg, "verbose") == 0) + flag_bits &= ~GDBR_LOG_VERBOSE; + else if (::strncasecmp(arg, "watch", 5) == 0) + flag_bits &= ~GDBR_LOG_WATCHPOINTS; + else { + feedback_strm->Printf("error: unrecognized log category '%s'\n", arg); + ListLogCategories(feedback_strm); + } + } } + if (flag_bits == 0) + g_log_enabled = false; + else + log->GetMask().Reset(flag_bits); + } + + return; +} + +Log *ProcessGDBRemoteLog::EnableLog(StreamSP &log_stream_sp, + uint32_t log_options, + const char **categories, + Stream *feedback_strm) { + // Try see if there already is a log - that way we can reuse its settings. + // We could reuse the log in toto, but we don't know that the stream is the + // same. + uint32_t flag_bits = 0; + if (g_log) + flag_bits = g_log->GetMask().Get(); + + // Now make a new log with this stream if one was provided + if (log_stream_sp) { if (g_log) - { - bool got_unknown_category = false; - for (size_t i=0; categories[i] != NULL; ++i) - { - const char *arg = categories[i]; - - if (::strcasecmp (arg, "all") == 0 ) flag_bits |= GDBR_LOG_ALL; - else if (::strcasecmp (arg, "async") == 0 ) flag_bits |= GDBR_LOG_ASYNC; - else if (::strncasecmp (arg, "break", 5) == 0 ) flag_bits |= GDBR_LOG_BREAKPOINTS; - else if (::strncasecmp (arg, "comm", 4) == 0 ) flag_bits |= GDBR_LOG_COMM; - else if (::strcasecmp (arg, "default") == 0 ) flag_bits |= GDBR_LOG_DEFAULT; - else if (::strcasecmp (arg, "packets") == 0 ) flag_bits |= GDBR_LOG_PACKETS; - else if (::strcasecmp (arg, "memory") == 0 ) flag_bits |= GDBR_LOG_MEMORY; - else if (::strcasecmp (arg, "data-short") == 0 ) flag_bits |= GDBR_LOG_MEMORY_DATA_SHORT; - else if (::strcasecmp (arg, "data-long") == 0 ) flag_bits |= GDBR_LOG_MEMORY_DATA_LONG; - else if (::strcasecmp (arg, "process") == 0 ) flag_bits |= GDBR_LOG_PROCESS; - else if (::strcasecmp (arg, "step") == 0 ) flag_bits |= GDBR_LOG_STEP; - else if (::strcasecmp (arg, "thread") == 0 ) flag_bits |= GDBR_LOG_THREAD; - else if (::strcasecmp (arg, "verbose") == 0 ) flag_bits |= GDBR_LOG_VERBOSE; - else if (::strncasecmp (arg, "watch", 5) == 0 ) flag_bits |= GDBR_LOG_WATCHPOINTS; - else - { - feedback_strm->Printf("error: unrecognized log category '%s'\n", arg); - if (got_unknown_category == false) - { - got_unknown_category = true; - ListLogCategories (feedback_strm); - } - } + g_log->SetStream(log_stream_sp); + else + g_log = new Log(log_stream_sp); + } + + if (g_log) { + bool got_unknown_category = false; + for (size_t i = 0; categories[i] != NULL; ++i) { + const char *arg = categories[i]; + + if (::strcasecmp(arg, "all") == 0) + flag_bits |= GDBR_LOG_ALL; + else if (::strcasecmp(arg, "async") == 0) + flag_bits |= GDBR_LOG_ASYNC; + else if (::strncasecmp(arg, "break", 5) == 0) + flag_bits |= GDBR_LOG_BREAKPOINTS; + else if (::strncasecmp(arg, "comm", 4) == 0) + flag_bits |= GDBR_LOG_COMM; + else if (::strcasecmp(arg, "default") == 0) + flag_bits |= GDBR_LOG_DEFAULT; + else if (::strcasecmp(arg, "packets") == 0) + flag_bits |= GDBR_LOG_PACKETS; + else if (::strcasecmp(arg, "memory") == 0) + flag_bits |= GDBR_LOG_MEMORY; + else if (::strcasecmp(arg, "data-short") == 0) + flag_bits |= GDBR_LOG_MEMORY_DATA_SHORT; + else if (::strcasecmp(arg, "data-long") == 0) + flag_bits |= GDBR_LOG_MEMORY_DATA_LONG; + else if (::strcasecmp(arg, "process") == 0) + flag_bits |= GDBR_LOG_PROCESS; + else if (::strcasecmp(arg, "step") == 0) + flag_bits |= GDBR_LOG_STEP; + else if (::strcasecmp(arg, "thread") == 0) + flag_bits |= GDBR_LOG_THREAD; + else if (::strcasecmp(arg, "verbose") == 0) + flag_bits |= GDBR_LOG_VERBOSE; + else if (::strncasecmp(arg, "watch", 5) == 0) + flag_bits |= GDBR_LOG_WATCHPOINTS; + else { + feedback_strm->Printf("error: unrecognized log category '%s'\n", arg); + if (got_unknown_category == false) { + got_unknown_category = true; + ListLogCategories(feedback_strm); } - if (flag_bits == 0) - flag_bits = GDBR_LOG_DEFAULT; - g_log->GetMask().Reset(flag_bits); - g_log->GetOptions().Reset(log_options); + } } - g_log_enabled = true; - return g_log; + if (flag_bits == 0) + flag_bits = GDBR_LOG_DEFAULT; + g_log->GetMask().Reset(flag_bits); + g_log->GetOptions().Reset(log_options); + } + g_log_enabled = true; + return g_log; } -void -ProcessGDBRemoteLog::ListLogCategories (Stream *strm) -{ - strm->Printf ("Logging categories for '%s':\n" - " all - turn on all available logging categories\n" - " async - log asynchronous activity\n" - " break - log breakpoints\n" - " communication - log communication activity\n" - " default - enable the default set of logging categories for liblldb\n" - " packets - log gdb remote packets\n" - " memory - log memory reads and writes\n" - " data-short - log memory bytes for memory reads and writes for short transactions only\n" - " data-long - log memory bytes for memory reads and writes for all transactions\n" - " process - log process events and activities\n" - " thread - log thread events and activities\n" - " step - log step related activities\n" - " verbose - enable verbose logging\n" - " watch - log watchpoint related activities\n", ProcessGDBRemote::GetPluginNameStatic().GetCString()); +void ProcessGDBRemoteLog::ListLogCategories(Stream *strm) { + strm->Printf( + "Logging categories for '%s':\n" + " all - turn on all available logging categories\n" + " async - log asynchronous activity\n" + " break - log breakpoints\n" + " communication - log communication activity\n" + " default - enable the default set of logging categories for liblldb\n" + " packets - log gdb remote packets\n" + " memory - log memory reads and writes\n" + " data-short - log memory bytes for memory reads and writes for short " + "transactions only\n" + " data-long - log memory bytes for memory reads and writes for all " + "transactions\n" + " process - log process events and activities\n" + " thread - log thread events and activities\n" + " step - log step related activities\n" + " verbose - enable verbose logging\n" + " watch - log watchpoint related activities\n", + ProcessGDBRemote::GetPluginNameStatic().GetCString()); } - -void -ProcessGDBRemoteLog::LogIf (uint32_t mask, const char *format, ...) -{ - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (mask)); - if (log) - { - va_list args; - va_start (args, format); - log->VAPrintf (format, args); - va_end (args); - } +void ProcessGDBRemoteLog::LogIf(uint32_t mask, const char *format, ...) { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(mask)); + if (log) { + va_list args; + va_start(args, format); + log->VAPrintf(format, args); + va_end(args); + } } diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h index 3cd974d..f5e92b4 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h @@ -17,50 +17,44 @@ // Project includes #include "lldb/Core/Log.h" -#define GDBR_LOG_VERBOSE (1u << 0) -#define GDBR_LOG_PROCESS (1u << 1) -#define GDBR_LOG_THREAD (1u << 2) -#define GDBR_LOG_PACKETS (1u << 3) -#define GDBR_LOG_MEMORY (1u << 4) // Log memory reads/writes calls -#define GDBR_LOG_MEMORY_DATA_SHORT (1u << 5) // Log short memory reads/writes bytes -#define GDBR_LOG_MEMORY_DATA_LONG (1u << 6) // Log all memory reads/writes bytes -#define GDBR_LOG_BREAKPOINTS (1u << 7) -#define GDBR_LOG_WATCHPOINTS (1u << 8) -#define GDBR_LOG_STEP (1u << 9) -#define GDBR_LOG_COMM (1u << 10) -#define GDBR_LOG_ASYNC (1u << 11) -#define GDBR_LOG_ALL (UINT32_MAX) -#define GDBR_LOG_DEFAULT GDBR_LOG_PACKETS +#define GDBR_LOG_VERBOSE (1u << 0) +#define GDBR_LOG_PROCESS (1u << 1) +#define GDBR_LOG_THREAD (1u << 2) +#define GDBR_LOG_PACKETS (1u << 3) +#define GDBR_LOG_MEMORY (1u << 4) // Log memory reads/writes calls +#define GDBR_LOG_MEMORY_DATA_SHORT \ + (1u << 5) // Log short memory reads/writes bytes +#define GDBR_LOG_MEMORY_DATA_LONG (1u << 6) // Log all memory reads/writes bytes +#define GDBR_LOG_BREAKPOINTS (1u << 7) +#define GDBR_LOG_WATCHPOINTS (1u << 8) +#define GDBR_LOG_STEP (1u << 9) +#define GDBR_LOG_COMM (1u << 10) +#define GDBR_LOG_ASYNC (1u << 11) +#define GDBR_LOG_ALL (UINT32_MAX) +#define GDBR_LOG_DEFAULT GDBR_LOG_PACKETS namespace lldb_private { namespace process_gdb_remote { -class ProcessGDBRemoteLog -{ +class ProcessGDBRemoteLog { public: - static void - Initialize(); + static void Initialize(); - static Log * - GetLogIfAllCategoriesSet(uint32_t mask = 0); - - static Log * - GetLogIfAnyCategoryIsSet (uint32_t mask); + static Log *GetLogIfAllCategoriesSet(uint32_t mask = 0); - static void - DisableLog (const char **categories, Stream *feedback_strm); + static Log *GetLogIfAnyCategoryIsSet(uint32_t mask); - static Log * - EnableLog (lldb::StreamSP &log_stream_sp, uint32_t log_options, const char **categories, Stream *feedback_strm); + static void DisableLog(const char **categories, Stream *feedback_strm); - static void - ListLogCategories (Stream *strm); + static Log *EnableLog(lldb::StreamSP &log_stream_sp, uint32_t log_options, + const char **categories, Stream *feedback_strm); - static void - LogIf (uint32_t mask, const char *format, ...); + static void ListLogCategories(Stream *strm); + + static void LogIf(uint32_t mask, const char *format, ...); }; } // namespace process_gdb_remote } // namespace lldb_private -#endif // liblldb_ProcessGDBRemoteLog_h_ +#endif // liblldb_ProcessGDBRemoteLog_h_ diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp index a4af12c..ab55214 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp @@ -7,7 +7,6 @@ // //===----------------------------------------------------------------------===// - #include "ThreadGDBRemote.h" #include "lldb/Breakpoint/Watchpoint.h" @@ -36,372 +35,318 @@ using namespace lldb_private::process_gdb_remote; // Thread Registers //---------------------------------------------------------------------- -ThreadGDBRemote::ThreadGDBRemote (Process &process, lldb::tid_t tid) : - Thread(process, tid), - m_thread_name (), - m_dispatch_queue_name (), - m_thread_dispatch_qaddr (LLDB_INVALID_ADDRESS), - m_dispatch_queue_t (LLDB_INVALID_ADDRESS), - m_queue_kind (eQueueKindUnknown), - m_queue_serial_number (LLDB_INVALID_QUEUE_ID), - m_associated_with_libdispatch_queue (eLazyBoolCalculate) -{ - ProcessGDBRemoteLog::LogIf(GDBR_LOG_THREAD, "%p: ThreadGDBRemote::ThreadGDBRemote (pid = %i, tid = 0x%4.4x)", - this, - process.GetID(), - GetID()); +ThreadGDBRemote::ThreadGDBRemote(Process &process, lldb::tid_t tid) + : Thread(process, tid), m_thread_name(), m_dispatch_queue_name(), + m_thread_dispatch_qaddr(LLDB_INVALID_ADDRESS), + m_dispatch_queue_t(LLDB_INVALID_ADDRESS), m_queue_kind(eQueueKindUnknown), + m_queue_serial_number(LLDB_INVALID_QUEUE_ID), + m_associated_with_libdispatch_queue(eLazyBoolCalculate) { + ProcessGDBRemoteLog::LogIf( + GDBR_LOG_THREAD, + "%p: ThreadGDBRemote::ThreadGDBRemote (pid = %i, tid = 0x%4.4x)", this, + process.GetID(), GetID()); } -ThreadGDBRemote::~ThreadGDBRemote () -{ - ProcessSP process_sp(GetProcess()); - ProcessGDBRemoteLog::LogIf(GDBR_LOG_THREAD, "%p: ThreadGDBRemote::~ThreadGDBRemote (pid = %i, tid = 0x%4.4x)", - this, - process_sp ? process_sp->GetID() : LLDB_INVALID_PROCESS_ID, - GetID()); - DestroyThread(); +ThreadGDBRemote::~ThreadGDBRemote() { + ProcessSP process_sp(GetProcess()); + ProcessGDBRemoteLog::LogIf( + GDBR_LOG_THREAD, + "%p: ThreadGDBRemote::~ThreadGDBRemote (pid = %i, tid = 0x%4.4x)", this, + process_sp ? process_sp->GetID() : LLDB_INVALID_PROCESS_ID, GetID()); + DestroyThread(); } -const char * -ThreadGDBRemote::GetName () -{ - if (m_thread_name.empty()) - return NULL; - return m_thread_name.c_str(); +const char *ThreadGDBRemote::GetName() { + if (m_thread_name.empty()) + return NULL; + return m_thread_name.c_str(); } -void -ThreadGDBRemote::ClearQueueInfo () -{ - m_dispatch_queue_name.clear(); - m_queue_kind = eQueueKindUnknown; - m_queue_serial_number = 0; - m_dispatch_queue_t = LLDB_INVALID_ADDRESS; - m_associated_with_libdispatch_queue = eLazyBoolCalculate; +void ThreadGDBRemote::ClearQueueInfo() { + m_dispatch_queue_name.clear(); + m_queue_kind = eQueueKindUnknown; + m_queue_serial_number = 0; + m_dispatch_queue_t = LLDB_INVALID_ADDRESS; + m_associated_with_libdispatch_queue = eLazyBoolCalculate; } -void -ThreadGDBRemote::SetQueueInfo (std::string &&queue_name, QueueKind queue_kind, uint64_t queue_serial, addr_t dispatch_queue_t, LazyBool associated_with_libdispatch_queue) -{ - m_dispatch_queue_name = queue_name; - m_queue_kind = queue_kind; - m_queue_serial_number = queue_serial; - m_dispatch_queue_t = dispatch_queue_t; - m_associated_with_libdispatch_queue = associated_with_libdispatch_queue; +void ThreadGDBRemote::SetQueueInfo(std::string &&queue_name, + QueueKind queue_kind, uint64_t queue_serial, + addr_t dispatch_queue_t, + LazyBool associated_with_libdispatch_queue) { + m_dispatch_queue_name = queue_name; + m_queue_kind = queue_kind; + m_queue_serial_number = queue_serial; + m_dispatch_queue_t = dispatch_queue_t; + m_associated_with_libdispatch_queue = associated_with_libdispatch_queue; } +const char *ThreadGDBRemote::GetQueueName() { + // If our cached queue info is valid, then someone called + // ThreadGDBRemote::SetQueueInfo(...) + // with valid information that was gleaned from the stop reply packet. In this + // case we trust + // that the info is valid in m_dispatch_queue_name without refetching it + if (CachedQueueInfoIsValid()) { + if (m_dispatch_queue_name.empty()) + return nullptr; + else + return m_dispatch_queue_name.c_str(); + } + // Always re-fetch the dispatch queue name since it can change -const char * -ThreadGDBRemote::GetQueueName () -{ - // If our cached queue info is valid, then someone called ThreadGDBRemote::SetQueueInfo(...) - // with valid information that was gleaned from the stop reply packet. In this case we trust - // that the info is valid in m_dispatch_queue_name without refetching it - if (CachedQueueInfoIsValid()) - { - if (m_dispatch_queue_name.empty()) - return nullptr; - else - return m_dispatch_queue_name.c_str(); - } - // Always re-fetch the dispatch queue name since it can change - - if (m_associated_with_libdispatch_queue == eLazyBoolNo) - return nullptr; - - if (m_thread_dispatch_qaddr != 0 && m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS) - { - ProcessSP process_sp (GetProcess()); - if (process_sp) - { - SystemRuntime *runtime = process_sp->GetSystemRuntime (); - if (runtime) - m_dispatch_queue_name = runtime->GetQueueNameFromThreadQAddress (m_thread_dispatch_qaddr); - else - m_dispatch_queue_name.clear(); - - if (!m_dispatch_queue_name.empty()) - return m_dispatch_queue_name.c_str(); - } + if (m_associated_with_libdispatch_queue == eLazyBoolNo) + return nullptr; + + if (m_thread_dispatch_qaddr != 0 && + m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS) { + ProcessSP process_sp(GetProcess()); + if (process_sp) { + SystemRuntime *runtime = process_sp->GetSystemRuntime(); + if (runtime) + m_dispatch_queue_name = + runtime->GetQueueNameFromThreadQAddress(m_thread_dispatch_qaddr); + else + m_dispatch_queue_name.clear(); + + if (!m_dispatch_queue_name.empty()) + return m_dispatch_queue_name.c_str(); } - return NULL; + } + return NULL; } -QueueKind -ThreadGDBRemote::GetQueueKind () -{ - // If our cached queue info is valid, then someone called ThreadGDBRemote::SetQueueInfo(...) - // with valid information that was gleaned from the stop reply packet. In this case we trust - // that the info is valid in m_dispatch_queue_name without refetching it - if (CachedQueueInfoIsValid()) - { - return m_queue_kind; - } +QueueKind ThreadGDBRemote::GetQueueKind() { + // If our cached queue info is valid, then someone called + // ThreadGDBRemote::SetQueueInfo(...) + // with valid information that was gleaned from the stop reply packet. In this + // case we trust + // that the info is valid in m_dispatch_queue_name without refetching it + if (CachedQueueInfoIsValid()) { + return m_queue_kind; + } + + if (m_associated_with_libdispatch_queue == eLazyBoolNo) + return eQueueKindUnknown; - if (m_associated_with_libdispatch_queue == eLazyBoolNo) - return eQueueKindUnknown; - - if (m_thread_dispatch_qaddr != 0 && m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS) - { - ProcessSP process_sp (GetProcess()); - if (process_sp) - { - SystemRuntime *runtime = process_sp->GetSystemRuntime (); - if (runtime) - m_queue_kind = runtime->GetQueueKind (m_thread_dispatch_qaddr); - return m_queue_kind; - } + if (m_thread_dispatch_qaddr != 0 && + m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS) { + ProcessSP process_sp(GetProcess()); + if (process_sp) { + SystemRuntime *runtime = process_sp->GetSystemRuntime(); + if (runtime) + m_queue_kind = runtime->GetQueueKind(m_thread_dispatch_qaddr); + return m_queue_kind; } - return eQueueKindUnknown; + } + return eQueueKindUnknown; } +queue_id_t ThreadGDBRemote::GetQueueID() { + // If our cached queue info is valid, then someone called + // ThreadGDBRemote::SetQueueInfo(...) + // with valid information that was gleaned from the stop reply packet. In this + // case we trust + // that the info is valid in m_dispatch_queue_name without refetching it + if (CachedQueueInfoIsValid()) + return m_queue_serial_number; -queue_id_t -ThreadGDBRemote::GetQueueID () -{ - // If our cached queue info is valid, then someone called ThreadGDBRemote::SetQueueInfo(...) - // with valid information that was gleaned from the stop reply packet. In this case we trust - // that the info is valid in m_dispatch_queue_name without refetching it - if (CachedQueueInfoIsValid()) - return m_queue_serial_number; - - if (m_associated_with_libdispatch_queue == eLazyBoolNo) - return LLDB_INVALID_QUEUE_ID; - - if (m_thread_dispatch_qaddr != 0 && m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS) - { - ProcessSP process_sp (GetProcess()); - if (process_sp) - { - SystemRuntime *runtime = process_sp->GetSystemRuntime (); - if (runtime) - { - return runtime->GetQueueIDFromThreadQAddress (m_thread_dispatch_qaddr); - } - } - } + if (m_associated_with_libdispatch_queue == eLazyBoolNo) return LLDB_INVALID_QUEUE_ID; + + if (m_thread_dispatch_qaddr != 0 && + m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS) { + ProcessSP process_sp(GetProcess()); + if (process_sp) { + SystemRuntime *runtime = process_sp->GetSystemRuntime(); + if (runtime) { + return runtime->GetQueueIDFromThreadQAddress(m_thread_dispatch_qaddr); + } + } + } + return LLDB_INVALID_QUEUE_ID; } -QueueSP -ThreadGDBRemote::GetQueue () -{ - queue_id_t queue_id = GetQueueID(); - QueueSP queue; - if (queue_id != LLDB_INVALID_QUEUE_ID) - { - ProcessSP process_sp (GetProcess()); - if (process_sp) - { - queue = process_sp->GetQueueList().FindQueueByID (queue_id); - } +QueueSP ThreadGDBRemote::GetQueue() { + queue_id_t queue_id = GetQueueID(); + QueueSP queue; + if (queue_id != LLDB_INVALID_QUEUE_ID) { + ProcessSP process_sp(GetProcess()); + if (process_sp) { + queue = process_sp->GetQueueList().FindQueueByID(queue_id); } - return queue; + } + return queue; } -addr_t -ThreadGDBRemote::GetQueueLibdispatchQueueAddress () -{ - if (m_dispatch_queue_t == LLDB_INVALID_ADDRESS) - { - if (m_thread_dispatch_qaddr != 0 && m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS) - { - ProcessSP process_sp (GetProcess()); - if (process_sp) - { - SystemRuntime *runtime = process_sp->GetSystemRuntime (); - if (runtime) - { - m_dispatch_queue_t = runtime->GetLibdispatchQueueAddressFromThreadQAddress (m_thread_dispatch_qaddr); - } - } +addr_t ThreadGDBRemote::GetQueueLibdispatchQueueAddress() { + if (m_dispatch_queue_t == LLDB_INVALID_ADDRESS) { + if (m_thread_dispatch_qaddr != 0 && + m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS) { + ProcessSP process_sp(GetProcess()); + if (process_sp) { + SystemRuntime *runtime = process_sp->GetSystemRuntime(); + if (runtime) { + m_dispatch_queue_t = + runtime->GetLibdispatchQueueAddressFromThreadQAddress( + m_thread_dispatch_qaddr); } + } } - return m_dispatch_queue_t; + } + return m_dispatch_queue_t; } -void -ThreadGDBRemote::SetQueueLibdispatchQueueAddress (lldb::addr_t dispatch_queue_t) -{ - m_dispatch_queue_t = dispatch_queue_t; +void ThreadGDBRemote::SetQueueLibdispatchQueueAddress( + lldb::addr_t dispatch_queue_t) { + m_dispatch_queue_t = dispatch_queue_t; } -bool -ThreadGDBRemote::ThreadHasQueueInformation () const -{ - if (m_thread_dispatch_qaddr != 0 - && m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS - && m_dispatch_queue_t != LLDB_INVALID_ADDRESS - && m_queue_kind != eQueueKindUnknown - && m_queue_serial_number != 0) - { - return true; - } - return false; +bool ThreadGDBRemote::ThreadHasQueueInformation() const { + if (m_thread_dispatch_qaddr != 0 && + m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS && + m_dispatch_queue_t != LLDB_INVALID_ADDRESS && + m_queue_kind != eQueueKindUnknown && m_queue_serial_number != 0) { + return true; + } + return false; } -LazyBool -ThreadGDBRemote::GetAssociatedWithLibdispatchQueue () -{ - return m_associated_with_libdispatch_queue; +LazyBool ThreadGDBRemote::GetAssociatedWithLibdispatchQueue() { + return m_associated_with_libdispatch_queue; } -void -ThreadGDBRemote::SetAssociatedWithLibdispatchQueue (LazyBool associated_with_libdispatch_queue) -{ - m_associated_with_libdispatch_queue = associated_with_libdispatch_queue; +void ThreadGDBRemote::SetAssociatedWithLibdispatchQueue( + LazyBool associated_with_libdispatch_queue) { + m_associated_with_libdispatch_queue = associated_with_libdispatch_queue; } -StructuredData::ObjectSP -ThreadGDBRemote::FetchThreadExtendedInfo () -{ - StructuredData::ObjectSP object_sp; - const lldb::user_id_t tid = GetProtocolID(); - Log *log(GetLogIfAnyCategoriesSet (GDBR_LOG_THREAD)); - if (log) - log->Printf ("Fetching extended information for thread %4.4" PRIx64, tid); - ProcessSP process_sp (GetProcess()); - if (process_sp) - { - ProcessGDBRemote *gdb_process = static_cast<ProcessGDBRemote *>(process_sp.get()); - object_sp = gdb_process->GetExtendedInfoForThread (tid); - } - return object_sp; +StructuredData::ObjectSP ThreadGDBRemote::FetchThreadExtendedInfo() { + StructuredData::ObjectSP object_sp; + const lldb::user_id_t tid = GetProtocolID(); + Log *log(GetLogIfAnyCategoriesSet(GDBR_LOG_THREAD)); + if (log) + log->Printf("Fetching extended information for thread %4.4" PRIx64, tid); + ProcessSP process_sp(GetProcess()); + if (process_sp) { + ProcessGDBRemote *gdb_process = + static_cast<ProcessGDBRemote *>(process_sp.get()); + object_sp = gdb_process->GetExtendedInfoForThread(tid); + } + return object_sp; } -void -ThreadGDBRemote::WillResume (StateType resume_state) -{ - int signo = GetResumeSignal(); - const lldb::user_id_t tid = GetProtocolID(); - Log *log(GetLogIfAnyCategoriesSet (GDBR_LOG_THREAD)); - if (log) - log->Printf ("Resuming thread: %4.4" PRIx64 " with state: %s.", tid, StateAsCString(resume_state)); - - ProcessSP process_sp (GetProcess()); - if (process_sp) - { - ProcessGDBRemote *gdb_process = static_cast<ProcessGDBRemote *>(process_sp.get()); - switch (resume_state) - { - case eStateSuspended: - case eStateStopped: - // Don't append anything for threads that should stay stopped. - break; - - case eStateRunning: - if (gdb_process->GetUnixSignals()->SignalIsValid(signo)) - gdb_process->m_continue_C_tids.push_back(std::make_pair(tid, signo)); - else - gdb_process->m_continue_c_tids.push_back(tid); - break; - - case eStateStepping: - if (gdb_process->GetUnixSignals()->SignalIsValid(signo)) - gdb_process->m_continue_S_tids.push_back(std::make_pair(tid, signo)); - else - gdb_process->m_continue_s_tids.push_back(tid); - break; - - default: - break; - } +void ThreadGDBRemote::WillResume(StateType resume_state) { + int signo = GetResumeSignal(); + const lldb::user_id_t tid = GetProtocolID(); + Log *log(GetLogIfAnyCategoriesSet(GDBR_LOG_THREAD)); + if (log) + log->Printf("Resuming thread: %4.4" PRIx64 " with state: %s.", tid, + StateAsCString(resume_state)); + + ProcessSP process_sp(GetProcess()); + if (process_sp) { + ProcessGDBRemote *gdb_process = + static_cast<ProcessGDBRemote *>(process_sp.get()); + switch (resume_state) { + case eStateSuspended: + case eStateStopped: + // Don't append anything for threads that should stay stopped. + break; + + case eStateRunning: + if (gdb_process->GetUnixSignals()->SignalIsValid(signo)) + gdb_process->m_continue_C_tids.push_back(std::make_pair(tid, signo)); + else + gdb_process->m_continue_c_tids.push_back(tid); + break; + + case eStateStepping: + if (gdb_process->GetUnixSignals()->SignalIsValid(signo)) + gdb_process->m_continue_S_tids.push_back(std::make_pair(tid, signo)); + else + gdb_process->m_continue_s_tids.push_back(tid); + break; + + default: + break; } + } } -void -ThreadGDBRemote::RefreshStateAfterStop() -{ - // Invalidate all registers in our register context. We don't set "force" to - // true because the stop reply packet might have had some register values - // that were expedited and these will already be copied into the register - // context by the time this function gets called. The GDBRemoteRegisterContext - // class has been made smart enough to detect when it needs to invalidate - // which registers are valid by putting hooks in the register read and - // register supply functions where they check the process stop ID and do - // the right thing. - const bool force = false; - GetRegisterContext()->InvalidateIfNeeded (force); -} - -bool -ThreadGDBRemote::ThreadIDIsValid (lldb::tid_t thread) -{ - return thread != 0; +void ThreadGDBRemote::RefreshStateAfterStop() { + // Invalidate all registers in our register context. We don't set "force" to + // true because the stop reply packet might have had some register values + // that were expedited and these will already be copied into the register + // context by the time this function gets called. The GDBRemoteRegisterContext + // class has been made smart enough to detect when it needs to invalidate + // which registers are valid by putting hooks in the register read and + // register supply functions where they check the process stop ID and do + // the right thing. + const bool force = false; + GetRegisterContext()->InvalidateIfNeeded(force); } -void -ThreadGDBRemote::Dump(Log *log, uint32_t index) -{ +bool ThreadGDBRemote::ThreadIDIsValid(lldb::tid_t thread) { + return thread != 0; } +void ThreadGDBRemote::Dump(Log *log, uint32_t index) {} -bool -ThreadGDBRemote::ShouldStop (bool &step_more) -{ - return true; -} -lldb::RegisterContextSP -ThreadGDBRemote::GetRegisterContext () -{ - if (m_reg_context_sp.get() == NULL) - m_reg_context_sp = CreateRegisterContextForFrame (NULL); - return m_reg_context_sp; +bool ThreadGDBRemote::ShouldStop(bool &step_more) { return true; } +lldb::RegisterContextSP ThreadGDBRemote::GetRegisterContext() { + if (m_reg_context_sp.get() == NULL) + m_reg_context_sp = CreateRegisterContextForFrame(NULL); + return m_reg_context_sp; } lldb::RegisterContextSP -ThreadGDBRemote::CreateRegisterContextForFrame (StackFrame *frame) -{ - lldb::RegisterContextSP reg_ctx_sp; - uint32_t concrete_frame_idx = 0; - - if (frame) - concrete_frame_idx = frame->GetConcreteFrameIndex (); - - - if (concrete_frame_idx == 0) - { - ProcessSP process_sp (GetProcess()); - if (process_sp) - { - ProcessGDBRemote *gdb_process = static_cast<ProcessGDBRemote *>(process_sp.get()); - // read_all_registers_at_once will be true if 'p' packet is not supported. - bool read_all_registers_at_once = !gdb_process->GetGDBRemote().GetpPacketSupported (GetID()); - reg_ctx_sp.reset (new GDBRemoteRegisterContext (*this, concrete_frame_idx, gdb_process->m_register_info, read_all_registers_at_once)); - } - } - else - { - Unwind *unwinder = GetUnwinder (); - if (unwinder) - reg_ctx_sp = unwinder->CreateRegisterContextForFrame (frame); +ThreadGDBRemote::CreateRegisterContextForFrame(StackFrame *frame) { + lldb::RegisterContextSP reg_ctx_sp; + uint32_t concrete_frame_idx = 0; + + if (frame) + concrete_frame_idx = frame->GetConcreteFrameIndex(); + + if (concrete_frame_idx == 0) { + ProcessSP process_sp(GetProcess()); + if (process_sp) { + ProcessGDBRemote *gdb_process = + static_cast<ProcessGDBRemote *>(process_sp.get()); + // read_all_registers_at_once will be true if 'p' packet is not supported. + bool read_all_registers_at_once = + !gdb_process->GetGDBRemote().GetpPacketSupported(GetID()); + reg_ctx_sp.reset(new GDBRemoteRegisterContext( + *this, concrete_frame_idx, gdb_process->m_register_info, + read_all_registers_at_once)); } - return reg_ctx_sp; + } else { + Unwind *unwinder = GetUnwinder(); + if (unwinder) + reg_ctx_sp = unwinder->CreateRegisterContextForFrame(frame); + } + return reg_ctx_sp; } -bool -ThreadGDBRemote::PrivateSetRegisterValue (uint32_t reg, StringExtractor &response) -{ - GDBRemoteRegisterContext *gdb_reg_ctx = static_cast<GDBRemoteRegisterContext *>(GetRegisterContext ().get()); - assert (gdb_reg_ctx); - return gdb_reg_ctx->PrivateSetRegisterValue (reg, response); +bool ThreadGDBRemote::PrivateSetRegisterValue(uint32_t reg, + llvm::ArrayRef<uint8_t> data) { + GDBRemoteRegisterContext *gdb_reg_ctx = + static_cast<GDBRemoteRegisterContext *>(GetRegisterContext().get()); + assert(gdb_reg_ctx); + return gdb_reg_ctx->PrivateSetRegisterValue(reg, data); } -bool -ThreadGDBRemote::PrivateSetRegisterValue (uint32_t reg, uint64_t regval) -{ - GDBRemoteRegisterContext *gdb_reg_ctx = static_cast<GDBRemoteRegisterContext *>(GetRegisterContext ().get()); - assert (gdb_reg_ctx); - return gdb_reg_ctx->PrivateSetRegisterValue (reg, regval); +bool ThreadGDBRemote::PrivateSetRegisterValue(uint32_t reg, uint64_t regval) { + GDBRemoteRegisterContext *gdb_reg_ctx = + static_cast<GDBRemoteRegisterContext *>(GetRegisterContext().get()); + assert(gdb_reg_ctx); + return gdb_reg_ctx->PrivateSetRegisterValue(reg, regval); } -bool -ThreadGDBRemote::CalculateStopInfo () -{ - ProcessSP process_sp (GetProcess()); - if (process_sp) - return static_cast<ProcessGDBRemote *>(process_sp.get())->CalculateThreadStopInfo(this); - return false; +bool ThreadGDBRemote::CalculateStopInfo() { + ProcessSP process_sp(GetProcess()); + if (process_sp) + return static_cast<ProcessGDBRemote *>(process_sp.get()) + ->CalculateThreadStopInfo(this); + return false; } - - diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h index d7619f4..27caf42 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h @@ -27,126 +27,94 @@ namespace process_gdb_remote { class ProcessGDBRemote; -class ThreadGDBRemote : public Thread -{ +class ThreadGDBRemote : public Thread { public: - ThreadGDBRemote (Process &process, lldb::tid_t tid); + ThreadGDBRemote(Process &process, lldb::tid_t tid); - ~ThreadGDBRemote() override; + ~ThreadGDBRemote() override; - void - WillResume (lldb::StateType resume_state) override; + void WillResume(lldb::StateType resume_state) override; - void - RefreshStateAfterStop() override; + void RefreshStateAfterStop() override; - const char * - GetName () override; + const char *GetName() override; - const char * - GetQueueName () override; + const char *GetQueueName() override; - lldb::QueueKind - GetQueueKind () override; + lldb::QueueKind GetQueueKind() override; - lldb::queue_id_t - GetQueueID () override; + lldb::queue_id_t GetQueueID() override; - lldb::QueueSP - GetQueue () override; + lldb::QueueSP GetQueue() override; - lldb::addr_t - GetQueueLibdispatchQueueAddress () override; + lldb::addr_t GetQueueLibdispatchQueueAddress() override; - void - SetQueueLibdispatchQueueAddress (lldb::addr_t dispatch_queue_t) override; + void SetQueueLibdispatchQueueAddress(lldb::addr_t dispatch_queue_t) override; - bool - ThreadHasQueueInformation () const override; + bool ThreadHasQueueInformation() const override; - lldb::RegisterContextSP - GetRegisterContext () override; + lldb::RegisterContextSP GetRegisterContext() override; - lldb::RegisterContextSP - CreateRegisterContextForFrame (StackFrame *frame) override; + lldb::RegisterContextSP + CreateRegisterContextForFrame(StackFrame *frame) override; - void - Dump (Log *log, uint32_t index); + void Dump(Log *log, uint32_t index); - static bool - ThreadIDIsValid (lldb::tid_t thread); + static bool ThreadIDIsValid(lldb::tid_t thread); - bool - ShouldStop (bool &step_more); + bool ShouldStop(bool &step_more); - const char * - GetBasicInfoAsString (); + const char *GetBasicInfoAsString(); - void - SetName (const char *name) override - { - if (name && name[0]) - m_thread_name.assign (name); - else - m_thread_name.clear(); - } + void SetName(const char *name) override { + if (name && name[0]) + m_thread_name.assign(name); + else + m_thread_name.clear(); + } - lldb::addr_t - GetThreadDispatchQAddr () - { - return m_thread_dispatch_qaddr; - } + lldb::addr_t GetThreadDispatchQAddr() { return m_thread_dispatch_qaddr; } - void - SetThreadDispatchQAddr (lldb::addr_t thread_dispatch_qaddr) - { - m_thread_dispatch_qaddr = thread_dispatch_qaddr; - } + void SetThreadDispatchQAddr(lldb::addr_t thread_dispatch_qaddr) { + m_thread_dispatch_qaddr = thread_dispatch_qaddr; + } - void - ClearQueueInfo (); - - void - SetQueueInfo (std::string &&queue_name, lldb::QueueKind queue_kind, uint64_t queue_serial, lldb::addr_t dispatch_queue_t, lldb_private::LazyBool associated_with_libdispatch_queue); + void ClearQueueInfo(); - lldb_private::LazyBool - GetAssociatedWithLibdispatchQueue () override; + void SetQueueInfo(std::string &&queue_name, lldb::QueueKind queue_kind, + uint64_t queue_serial, lldb::addr_t dispatch_queue_t, + lldb_private::LazyBool associated_with_libdispatch_queue); - void - SetAssociatedWithLibdispatchQueue (lldb_private::LazyBool associated_with_libdispatch_queue) override; + lldb_private::LazyBool GetAssociatedWithLibdispatchQueue() override; - StructuredData::ObjectSP - FetchThreadExtendedInfo () override; + void SetAssociatedWithLibdispatchQueue( + lldb_private::LazyBool associated_with_libdispatch_queue) override; + + StructuredData::ObjectSP FetchThreadExtendedInfo() override; protected: - friend class ProcessGDBRemote; - - std::string m_thread_name; - std::string m_dispatch_queue_name; - lldb::addr_t m_thread_dispatch_qaddr; - lldb::addr_t m_dispatch_queue_t; - lldb::QueueKind m_queue_kind; // Queue info from stop reply/stop info for thread - uint64_t m_queue_serial_number; // Queue info from stop reply/stop info for thread - lldb_private::LazyBool m_associated_with_libdispatch_queue; - - bool - PrivateSetRegisterValue (uint32_t reg, - StringExtractor &response); - - bool - PrivateSetRegisterValue (uint32_t reg, - uint64_t regval); - - bool - CachedQueueInfoIsValid() const - { - return m_queue_kind != lldb::eQueueKindUnknown; - } - void - SetStopInfoFromPacket (StringExtractor &stop_packet, uint32_t stop_id); - - bool - CalculateStopInfo () override; + friend class ProcessGDBRemote; + + std::string m_thread_name; + std::string m_dispatch_queue_name; + lldb::addr_t m_thread_dispatch_qaddr; + lldb::addr_t m_dispatch_queue_t; + lldb::QueueKind + m_queue_kind; // Queue info from stop reply/stop info for thread + uint64_t + m_queue_serial_number; // Queue info from stop reply/stop info for thread + lldb_private::LazyBool m_associated_with_libdispatch_queue; + + bool PrivateSetRegisterValue(uint32_t reg, llvm::ArrayRef<uint8_t> data); + + bool PrivateSetRegisterValue(uint32_t reg, uint64_t regval); + + bool CachedQueueInfoIsValid() const { + return m_queue_kind != lldb::eQueueKindUnknown; + } + void SetStopInfoFromPacket(StringExtractor &stop_packet, uint32_t stop_id); + + bool CalculateStopInfo() override; }; } // namespace process_gdb_remote |