diff options
author | dim <dim@FreeBSD.org> | 2015-12-30 11:55:28 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2015-12-30 11:55:28 +0000 |
commit | 66b75430a93929d6fc6ed63db14ca28e3ad5b1f6 (patch) | |
tree | 9ed5e1a91f242e2cb5911577356e487a55c01b78 /source/Plugins/Process/gdb-remote | |
parent | 23814158e5384f73c6fa951b66d5f807f9c24a2b (diff) | |
download | FreeBSD-src-66b75430a93929d6fc6ed63db14ca28e3ad5b1f6.zip FreeBSD-src-66b75430a93929d6fc6ed63db14ca28e3ad5b1f6.tar.gz |
Vendor import of stripped lldb trunk r256633:
https://llvm.org/svn/llvm-project/lldb/trunk@256633
Diffstat (limited to 'source/Plugins/Process/gdb-remote')
17 files changed, 2058 insertions, 1312 deletions
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index 9c263c8..2ea1f20 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -30,6 +30,7 @@ #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" @@ -574,15 +575,24 @@ GDBRemoteCommunication::DecompressPacket () return true; if (m_bytes[1] != 'C' && m_bytes[1] != 'N') return true; - if (m_bytes[pkt_size - 3] != '#') + + 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[pkt_size - 2]) || !::isxdigit (m_bytes[pkt_size - 1])) + + 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 hash_mark_idx = pkt_size - 3; // The '#' character marking the end of the packet - size_t checksum_idx = pkt_size - 2; // The first character of the two hex checksum characters + 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 @@ -604,7 +614,7 @@ GDBRemoteCommunication::DecompressPacket () decompressed_bufsize = ::strtoul (bufsize_str.c_str(), NULL, 10); if (errno != 0 || decompressed_bufsize == ULONG_MAX) { - m_bytes.erase (0, pkt_size); + m_bytes.erase (0, size_of_first_packet); return false; } } @@ -633,7 +643,7 @@ GDBRemoteCommunication::DecompressPacket () if (!success) { SendNack(); - m_bytes.erase (0, pkt_size); + m_bytes.erase (0, size_of_first_packet); return false; } else @@ -677,7 +687,7 @@ GDBRemoteCommunication::DecompressPacket () decompressed_buffer = (uint8_t *) malloc (decompressed_bufsize + 1); if (decompressed_buffer == nullptr) { - m_bytes.erase (0, pkt_size); + m_bytes.erase (0, size_of_first_packet); return false; } @@ -751,7 +761,7 @@ GDBRemoteCommunication::DecompressPacket () { if (decompressed_buffer) free (decompressed_buffer); - m_bytes.erase (0, pkt_size); + m_bytes.erase (0, size_of_first_packet); return false; } @@ -773,7 +783,7 @@ GDBRemoteCommunication::DecompressPacket () new_packet.push_back ('0'); } - m_bytes = new_packet; + m_bytes.replace (0, size_of_first_packet, new_packet.data(), new_packet.size()); free (decompressed_buffer); return true; @@ -927,8 +937,10 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri { for (size_t i=0; !binary && i<total_length; ++i) { - if (isprint(m_bytes[i]) == 0) + if (isprint (m_bytes[i]) == 0 && isspace (m_bytes[i]) == 0) + { binary = true; + } } } if (binary) @@ -1100,16 +1112,16 @@ GDBRemoteCommunication::ListenThread (lldb::thread_arg_t arg) } Error -GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, - uint16_t in_port, +GDBRemoteCommunication::StartDebugserverProcess (const char *url, + Platform *platform, ProcessLaunchInfo &launch_info, - uint16_t &out_port) + uint16_t *port, + const Args& inferior_args) { Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); if (log) - log->Printf ("GDBRemoteCommunication::%s(hostname=%s, in_port=%" PRIu16 ", out_port=%" PRIu16, __FUNCTION__, hostname ? hostname : "<empty>", in_port, out_port); + log->Printf ("GDBRemoteCommunication::%s(url=%s, port=%" PRIu16, __FUNCTION__, url ? url : "<empty>", port ? *port : uint16_t(0)); - out_port = in_port; Error error; // If we locate debugserver, keep that located version around static FileSpec g_debugserver_file_spec; @@ -1146,11 +1158,20 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, } else { - if (log) - log->Printf ("GDBRemoteCommunication::%s() could not find gdb-remote stub exe '%s'", __FUNCTION__, debugserver_file_spec.GetPath ().c_str ()); - + 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(); - debugserver_file_spec.Clear(); } } } @@ -1171,17 +1192,9 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, debugserver_args.AppendArgument("gdbserver"); #endif - // If a host and port is supplied then use it - char host_and_port[128]; - if (hostname) - { - snprintf (host_and_port, sizeof(host_and_port), "%s:%u", hostname, in_port); - debugserver_args.AppendArgument(host_and_port); - } - else - { - host_and_port[0] = '\0'; - } + // If a url is supplied then use it + if (url) + debugserver_args.AppendArgument(url); // use native registers, not the GDB registers debugserver_args.AppendArgument("--native-regs"); @@ -1192,30 +1205,41 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, } llvm::SmallString<PATH_MAX> named_pipe_path; - Pipe port_pipe; - - if (host_and_port[0] && in_port == 0) + // 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) { - // 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" - - // Binding to port zero, we need to figure out what port it ends up - // using using a named pipe... - error = port_pipe.CreateWithUniqueName("debugserver-named-pipe", false, named_pipe_path); - if (error.Success()) + 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 - { - if (log) - log->Printf("GDBRemoteCommunication::%s() " - "named pipe creation failed: %s", - __FUNCTION__, error.AsCString()); - // let's try an unnamed pipe - error = port_pipe.CreateNew(true); +#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) @@ -1224,42 +1248,43 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, __FUNCTION__, error.AsCString()); return error; } - int write_fd = port_pipe.GetWriteFileDescriptor(); + int write_fd = socket_pipe.GetWriteFileDescriptor(); debugserver_args.AppendArgument("--pipe"); debugserver_args.AppendArgument(std::to_string(write_fd).c_str()); - launch_info.AppendCloseFileAction(port_pipe.GetReadFileDescriptor()); - } - } - 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 - out_port = connection->GetListeningPort(10); - if (out_port > 0) - { - char port_cstr[32]; - snprintf(port_cstr, sizeof(port_cstr), "127.0.0.1:%i", out_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); + launch_info.AppendCloseFileAction(socket_pipe.GetReadFileDescriptor()); +#endif } 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; + // 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; + } } } @@ -1304,6 +1329,20 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, } } while (has_env_var); + if (inferior_args.GetArgumentCount() > 0) + { + debugserver_args.AppendArgument ("--"); + debugserver_args.AppendArguments (inferior_args); + } + + // 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()); + } + // Close STDIN, STDOUT and STDERR. launch_info.AppendCloseFileAction (STDIN_FILENO); launch_info.AppendCloseFileAction (STDOUT_FILENO); @@ -1316,11 +1355,12 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, error = Host::LaunchProcess(launch_info); - if (error.Success() && launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) + if (error.Success() && + launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) { if (named_pipe_path.size() > 0) { - error = port_pipe.OpenAsReader(named_pipe_path, false); + error = socket_pipe.OpenAsReader(named_pipe_path, false); if (error.Fail()) if (log) log->Printf("GDBRemoteCommunication::%s() " @@ -1328,24 +1368,24 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, __FUNCTION__, named_pipe_path.c_str(), error.AsCString()); } - if (port_pipe.CanWrite()) - port_pipe.CloseWriteFileDescriptor(); - if (port_pipe.CanRead()) + if (socket_pipe.CanWrite()) + socket_pipe.CloseWriteFileDescriptor(); + if (socket_pipe.CanRead()) { - char port_cstr[256]; + 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 = port_pipe.ReadWithTimeout(port_cstr, num_bytes, + error = socket_pipe.ReadWithTimeout(port_cstr, num_bytes, std::chrono::seconds{10}, num_bytes); - if (error.Success()) + if (error.Success() && (port != nullptr)) { assert(num_bytes > 0 && port_cstr[num_bytes-1] == '\0'); - out_port = StringConvert::ToUInt32(port_cstr, 0); + *port = StringConvert::ToUInt32(port_cstr, 0); if (log) log->Printf("GDBRemoteCommunication::%s() " - "debugserver listens %u port", - __FUNCTION__, out_port); + "debugserver listens %u port", + __FUNCTION__, *port); } else { @@ -1355,12 +1395,12 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, __FUNCTION__, named_pipe_path.c_str(), error.AsCString()); } - port_pipe.Close(); + socket_pipe.Close(); } if (named_pipe_path.size() > 0) { - const auto err = port_pipe.Delete(named_pipe_path); + const auto err = socket_pipe.Delete(named_pipe_path); if (err.Fail()) { if (log) diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h index 7379bb3..2a01bce 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h @@ -12,9 +12,9 @@ // C Includes // C++ Includes -#include <list> #include <string> #include <queue> +#include <vector> // Other libraries and framework includes // Project includes @@ -25,6 +25,7 @@ #include "lldb/Host/Mutex.h" #include "lldb/Host/Predicate.h" #include "lldb/Host/TimeValue.h" +#include "lldb/Interpreter/Args.h" #include "Utility/StringExtractorGDBRemote.h" @@ -94,14 +95,10 @@ public: uint32_t m_saved_timeout; }; - //------------------------------------------------------------------ - // Constructors and Destructors - //------------------------------------------------------------------ GDBRemoteCommunication(const char *comm_name, const char *listener_name); - virtual - ~GDBRemoteCommunication(); + ~GDBRemoteCommunication() override; PacketResult GetAck (); @@ -117,12 +114,13 @@ public: size_t payload_length); bool - GetSequenceMutex (Mutex::Locker& locker, const char *failure_message = NULL); + GetSequenceMutex(Mutex::Locker& locker, const char *failure_message = nullptr); PacketType CheckForPacket (const uint8_t *src, size_t src_len, StringExtractorGDBRemote &packet); + bool IsRunning() const { @@ -162,21 +160,22 @@ public: { return m_packet_timeout * TimeValue::MicroSecPerSec; } + //------------------------------------------------------------------ // Start a debugserver instance on the current host using the // supplied connection URL. //------------------------------------------------------------------ Error - StartDebugserverProcess (const char *hostname, - uint16_t in_port, // If set to zero, then out_port will contain the bound port on exit - ProcessLaunchInfo &launch_info, - uint16_t &out_port); + 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: @@ -223,6 +222,7 @@ protected: AddPacket (char packet_char, PacketType type, uint32_t bytes_transmitted); + void AddPacket (const std::string &src, uint32_t src_len, @@ -241,7 +241,7 @@ protected: return m_dumped_to_log; } -protected: + protected: uint32_t GetFirstSavedPacketIndex () const { @@ -275,13 +275,30 @@ protected: 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); @@ -321,27 +338,6 @@ protected: bool DecompressPacket (); - //------------------------------------------------------------------ - // Classes that inherit from GDBRemoteCommunication can see and modify these - //------------------------------------------------------------------ - 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; - Error StartListenThread (const char *hostname = "127.0.0.1", uint16_t port = 0); @@ -361,10 +357,12 @@ protected: // This method is defined as part of communication.h // when the read thread gets any bytes it will pass them on to this function - virtual void AppendBytesToCache (const uint8_t * bytes, size_t len, bool broadcast, lldb::ConnectionStatus status); + 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 @@ -372,13 +370,10 @@ private: HostThread m_listen_thread; std::string m_listen_url; - //------------------------------------------------------------------ - // For GDBRemoteCommunication only - //------------------------------------------------------------------ DISALLOW_COPY_AND_ASSIGN (GDBRemoteCommunication); }; } // namespace process_gdb_remote } // namespace lldb_private -#endif // liblldb_GDBRemoteCommunication_h_ +#endif // liblldb_GDBRemoteCommunication_h_ diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index b8c67c5..5c7f6ca 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -619,7 +619,6 @@ GDBRemoteCommunicationClient::GetThreadsInfo() if (m_supports_jThreadsInfo) { StringExtractorGDBRemote response; - m_supports_jThreadExtendedInfo = eLazyBoolNo; if (SendPacketAndWaitForResponse("jThreadsInfo", response, false) == PacketResult::Success) { if (response.IsUnsupportedResponse()) @@ -782,7 +781,7 @@ GDBRemoteCommunicationClient::SendPacketAndWaitForResponse Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); // In order to stop async notifications from being processed in the middle of the - // send/recieve sequence Hijack the broadcast. Then rebroadcast any events when we are done. + // send/receive sequence Hijack the broadcast. Then rebroadcast any events when we are done. static Listener hijack_listener("lldb.NotifyHijacker"); HijackBroadcaster(&hijack_listener, eBroadcastBitGdbReadThreadGotNotify); @@ -878,10 +877,10 @@ GDBRemoteCommunicationClient::SendPacketAndWaitForResponse } } - // Remove our Hijacking listner from the broadcast. + // Remove our Hijacking listener from the broadcast. RestoreBroadcaster(); - // If a notification event occured, rebroadcast since it can now be processed safely. + // If a notification event occurred, rebroadcast since it can now be processed safely. EventSP event_sp; if (hijack_listener.GetNextEvent(event_sp)) BroadcastEvent(event_sp); @@ -1050,7 +1049,6 @@ GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse Mutex::Locker locker(m_sequence_mutex); StateType state = eStateRunning; - BroadcastEvent(eBroadcastBitRunPacketSent, NULL); 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... @@ -1060,6 +1058,7 @@ GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse const auto sigint_signo = process->GetUnixSignals()->GetSignalNumberFromName("SIGINT"); bool got_async_packet = false; + bool broadcast_sent = false; while (state == eStateRunning) { @@ -1072,6 +1071,12 @@ GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse else m_interrupt_sent = false; + if (! broadcast_sent) + { + BroadcastEvent(eBroadcastBitRunPacketSent, NULL); + broadcast_sent = true; + } + m_private_is_running.SetValue (true, eBroadcastAlways); } @@ -1133,10 +1138,10 @@ GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse continue_after_async = false; // We didn't get a SIGINT or SIGSTOP, so try for a - // very brief time (1 ms) to get another stop reply + // 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 = 1000; + uint32_t timeout_usec = 100000; if (ReadPacket (extra_stop_reply_packet, timeout_usec, false) == PacketResult::Success) { switch (extra_stop_reply_packet.GetChar()) @@ -1262,9 +1267,13 @@ GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse got_async_packet = true; std::string inferior_stdout; inferior_stdout.reserve(response.GetBytesLeft () / 2); - char ch; - while ((ch = response.GetHexU8()) != '\0') - inferior_stdout.append(1, ch); + + 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; @@ -1574,6 +1583,8 @@ GDBRemoteCommunicationClient::SendEnvironmentPacket (char const *name_equal_valu { case '$': case '#': + case '*': + case '}': send_hex_encoding = true; break; default: @@ -2308,7 +2319,8 @@ GDBRemoteCommunicationClient::Detach (bool keep_stopped) 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) + if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success + && response.IsOKResponse()) { m_supports_detach_stay_stopped = eLazyBoolYes; } @@ -2326,7 +2338,7 @@ GDBRemoteCommunicationClient::Detach (bool keep_stopped) else { StringExtractorGDBRemote response; - PacketResult packet_result = SendPacketAndWaitForResponse ("D1", 1, response, false); + PacketResult packet_result = SendPacketAndWaitForResponse ("D1", 2, response, false); if (packet_result != PacketResult::Success) error.SetErrorString ("Sending extended disconnect packet failed."); } @@ -3311,10 +3323,16 @@ GDBRemoteCommunicationClient::SendSpeedTestPacket (uint32_t send_size, uint32_t return SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success; } -uint16_t -GDBRemoteCommunicationClient::LaunchGDBserverAndGetPort (lldb::pid_t &pid, const char *remote_accept_hostname) +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;"); @@ -3339,22 +3357,67 @@ GDBRemoteCommunicationClient::LaunchGDBserverAndGetPort (lldb::pid_t &pid, const // 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; - uint16_t port = 0; + 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; + } } - return port; + return true; } - return 0; + return false; +} + +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; + + StructuredData::ObjectSP data = StructuredData::ParseJSON(response.GetStringRef()); + if (!data) + 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; + + 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(); + + if (port != 0 || !socket_name.empty()) + connection_urls.emplace_back(port, socket_name); + } + return connection_urls.size(); } bool @@ -3395,6 +3458,17 @@ GDBRemoteCommunicationClient::SetCurrentThread (uint64_t tid) 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; } @@ -3421,6 +3495,17 @@ GDBRemoteCommunicationClient::SetCurrentThreadForRun (uint64_t tid) 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; } @@ -3546,6 +3631,17 @@ GDBRemoteCommunicationClient::GetCurrentThreadIDs (std::vector<lldb::tid_t> &thr } 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 { @@ -4347,100 +4443,97 @@ GDBRemoteCommunicationClient::ServeSymbolLookups(lldb_private::Process *process) { StreamString packet; packet.PutCString ("qSymbol::"); - while (1) + StringExtractorGDBRemote response; + while (SendPacketAndWaitForResponseNoLock(packet.GetData(), packet.GetSize(), response) == PacketResult::Success) { - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponseNoLock(packet.GetData(), packet.GetSize(), response) == PacketResult::Success) + if (response.IsOKResponse()) { - if (response.IsOKResponse()) - { - // We are done serving symbols requests - return; - } + // We are done serving symbols requests + return; + } - if (response.IsUnsupportedResponse()) - { - // qSymbol is not supported by the current GDB server we are connected to - m_supports_qSymbol = false; - return; - } - else + 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:")) { - llvm::StringRef response_str(response.GetStringRef()); - if (response_str.startswith("qSymbol:")) + response.SetFilePos(strlen("qSymbol:")); + std::string symbol_name; + if (response.GetHexByteString(symbol_name)) { - response.SetFilePos(strlen("qSymbol:")); - std::string symbol_name; - if (response.GetHexByteString(symbol_name)) - { - if (symbol_name.empty()) - return; + 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)) + 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) { - 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)) { - SymbolContext sc; - if (sc_list.GetContextAtIndex(sc_idx, sc)) + if (sc.symbol) { - if (sc.symbol) + switch (sc.symbol->GetType()) { - 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; - } + 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); - 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 } + // 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); + 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 } } } diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index b08ff06..d2df214 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -12,6 +12,8 @@ // C Includes // C++ Includes +#include <map> +#include <string> #include <vector> // Other libraries and framework includes @@ -28,12 +30,9 @@ namespace process_gdb_remote { class GDBRemoteCommunicationClient : public GDBRemoteCommunication { public: - //------------------------------------------------------------------ - // Constructors and Destructors - //------------------------------------------------------------------ GDBRemoteCommunicationClient(); - ~GDBRemoteCommunicationClient(); + ~GDBRemoteCommunicationClient() override; //------------------------------------------------------------------ // After connecting, send the handshake to the server to make sure @@ -79,6 +78,7 @@ public: const char *packet_payload, size_t packet_length, StringExtractorGDBRemote &response); + bool SendvContPacket (ProcessGDBRemote *process, const char *payload, @@ -114,9 +114,15 @@ public: bool GetLaunchSuccess (std::string &error_str); - uint16_t - LaunchGDBserverAndGetPort (lldb::pid_t &pid, const char *remote_accept_hostname); - + 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); @@ -161,7 +167,7 @@ public: SendLaunchArchPacket (const char *arch); int - SendLaunchEventDataPacket (const char *data, bool *was_supported = NULL); + SendLaunchEventDataPacket(const char *data, bool *was_supported = nullptr); //------------------------------------------------------------------ /// Sends a "vAttach:PID" where PID is in hex. @@ -182,7 +188,6 @@ public: SendAttach (lldb::pid_t pid, StringExtractorGDBRemote& response); - //------------------------------------------------------------------ /// Sends a GDB remote protocol 'I' packet that delivers stdin /// data to the remote process. @@ -396,6 +401,7 @@ public: default: return false; } } + uint8_t SendGDBStoppointTypePacket (GDBStoppointType type, // Type of breakpoint or watchpoint bool insert, // Insert or remove? @@ -505,11 +511,11 @@ public: GetFileExists (const FileSpec& file_spec); Error - RunShellCommand(const char *command, // Shouldn't be NULL + 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 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 + 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 @@ -567,26 +573,6 @@ public: ServeSymbolLookups(lldb_private::Process *process); protected: - - 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); - - //------------------------------------------------------------------ - // Classes that inherit from GDBRemoteCommunicationClient can see and modify these - //------------------------------------------------------------------ LazyBool m_supports_not_sending_acks; LazyBool m_supports_thread_suffix; LazyBool m_supports_threads_in_stop_reply; @@ -639,7 +625,6 @@ protected: 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 @@ -667,18 +652,31 @@ protected: 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); + private: - //------------------------------------------------------------------ - // For GDBRemoteCommunicationClient only - //------------------------------------------------------------------ DISALLOW_COPY_AND_ASSIGN (GDBRemoteCommunicationClient); }; } // namespace process_gdb_remote } // namespace lldb_private -#endif // liblldb_GDBRemoteCommunicationClient_h_ +#endif // liblldb_GDBRemoteCommunicationClient_h_ diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h index 44c0f6a..1d512bf 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h @@ -39,8 +39,7 @@ public: GDBRemoteCommunicationServer(const char *comm_name, const char *listener_name); - virtual - ~GDBRemoteCommunicationServer(); + ~GDBRemoteCommunicationServer() override; void RegisterPacketHandler(StringExtractorGDBRemote::ServerPacketType packet_type, PacketHandler handler); @@ -73,13 +72,10 @@ protected: SendOKResponse (); private: - //------------------------------------------------------------------ - // For GDBRemoteCommunicationServer only - //------------------------------------------------------------------ DISALLOW_COPY_AND_ASSIGN (GDBRemoteCommunicationServer); }; } // namespace process_gdb_remote } // namespace lldb_private -#endif // liblldb_GDBRemoteCommunicationServer_h_ +#endif // liblldb_GDBRemoteCommunicationServer_h_ diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp index 698854e..7f876fb 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp @@ -58,8 +58,6 @@ using namespace lldb_private::process_gdb_remote; //---------------------------------------------------------------------- GDBRemoteCommunicationServerCommon::GDBRemoteCommunicationServerCommon(const char *comm_name, const char *listener_name) : GDBRemoteCommunicationServer (comm_name, listener_name), - m_spawned_pids (), - m_spawned_pids_mutex (Mutex::eMutexTypeRecursive), m_process_launch_info (), m_process_launch_error (), m_proc_infos (), @@ -79,8 +77,6 @@ GDBRemoteCommunicationServerCommon::GDBRemoteCommunicationServerCommon(const cha &GDBRemoteCommunicationServerCommon::Handle_qGroupName); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qHostInfo, &GDBRemoteCommunicationServerCommon::Handle_qHostInfo); - RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qKillSpawnedProcess, - &GDBRemoteCommunicationServerCommon::Handle_qKillSpawnedProcess); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QLaunchArch, &GDBRemoteCommunicationServerCommon::Handle_QLaunchArch); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qLaunchSuccess, @@ -185,14 +181,20 @@ GDBRemoteCommunicationServerCommon::Handle_qHostInfo (StringExtractorGDBRemote & else response.Printf("watchpoint_exceptions_received:after;"); #else - if (host_arch.GetMachine() == llvm::Triple::mips64 || - host_arch.GetMachine() == llvm::Triple::mips64el) + 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 - switch (lldb::endian::InlHostByteOrder()) + switch (endian::InlHostByteOrder()) { case eByteOrderBig: response.PutCString ("endian:big;"); break; case eByteOrderLittle: response.PutCString ("endian:little;"); break; @@ -485,94 +487,6 @@ GDBRemoteCommunicationServerCommon::Handle_qSpeedTest (StringExtractorGDBRemote } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerCommon::Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen ("qKillSpawnedProcess:")); - - lldb::pid_t pid = packet.GetU64(LLDB_INVALID_PROCESS_ID); - - // verify that we know anything about this pid. - // Scope for locker - { - Mutex::Locker locker (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); -} - -bool -GDBRemoteCommunicationServerCommon::KillSpawnedProcess (lldb::pid_t pid) -{ - // make sure we know about this process - { - Mutex::Locker locker (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); - - // check if that worked - for (size_t i=0; i<10; ++i) - { - { - Mutex::Locker locker (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 - { - Mutex::Locker locker (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); - - for (size_t i=0; i<10; ++i) - { - { - Mutex::Locker locker (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 - { - Mutex::Locker locker (m_spawned_pids_mutex); - if (m_spawned_pids.find(pid) == m_spawned_pids.end()) - return true; - } - - // no luck - the process still lives - return false; -} - -GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_vFile_Open (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("vFile:open:")); @@ -1299,6 +1213,7 @@ GDBRemoteCommunicationServerCommon::CreateProcessInfoResponse_DebugServerStyle ( switch (proc_triple.getArch ()) { case llvm::Triple::arm: + case llvm::Triple::thumb: case llvm::Triple::aarch64: ostype = "ios"; break; diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h index 62b129b..f55b2eb 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h @@ -12,14 +12,14 @@ // C Includes // C++ Includes -#include <set> +#include <string> // Other libraries and framework includes +// Project includes #include "lldb/lldb-private-forward.h" #include "lldb/Host/Mutex.h" #include "lldb/Target/Process.h" -// Project includes #include "GDBRemoteCommunicationServer.h" #include "GDBRemoteCommunicationServerCommon.h" @@ -36,12 +36,9 @@ class GDBRemoteCommunicationServerCommon : public: GDBRemoteCommunicationServerCommon(const char *comm_name, const char *listener_name); - virtual - ~GDBRemoteCommunicationServerCommon(); + ~GDBRemoteCommunicationServerCommon() override; protected: - std::set<lldb::pid_t> m_spawned_pids; - Mutex m_spawned_pids_mutex; ProcessLaunchInfo m_process_launch_info; Error m_process_launch_error; ProcessInstanceInfoList m_proc_infos; @@ -74,9 +71,6 @@ protected: Handle_qSpeedTest (StringExtractorGDBRemote &packet); PacketResult - Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet); - - PacketResult Handle_vFile_Open (StringExtractorGDBRemote &packet); PacketResult @@ -160,9 +154,6 @@ protected: PacketResult Handle_QLaunchArch (StringExtractorGDBRemote &packet); - bool - KillSpawnedProcess (lldb::pid_t pid); - static void CreateProcessInfoResponse (const ProcessInstanceInfo &proc_info, StreamString &response); @@ -213,4 +204,4 @@ protected: } // namespace process_gdb_remote } // namespace lldb_private -#endif // liblldb_GDBRemoteCommunicationServerCommon_h_ +#endif // liblldb_GDBRemoteCommunicationServerCommon_h_ diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index c452325..921369c 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -43,6 +43,8 @@ #include "lldb/Host/common/NativeRegisterContext.h" #include "lldb/Host/common/NativeProcessProtocol.h" #include "lldb/Host/common/NativeThreadProtocol.h" +#include "lldb/Utility/JSON.h" +#include "lldb/Utility/LLDBAssert.h" // Project includes #include "Utility/StringExtractorGDBRemote.h" @@ -96,20 +98,6 @@ GDBRemoteCommunicationServerLLGS::GDBRemoteCommunicationServerLLGS( RegisterPacketHandlers(); } -//---------------------------------------------------------------------- -// Destructor -//---------------------------------------------------------------------- -GDBRemoteCommunicationServerLLGS::~GDBRemoteCommunicationServerLLGS() -{ - Mutex::Locker locker (m_debugged_process_mutex); - - if (m_debugged_process_sp) - { - m_debugged_process_sp->Terminate (); - m_debugged_process_sp.reset (); - } -} - void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() { @@ -126,7 +114,7 @@ GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_interrupt, &GDBRemoteCommunicationServerLLGS::Handle_interrupt); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_m, - &GDBRemoteCommunicationServerLLGS::Handle_m); + &GDBRemoteCommunicationServerLLGS::Handle_memory_read); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_M, &GDBRemoteCommunicationServerLLGS::Handle_M); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_p, @@ -161,6 +149,8 @@ GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() &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, @@ -175,6 +165,8 @@ GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() &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, @@ -223,6 +215,7 @@ GDBRemoteCommunicationServerLLGS::LaunchProcess () error = NativeProcessProtocol::Launch( m_process_launch_info, *this, + m_mainloop, m_debugged_process_sp); } @@ -274,17 +267,6 @@ GDBRemoteCommunicationServerLLGS::LaunchProcess () 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. - lldb::pid_t pid; - if ((pid = m_process_launch_info.GetProcessID ()) != LLDB_INVALID_PROCESS_ID) - { - // add to spawned pids - Mutex::Locker locker (m_spawned_pids_mutex); - // On an lldb-gdbserver, we would expect there to be only one. - assert (m_spawned_pids.empty () && "lldb-gdbserver adding tracked process but one already existed"); - m_spawned_pids.insert (pid); - } - return error; } @@ -297,48 +279,37 @@ GDBRemoteCommunicationServerLLGS::AttachToProcess (lldb::pid_t pid) if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64, __FUNCTION__, pid); - // Scope for mutex locker. + // 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 ()) { - // Before we try to attach, make sure we aren't already monitoring something else. - Mutex::Locker locker (m_spawned_pids_mutex); - if (!m_spawned_pids.empty ()) - { - error.SetErrorStringWithFormat ("cannot attach to a process %" PRIu64 " when another process with pid %" PRIu64 " is being debugged.", pid, *m_spawned_pids.begin()); - return error; - } + fprintf (stderr, "%s: failed to attach to process %" PRIu64 ": %s", __FUNCTION__, pid, error.AsCString ()); + return error; + } - // Try to attach. - error = NativeProcessProtocol::Attach(pid, *this, m_debugged_process_sp); - if (!error.Success ()) - { - fprintf (stderr, "%s: failed to attach to process %" PRIu64 ": %s", __FUNCTION__, pid, error.AsCString ()); + // 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; - } - - // 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 ("ProcessGDBRemoteCommunicationServerLLGS::%s ignoring inferior STDIO since terminal fd reported as %d", __FUNCTION__, terminal_fd); + } - // Add to list of spawned processes. - assert (m_spawned_pids.empty () && "lldb-gdbserver adding tracked process but one already existed"); - m_spawned_pids.insert (pid); + printf ("Attached to process %" PRIu64 "...\n", pid); - return error; - } + return error; } void @@ -455,6 +426,178 @@ WriteRegisterValueInHexFixedWidth (StreamString &response, } } +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>(); + +#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; +#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. +#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 + } + 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(); + + // 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, + __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)); + + 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); + } + + // TODO: Expedite interesting regions of inferior memory + } + + return threads_array_sp; +} + GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread (lldb::tid_t tid) { @@ -548,6 +691,31 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread (lldb::tid_t tid) 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()); + + } } // @@ -595,34 +763,7 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread (lldb::tid_t tid) } } - const char* reason_str = nullptr; - switch (tid_stop_info.reason) - { - case eStopReasonTrace: - reason_str = "trace"; - break; - case eStopReasonBreakpoint: - reason_str = "breakpoint"; - break; - case eStopReasonWatchpoint: - reason_str = "watchpoint"; - break; - case eStopReasonSignal: - reason_str = "signal"; - break; - case eStopReasonException: - reason_str = "exception"; - break; - case eStopReasonExec: - reason_str = "exec"; - break; - case eStopReasonInstrumentation: - case eStopReasonInvalid: - case eStopReasonPlanComplete: - case eStopReasonThreadExiting: - case eStopReasonNone: - break; - } + const char* reason_str = GetStopReasonString(tid_stop_info.reason); if (reason_str != nullptr) { response.Printf ("reason:%s;", reason_str); @@ -663,43 +804,15 @@ GDBRemoteCommunicationServerLLGS::HandleInferiorState_Exited (NativeProcessProto if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__); - // Send the exit result, and don't flush output. - // Note: flushing output here would join the inferior stdio reflection thread, which - // would gunk up the waitpid monitor thread that is calling this. - PacketResult result = SendStopReasonForState (StateType::eStateExited, false); + 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 ()); } - // Remove the process from the list of spawned pids. - { - Mutex::Locker locker (m_spawned_pids_mutex); - if (m_spawned_pids.erase (process->GetID ()) < 1) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to remove PID %" PRIu64 " from the spawned pids list", __FUNCTION__, process->GetID ()); - - } - } - - // FIXME can't do this yet - since process state propagation is currently - // synchronous, it is running off the NativeProcessProtocol's innards and - // will tear down the NPP while it still has code to execute. -#if 0 - // Clear the NativeProcessProtocol pointer. - { - Mutex::Locker locker (m_debugged_process_mutex); - m_debugged_process_sp.reset(); - } -#endif - // Close the pipe to the inferior terminal i/o if we launched it - // and set one up. Otherwise, 'k' and its flush of stdio could - // end up waiting on a thread join that will never end. Consider - // adding a timeout to the connection thread join call so we - // can avoid that scenario altogether. + // and set one up. MaybeCloseInferiorTerminalConnection (); // We are ready to exit the debug monitor. @@ -725,7 +838,7 @@ GDBRemoteCommunicationServerLLGS::HandleInferiorState_Stopped (NativeProcessProt break; default: // In all other cases, send the stop reason. - PacketResult result = SendStopReasonForState (StateType::eStateStopped, false); + PacketResult result = SendStopReasonForState(StateType::eStateStopped); if (result != PacketResult::Success) { if (log) @@ -748,21 +861,30 @@ GDBRemoteCommunicationServerLLGS::ProcessStateChanged (NativeProcessProtocol *pr StateAsCString (state)); } - // 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 - m_stdio_communication.SynchronizeWithReadThread(); - switch (state) { - case StateType::eStateExited: - HandleInferiorState_Exited (process); + 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; + default: if (log) { @@ -796,7 +918,6 @@ GDBRemoteCommunicationServerLLGS::DataAvailableCallback () if(log) log->Printf("GDBRemoteCommunicationServerLLGS::%s handshake with client failed, exiting", __FUNCTION__); - m_read_handle_up.reset(); m_mainloop.RequestTermination(); return; } @@ -817,7 +938,6 @@ GDBRemoteCommunicationServerLLGS::DataAvailableCallback () if(log) log->Printf("GDBRemoteCommunicationServerLLGS::%s processing a packet failed: %s", __FUNCTION__, error.AsCString()); - m_read_handle_up.reset(); m_mainloop.RequestTermination(); break; } @@ -831,7 +951,7 @@ GDBRemoteCommunicationServerLLGS::InitializeConnection (std::unique_ptr<Connecti GDBRemoteCommunicationServer::SetConnection(connection.release()); Error error; - m_read_handle_up = m_mainloop.RegisterReadObject(read_object_sp, + m_network_handle_up = m_mainloop.RegisterReadObject(read_object_sp, [this] (MainLoopBase &) { DataAvailableCallback(); }, error); return error; } @@ -857,7 +977,7 @@ GDBRemoteCommunicationServerLLGS::SetSTDIOFileDescriptor (int fd) { Error error; - // Set up the Read Thread for reading/handling process I/O + // Set up the reading/handling of process I/O std::unique_ptr<ConnectionFileDescriptor> conn_up (new ConnectionFileDescriptor (fd, true)); if (!conn_up) { @@ -873,29 +993,73 @@ GDBRemoteCommunicationServerLLGS::SetSTDIOFileDescriptor (int fd) return error; } + return Error(); +} + +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) == nullptr || - m_process_launch_info.GetFileActionForFD(STDERR_FILENO) == nullptr - ) + 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) { - // output from the process must be forwarded over gdb-remote - // create a thread to read the handle and send the data - m_stdio_communication.SetReadThreadBytesReceivedCallback (STDIOReadThreadBytesReceived, this); - m_stdio_communication.StartReadThread(); + // 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()); } +} - return error; +void +GDBRemoteCommunicationServerLLGS::StopSTDIOForwarding() +{ + m_stdio_handle_up.reset(); } void -GDBRemoteCommunicationServerLLGS::STDIOReadThreadBytesReceived (void *baton, const void *src, size_t src_len) +GDBRemoteCommunicationServerLLGS::SendProcessOutput() { - GDBRemoteCommunicationServerLLGS *server = reinterpret_cast<GDBRemoteCommunicationServerLLGS*> (baton); - static_cast<void> (server->SendONotification (static_cast<const char *>(src), src_len)); + 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; + } + } } GDBRemoteCommunication::PacketResult @@ -941,49 +1105,24 @@ GDBRemoteCommunicationServerLLGS::Handle_qC (StringExtractorGDBRemote &packet) return SendPacketNoLock (response.GetData(), response.GetSize()); } -bool -GDBRemoteCommunicationServerLLGS::DebuggedProcessReaped (lldb::pid_t pid) -{ - // reap a process that we were debugging (but not debugserver) - Mutex::Locker locker (m_spawned_pids_mutex); - return m_spawned_pids.erase(pid) > 0; -} - -bool -GDBRemoteCommunicationServerLLGS::ReapDebuggedProcess (void *callback_baton, - lldb::pid_t pid, - bool exited, - int signal, // Zero for no signal - int status) // Exit value of process if signal is zero -{ - GDBRemoteCommunicationServerLLGS *server = (GDBRemoteCommunicationServerLLGS *)callback_baton; - server->DebuggedProcessReaped (pid); - return true; -} - GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_k (StringExtractorGDBRemote &packet) { - // shutdown all spawned processes - std::set<lldb::pid_t> spawned_pids_copy; + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - // copy pids - { - Mutex::Locker locker (m_spawned_pids_mutex); - spawned_pids_copy.insert (m_spawned_pids.begin (), m_spawned_pids.end ()); - } + StopSTDIOForwarding(); - // nuke the spawned processes - for (auto it = spawned_pids_copy.begin (); it != spawned_pids_copy.end (); ++it) + if (! m_debugged_process_sp) { - lldb::pid_t spawned_pid = *it; - if (!KillSpawnedProcess (spawned_pid)) - { - fprintf (stderr, "%s: failed to kill spawned pid %" PRIu64 ", ignoring.\n", __FUNCTION__, spawned_pid); - } + if (log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s No debugged process found.", __FUNCTION__); + return PacketResult::Success; } - FlushInferiorOutput (); + 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 (); @@ -1316,11 +1455,11 @@ GDBRemoteCommunicationServerLLGS::Handle_stop_reason (StringExtractorGDBRemote & if (!m_debugged_process_sp) return SendErrorResponse (02); - return SendStopReasonForState (m_debugged_process_sp->GetState (), true); + return SendStopReasonForState (m_debugged_process_sp->GetState()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::SendStopReasonForState (lldb::StateType process_state, bool flush_on_exit) +GDBRemoteCommunicationServerLLGS::SendStopReasonForState (lldb::StateType process_state) { Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); @@ -1349,8 +1488,6 @@ GDBRemoteCommunicationServerLLGS::SendStopReasonForState (lldb::StateType proces case eStateInvalid: case eStateUnloaded: case eStateExited: - if (flush_on_exit) - FlushInferiorOutput (); return SendWResponse(m_debugged_process_sp.get()); default: @@ -1448,8 +1585,8 @@ GDBRemoteCommunicationServerLLGS::Handle_qRegisterInfo (StringExtractorGDBRemote response.PutChar (';'); } - if (reg_info->kinds[RegisterKind::eRegisterKindGCC] != LLDB_INVALID_REGNUM) - response.Printf ("gcc:%" PRIu32 ";", reg_info->kinds[RegisterKind::eRegisterKindGCC]); + 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]); @@ -1856,7 +1993,7 @@ GDBRemoteCommunicationServerLLGS::Handle_interrupt (StringExtractorGDBRemote &pa } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_m (StringExtractorGDBRemote &packet) +GDBRemoteCommunicationServerLLGS::Handle_memory_read(StringExtractorGDBRemote &packet) { Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); @@ -1889,7 +2026,7 @@ GDBRemoteCommunicationServerLLGS::Handle_m (StringExtractorGDBRemote &packet) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s nothing to read: zero-length packet", __FUNCTION__); - return PacketResult::Success; + return SendOKResponse(); } // Allocate the response buffer. @@ -1916,8 +2053,16 @@ GDBRemoteCommunicationServerLLGS::Handle_m (StringExtractorGDBRemote &packet) } StreamGDBRemote response; - for (size_t i = 0; i < bytes_read; ++i) - response.PutHex8(buf[i]); + 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()); } @@ -2108,6 +2253,7 @@ GDBRemoteCommunicationServerLLGS::Handle_Z (StringExtractorGDBRemote &packet) bool want_breakpoint = true; bool want_hardware = false; + uint32_t watch_flags = 0; const GDBStoppointType stoppoint_type = GDBStoppointType(packet.GetS32 (eStoppointInvalid)); @@ -2118,10 +2264,13 @@ GDBRemoteCommunicationServerLLGS::Handle_Z (StringExtractorGDBRemote &packet) 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"); @@ -2161,11 +2310,6 @@ GDBRemoteCommunicationServerLLGS::Handle_Z (StringExtractorGDBRemote &packet) } else { - uint32_t watch_flags = - stoppoint_type == eWatchpointWrite - ? 0x1 // Write - : 0x3; // ReadWrite - // Try to set the watchpoint. const Error error = m_debugged_process_sp->SetWatchpoint ( addr, size, watch_flags, want_hardware); @@ -2555,7 +2699,7 @@ GDBRemoteCommunicationServerLLGS::Handle_vAttach (StringExtractorGDBRemote &pack } // Notify we attached by sending a stop packet. - return SendStopReasonForState (m_debugged_process_sp->GetState (), true); + return SendStopReasonForState (m_debugged_process_sp->GetState ()); } GDBRemoteCommunication::PacketResult @@ -2563,8 +2707,7 @@ GDBRemoteCommunicationServerLLGS::Handle_D (StringExtractorGDBRemote &packet) { Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS)); - // Scope for mutex locker. - Mutex::Locker locker (m_spawned_pids_mutex); + StopSTDIOForwarding(); // Fail if we don't have a current process. if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) @@ -2574,14 +2717,6 @@ GDBRemoteCommunicationServerLLGS::Handle_D (StringExtractorGDBRemote &packet) return SendErrorResponse (0x15); } - if (m_spawned_pids.find(m_debugged_process_sp->GetID ()) == m_spawned_pids.end()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to find PID %" PRIu64 " in spawned pids list", - __FUNCTION__, m_debugged_process_sp->GetID ()); - return SendErrorResponse (0x1); - } - lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; // Consume the ';' after D. @@ -2603,11 +2738,6 @@ GDBRemoteCommunicationServerLLGS::Handle_D (StringExtractorGDBRemote &packet) return SendIllFormedResponse (packet, "Invalid pid"); } - if (m_stdio_communication.IsConnected ()) - { - m_stdio_communication.StopReadThread (); - } - const Error error = m_debugged_process_sp->Detach (); if (error.Fail ()) { @@ -2617,7 +2747,6 @@ GDBRemoteCommunicationServerLLGS::Handle_D (StringExtractorGDBRemote &packet) return SendErrorResponse (0x01); } - m_spawned_pids.erase (m_debugged_process_sp->GetID ()); return SendOKResponse (); } @@ -2638,6 +2767,38 @@ GDBRemoteCommunicationServerLLGS::Handle_qThreadStopInfo (StringExtractorGDBRemo } 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, + __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); + } + + threads_array_sp->Write(response); + StreamGDBRemote escaped_response; + escaped_response.PutEscapedBytes(response.GetData(), response.GetSize()); + return SendPacketNoLock (escaped_response.GetData(), escaped_response.GetSize()); +} + +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_qWatchpointSupportInfo (StringExtractorGDBRemote &packet) { // Fail if we don't have a current process. @@ -2686,21 +2847,6 @@ GDBRemoteCommunicationServerLLGS::Handle_qFileLoadAddress (StringExtractorGDBRem } void -GDBRemoteCommunicationServerLLGS::FlushInferiorOutput () -{ - // If we're not monitoring an inferior's terminal, ignore this. - if (!m_stdio_communication.IsConnected()) - return; - - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); - if (log) - log->Printf ("GDBRemoteCommunicationServerLLGS::%s() called", __FUNCTION__); - - // FIXME implement a timeout on the join. - m_stdio_communication.JoinReadThread(); -} - -void GDBRemoteCommunicationServerLLGS::MaybeCloseInferiorTerminalConnection () { Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h index 29f3fde..f160577 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h @@ -42,9 +42,6 @@ public: //------------------------------------------------------------------ GDBRemoteCommunicationServerLLGS(const lldb::PlatformSP& platform_sp, MainLoop &mainloop); - virtual - ~GDBRemoteCommunicationServerLLGS(); - //------------------------------------------------------------------ /// Specify the program to launch and its arguments. /// @@ -119,12 +116,15 @@ public: protected: lldb::PlatformSP m_platform_sp; MainLoop &m_mainloop; - MainLoop::ReadHandleUP m_read_handle_up; + MainLoop::ReadHandleUP m_network_handle_up; lldb::tid_t m_current_tid; lldb::tid_t m_continue_tid; Mutex m_debugged_process_mutex; NativeProcessProtocolSP m_debugged_process_sp; + Communication m_stdio_communication; + MainLoop::ReadHandleUP m_stdio_handle_up; + lldb::StateType m_inferior_prev_state; lldb::DataBufferSP m_active_auxv_buffer_sp; Mutex m_saved_registers_mutex; @@ -142,7 +142,7 @@ protected: SendStopReplyPacketForThread (lldb::tid_t tid); PacketResult - SendStopReasonForState (lldb::StateType process_state, bool flush_on_exit); + SendStopReasonForState (lldb::StateType process_state); PacketResult Handle_k (StringExtractorGDBRemote &packet); @@ -201,8 +201,9 @@ protected: PacketResult Handle_interrupt (StringExtractorGDBRemote &packet); + // Handles $m and $x packets. PacketResult - Handle_m (StringExtractorGDBRemote &packet); + Handle_memory_read (StringExtractorGDBRemote &packet); PacketResult Handle_M (StringExtractorGDBRemote &packet); @@ -241,6 +242,9 @@ protected: Handle_qThreadStopInfo (StringExtractorGDBRemote &packet); PacketResult + Handle_jThreadsInfo (StringExtractorGDBRemote &packet); + + PacketResult Handle_qWatchpointSupportInfo (StringExtractorGDBRemote &packet); PacketResult @@ -261,32 +265,16 @@ protected: Error SetSTDIOFileDescriptor (int fd); - static void - STDIOReadThreadBytesReceived (void *baton, const void *src, size_t src_len); - FileSpec FindModuleFile (const std::string& module_path, const ArchSpec& arch) override; private: - bool - DebuggedProcessReaped (lldb::pid_t pid); - - static bool - ReapDebuggedProcess (void *callback_baton, - lldb::pid_t pid, - bool exited, - int signal, - int status); - void HandleInferiorState_Exited (NativeProcessProtocol *process); void HandleInferiorState_Stopped (NativeProcessProtocol *process); - void - FlushInferiorOutput (); - NativeThreadProtocolSP GetThreadFromSuffix (StringExtractorGDBRemote &packet); @@ -305,6 +293,15 @@ private: void DataAvailableCallback (); + void + SendProcessOutput (); + + void + StartSTDIOForwarding(); + + void + StopSTDIOForwarding(); + //------------------------------------------------------------------ // For GDBRemoteCommunicationServerLLGS only //------------------------------------------------------------------ diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp index 1205049..f88ac12 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp @@ -15,19 +15,26 @@ // C++ Includes #include <cstring> #include <chrono> +#include <mutex> +#include <sstream> // Other libraries and framework includes +#include "llvm/Support/FileSystem.h" + #include "lldb/Core/Log.h" +#include "lldb/Core/StreamGDBRemote.h" #include "lldb/Core/StreamString.h" #include "lldb/Core/StructuredData.h" #include "lldb/Host/Config.h" #include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/Host/Host.h" +#include "lldb/Host/HostInfo.h" #include "lldb/Host/StringConvert.h" #include "lldb/Target/FileAction.h" #include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" #include "lldb/Target/UnixSignals.h" +#include "lldb/Utility/JSON.h" // Project includes #include "Utility/StringExtractorGDBRemote.h" @@ -40,18 +47,29 @@ using namespace lldb_private::process_gdb_remote; //---------------------------------------------------------------------- // GDBRemoteCommunicationServerPlatform constructor //---------------------------------------------------------------------- -GDBRemoteCommunicationServerPlatform::GDBRemoteCommunicationServerPlatform() : +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 (Mutex::eMutexTypeRecursive), m_platform_sp (Platform::GetHostPlatform ()), 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, @@ -78,38 +96,16 @@ GDBRemoteCommunicationServerPlatform::~GDBRemoteCommunicationServerPlatform() { } -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet) +Error +GDBRemoteCommunicationServerPlatform::LaunchGDBServer(const lldb_private::Args& args, + std::string hostname, + lldb::pid_t& pid, + uint16_t& port, + std::string& socket_name) { -#ifdef _WIN32 - 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)); - if (log) - log->Printf ("GDBRemoteCommunicationServerPlatform::%s() called", __FUNCTION__); - - // Sleep and wait a bit for debugserver to start to listen... - ConnectionFileDescriptor file_conn; - std::string hostname; - // TODO: /tmp/ should not be hardcoded. User might want to override /tmp - // with the TMPDIR environment variable - 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); - } if (port == UINT16_MAX) port = GetNextAvailablePort(); - + // Spawn a new thread to accept the port that gets bound after // binding to port 0 (zero). @@ -120,6 +116,8 @@ GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer (StringExtractorGD 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); @@ -133,53 +131,210 @@ GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer (StringExtractorGD 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); - Error error = StartDebugserverProcess ( - platform_ip.c_str(), - port, - debugserver_launch_info, - port); - lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID(); + std::ostringstream url; + 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); - if (debugserver_pid != LLDB_INVALID_PROCESS_ID) + pid = debugserver_launch_info.GetProcessID(); + if (pid != LLDB_INVALID_PROCESS_ID) { Mutex::Locker locker (m_spawned_pids_mutex); - m_spawned_pids.insert(debugserver_pid); + m_spawned_pids.insert(pid); if (port > 0) - AssociatePortWithProcess(port, debugserver_pid); + AssociatePortWithProcess(port, pid); } else { if (port > 0) - FreePort (port); + FreePort(port); + } + return error; +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet) +{ +#ifdef _WIN32 + return SendErrorResponse(9); +#else + // Spawn a local debugserver as a platform so we can then attach or launch + // a process... + + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); + 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); } - if (error.Success()) + 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 launched successfully as pid %" PRIu64, __FUNCTION__, debugserver_pid); + log->Printf("GDBRemoteCommunicationServerPlatform::%s() debugserver launch failed: %s", __FUNCTION__, error.AsCString ()); + return SendErrorResponse(9); + } - char response[256]; - const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset); - assert (response_len < (int)sizeof(response)); - PacketResult packet_result = SendPacketNoLock (response, response_len); + if (log) + log->Printf ("GDBRemoteCommunicationServerPlatform::%s() debugserver launched successfully as pid %" PRIu64, __FUNCTION__, debugserver_pid); - if (packet_result != PacketResult::Success) + 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; +#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()); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerPlatform::Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet) +{ + packet.SetFilePos(::strlen ("qKillSpawnedProcess:")); + + lldb::pid_t pid = packet.GetU64(LLDB_INVALID_PROCESS_ID); + + // verify that we know anything about this pid. + // Scope for locker + { + Mutex::Locker locker (m_spawned_pids_mutex); + if (m_spawned_pids.find(pid) == m_spawned_pids.end()) { - if (debugserver_pid != LLDB_INVALID_PROCESS_ID) - ::kill (debugserver_pid, SIGINT); + // not a pid we know about + return SendErrorResponse (10); } - return packet_result; } + + // 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 { - if (log) - log->Printf ("GDBRemoteCommunicationServerPlatform::%s() debugserver launch failed: %s", __FUNCTION__, error.AsCString ()); + Mutex::Locker locker (m_spawned_pids_mutex); + if (m_spawned_pids.find(pid) == m_spawned_pids.end()) + return false; } - return SendErrorResponse (9); -#endif + + // first try a SIGTERM (standard kill) + Host::Kill (pid, SIGTERM); + + // check if that worked + for (size_t i=0; i<10; ++i) + { + { + Mutex::Locker locker (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 + { + Mutex::Locker locker (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); + + for (size_t i=0; i<10; ++i) + { + { + Mutex::Locker locker (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 + { + Mutex::Locker locker (m_spawned_pids_mutex); + if (m_spawned_pids.find(pid) == m_spawned_pids.end()) + return true; + } + + // no luck - the process still lives + return false; } GDBRemoteCommunication::PacketResult @@ -402,8 +557,48 @@ GDBRemoteCommunicationServerPlatform::FreePortForProcess (lldb::pid_t pid) 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; +} + +FileSpec +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()); + + llvm::sys::fs::createUniqueFile(socket_path_spec.GetCString(), socket_path); + return FileSpec(socket_path.c_str(), false); +} + void -GDBRemoteCommunicationServerPlatform::SetPortOffset (uint16_t port_offset) +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; +} diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h index 5c01137..1fe7207 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h @@ -10,7 +10,15 @@ #ifndef liblldb_GDBRemoteCommunicationServerPlatform_h_ #define liblldb_GDBRemoteCommunicationServerPlatform_h_ +// C Includes +// C++ Includes +#include <map> +#include <set> + +// Other libraries and framework includes +// Project includes #include "GDBRemoteCommunicationServerCommon.h" +#include "lldb/Host/Socket.h" namespace lldb_private { namespace process_gdb_remote { @@ -21,10 +29,10 @@ class GDBRemoteCommunicationServerPlatform : public: typedef std::map<uint16_t, lldb::pid_t> PortMap; - GDBRemoteCommunicationServerPlatform(); + GDBRemoteCommunicationServerPlatform(const Socket::SocketProtocol socket_protocol, + const char* socket_scheme); - virtual - ~GDBRemoteCommunicationServerPlatform(); + ~GDBRemoteCommunicationServerPlatform() override; Error LaunchProcess () override; @@ -58,16 +66,40 @@ public: void SetPortOffset (uint16_t port_offset); + 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); + + 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; + Mutex m_spawned_pids_mutex; + std::set<lldb::pid_t> m_spawned_pids; lldb::PlatformSP m_platform_sp; 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_qQueryGDBServer (StringExtractorGDBRemote &packet); + + PacketResult + Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet); + + PacketResult Handle_qProcessInfo (StringExtractorGDBRemote &packet); PacketResult @@ -84,6 +116,9 @@ protected: private: bool + KillSpawnedProcess (lldb::pid_t pid); + + bool DebugserverProcessReaped (lldb::pid_t pid); static bool @@ -93,13 +128,16 @@ private: int signal, int status); - //------------------------------------------------------------------ - // For GDBRemoteCommunicationServerPlatform only - //------------------------------------------------------------------ + static const FileSpec& + GetDomainSocketDir(); + + static FileSpec + GetDomainSocketPath(const char* prefix); + DISALLOW_COPY_AND_ASSIGN (GDBRemoteCommunicationServerPlatform); }; } // namespace process_gdb_remote } // namespace lldb_private -#endif // liblldb_GDBRemoteCommunicationServerPlatform_h_ +#endif // liblldb_GDBRemoteCommunicationServerPlatform_h_ diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp index f5f134e..b0a1eaa 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp @@ -17,9 +17,6 @@ #include "lldb/Core/RegisterValue.h" #include "lldb/Core/Scalar.h" #include "lldb/Core/StreamString.h" -#ifndef LLDB_DISABLE_PYTHON -#include "lldb/Interpreter/PythonDataObjects.h" -#endif #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Target.h" #include "lldb/Utility/Utils.h" @@ -28,8 +25,8 @@ #include "ProcessGDBRemote.h" #include "ProcessGDBRemoteLog.h" #include "ThreadGDBRemote.h" -#include "Utility/ARM_GCC_Registers.h" #include "Utility/ARM_DWARF_Registers.h" +#include "Utility/ARM_ehframe_Registers.h" using namespace lldb; using namespace lldb_private; @@ -150,6 +147,52 @@ GDBRemoteRegisterContext::PrivateSetRegisterValue (uint32_t reg, StringExtractor 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); + + DataBufferSP buffer_sp (new DataBufferHeap (&new_reg_val, sizeof (new_reg_val))); + DataExtractor data (buffer_sp, endian::InlHostByteOrder(), sizeof (void*)); + + // 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 (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, @@ -186,7 +229,8 @@ GDBRemoteRegisterContext::ReadRegisterBytes (const RegisterInfo *reg_info, DataE if (!gdb_comm.ReadAllRegisters(m_thread.GetProtocolID(), response)) return false; if (response.IsNormalResponse()) - if (response.GetHexBytes ((void *)m_reg_data.GetDataStart(), m_reg_data.GetByteSize(), '\xcc') == m_reg_data.GetByteSize()) + 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) @@ -275,8 +319,8 @@ GDBRemoteRegisterContext::SetPrimordialRegister(const RegisterInfo *reg_info, packet.Printf ("P%x=", reg); packet.PutBytesAsRawHex8 (m_reg_data.PeekData(reg_info->byte_offset, reg_info->byte_size), reg_info->byte_size, - lldb::endian::InlHostByteOrder(), - lldb::endian::InlHostByteOrder()); + endian::InlHostByteOrder(), + endian::InlHostByteOrder()); if (gdb_comm.GetThreadSuffixSupported()) packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID()); @@ -372,8 +416,8 @@ GDBRemoteRegisterContext::WriteRegisterBytes (const RegisterInfo *reg_info, Data packet.PutChar ('G'); packet.PutBytesAsRawHex8 (m_reg_data.GetDataStart(), m_reg_data.GetByteSize(), - lldb::endian::InlHostByteOrder(), - lldb::endian::InlHostByteOrder()); + endian::InlHostByteOrder(), + endian::InlHostByteOrder()); if (thread_suffix_supported) packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID()); @@ -772,8 +816,8 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data packet.Printf ("P%x=", reg); packet.PutBytesAsRawHex8 (restore_src, reg_byte_size, - lldb::endian::InlHostByteOrder(), - lldb::endian::InlHostByteOrder()); + endian::InlHostByteOrder(), + endian::InlHostByteOrder()); if (thread_suffix_supported) packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID()); @@ -795,8 +839,8 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data packet.Printf ("P%x=", reg); packet.PutBytesAsRawHex8 (restore_src, reg_byte_size, - lldb::endian::InlHostByteOrder(), - lldb::endian::InlHostByteOrder()); + endian::InlHostByteOrder(), + endian::InlHostByteOrder()); if (thread_suffix_supported) packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID()); @@ -851,7 +895,7 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data } StreamString packet; packet.Printf ("P%x=", reg_info->kinds[eRegisterKindLLDB]); - packet.PutBytesAsRawHex8 (data_sp->GetBytes() + reg_info->byte_offset, reg_info->byte_size, lldb::endian::InlHostByteOrder(), lldb::endian::InlHostByteOrder()); + 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()); @@ -941,115 +985,115 @@ GDBRemoteDynamicRegisterInfo::HardcodeARMRegisters(bool from_scratch) }; static RegisterInfo g_register_infos[] = { -// NAME ALT SZ OFF ENCODING FORMAT COMPILER DWARF GENERIC GDB LLDB VALUE REGS INVALIDATE REGS -// ====== ====== === === ============= ============ =================== =================== ====================== === ==== ========== =============== - { "r0", "arg1", 4, 0, eEncodingUint, eFormatHex, { gcc_r0, dwarf_r0, LLDB_REGNUM_GENERIC_ARG1,0, 0 }, NULL, NULL}, - { "r1", "arg2", 4, 0, eEncodingUint, eFormatHex, { gcc_r1, dwarf_r1, LLDB_REGNUM_GENERIC_ARG2,1, 1 }, NULL, NULL}, - { "r2", "arg3", 4, 0, eEncodingUint, eFormatHex, { gcc_r2, dwarf_r2, LLDB_REGNUM_GENERIC_ARG3,2, 2 }, NULL, NULL}, - { "r3", "arg4", 4, 0, eEncodingUint, eFormatHex, { gcc_r3, dwarf_r3, LLDB_REGNUM_GENERIC_ARG4,3, 3 }, NULL, NULL}, - { "r4", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r4, dwarf_r4, LLDB_INVALID_REGNUM, 4, 4 }, NULL, NULL}, - { "r5", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r5, dwarf_r5, LLDB_INVALID_REGNUM, 5, 5 }, NULL, NULL}, - { "r6", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r6, dwarf_r6, LLDB_INVALID_REGNUM, 6, 6 }, NULL, NULL}, - { "r7", "fp", 4, 0, eEncodingUint, eFormatHex, { gcc_r7, dwarf_r7, LLDB_REGNUM_GENERIC_FP, 7, 7 }, NULL, NULL}, - { "r8", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r8, dwarf_r8, LLDB_INVALID_REGNUM, 8, 8 }, NULL, NULL}, - { "r9", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r9, dwarf_r9, LLDB_INVALID_REGNUM, 9, 9 }, NULL, NULL}, - { "r10", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r10, dwarf_r10, LLDB_INVALID_REGNUM, 10, 10 }, NULL, NULL}, - { "r11", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r11, dwarf_r11, LLDB_INVALID_REGNUM, 11, 11 }, NULL, NULL}, - { "r12", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r12, dwarf_r12, LLDB_INVALID_REGNUM, 12, 12 }, NULL, NULL}, - { "sp", "r13", 4, 0, eEncodingUint, eFormatHex, { gcc_sp, dwarf_sp, LLDB_REGNUM_GENERIC_SP, 13, 13 }, NULL, NULL}, - { "lr", "r14", 4, 0, eEncodingUint, eFormatHex, { gcc_lr, dwarf_lr, LLDB_REGNUM_GENERIC_RA, 14, 14 }, NULL, NULL}, - { "pc", "r15", 4, 0, eEncodingUint, eFormatHex, { gcc_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, { gcc_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 +// ====== ====== === === ============= ============ =================== =================== ====================== ============= ==== ========== =============== + { "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} }; static const uint32_t num_registers = llvm::array_lengthof(g_register_infos); diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h index 117d280..0e26c69 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h @@ -42,32 +42,22 @@ public: { } - ~GDBRemoteDynamicRegisterInfo () - { - } + ~GDBRemoteDynamicRegisterInfo() override = default; void HardcodeARMRegisters(bool from_scratch); - }; class GDBRemoteRegisterContext : public RegisterContext { public: - //------------------------------------------------------------------ - // Constructors and Destructors - //------------------------------------------------------------------ GDBRemoteRegisterContext (ThreadGDBRemote &thread, uint32_t concrete_frame_idx, GDBRemoteDynamicRegisterInfo ®_info, bool read_all_at_once); - virtual - ~GDBRemoteRegisterContext (); + ~GDBRemoteRegisterContext() override; - //------------------------------------------------------------------ - // Subclasses must override these functions - //------------------------------------------------------------------ void InvalidateAllRegisters () override; @@ -119,6 +109,9 @@ protected: bool PrivateSetRegisterValue (uint32_t reg, StringExtractor &response); + bool + PrivateSetRegisterValue (uint32_t reg, uint64_t val); + void SetAllRegisterValid (bool b); @@ -166,13 +159,10 @@ private: bool SetPrimordialRegister(const RegisterInfo *reg_info, GDBRemoteCommunicationClient &gdb_comm); - //------------------------------------------------------------------ - // For GDBRemoteRegisterContext only - //------------------------------------------------------------------ DISALLOW_COPY_AND_ASSIGN (GDBRemoteRegisterContext); }; } // namespace process_gdb_remote } // namespace lldb_private -#endif // lldb_GDBRemoteRegisterContext_h_ +#endif // lldb_GDBRemoteRegisterContext_h_ diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 1e150b1..2e7a5b5 100644 --- a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -40,6 +40,7 @@ #include "lldb/Core/Timer.h" #include "lldb/Core/Value.h" #include "lldb/DataFormatters/FormatManager.h" +#include "lldb/Host/FileSystem.h" #include "lldb/Host/HostThread.h" #include "lldb/Host/StringConvert.h" #include "lldb/Host/Symbols.h" @@ -56,6 +57,7 @@ #include "lldb/Interpreter/OptionGroupUInt64.h" #include "lldb/Interpreter/Property.h" #include "lldb/Symbol/ObjectFile.h" +#include "lldb/Target/ABI.h" #include "lldb/Target/DynamicLoader.h" #include "lldb/Target/Target.h" #include "lldb/Target/TargetList.h" @@ -192,7 +194,7 @@ public: { for (uint32_t i = 0; i < e_num; ++i) m_has[i] = false; - }; + } void set_name (const std::string & name) { @@ -216,6 +218,16 @@ public: return m_has[e_has_base]; } + void set_base_is_offset (bool is_offset) + { + m_base_is_offset = is_offset; + } + bool get_base_is_offset(bool & out) const + { + out = m_base_is_offset; + return m_has[e_has_base]; + } + void set_link_map (const lldb::addr_t addr) { m_link_map = addr; @@ -250,6 +262,7 @@ public: std::string m_name; lldb::addr_t m_link_map; lldb::addr_t m_base; + bool m_base_is_offset; lldb::addr_t m_dynamic; }; @@ -322,22 +335,22 @@ ProcessGDBRemote::Terminate() lldb::ProcessSP -ProcessGDBRemote::CreateInstance (Target &target, Listener &listener, const FileSpec *crash_file_path) +ProcessGDBRemote::CreateInstance (lldb::TargetSP target_sp, Listener &listener, const FileSpec *crash_file_path) { lldb::ProcessSP process_sp; if (crash_file_path == NULL) - process_sp.reset (new ProcessGDBRemote (target, listener)); + process_sp.reset (new ProcessGDBRemote (target_sp, listener)); return process_sp; } bool -ProcessGDBRemote::CanDebug (Target &target, bool plugin_specified_by_name) +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.GetExecutableModulePointer(); + Module *exe_module = target_sp->GetExecutableModulePointer(); if (exe_module) { ObjectFile *exe_objfile = exe_module->GetObjectFile(); @@ -366,17 +379,20 @@ ProcessGDBRemote::CanDebug (Target &target, bool plugin_specified_by_name) //---------------------------------------------------------------------- // ProcessGDBRemote constructor //---------------------------------------------------------------------- -ProcessGDBRemote::ProcessGDBRemote(Target& target, Listener &listener) : - Process (target, listener), +ProcessGDBRemote::ProcessGDBRemote(lldb::TargetSP target_sp, Listener &listener) : + Process (target_sp, listener), m_flags (0), m_gdb_comm (), m_debugserver_pid (LLDB_INVALID_PROCESS_ID), m_last_stop_packet_mutex (Mutex::eMutexTypeRecursive), m_register_info (), m_async_broadcaster (NULL, "lldb.process.gdb-remote.async-broadcaster"), + m_async_listener("lldb.process.gdb-remote.async-listener"), m_async_thread_state_mutex(Mutex::eMutexTypeRecursive), m_thread_ids (), - m_threads_info_sp (), + m_thread_pcs (), + m_jstopinfo_sp (), + m_jthreadsinfo_sp (), m_continue_c_tids (), m_continue_C_tids (), m_continue_s_tids (), @@ -394,6 +410,25 @@ ProcessGDBRemote::ProcessGDBRemote(Target& target, Listener &listener) : 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.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.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); @@ -481,6 +516,40 @@ ProcessGDBRemote::ParsePythonTargetDefinition(const FileSpec &target_definition_ return false; } +// 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 size_t SplitCommaSeparatedRegisterNumberString(const llvm::StringRef &comma_separated_regiter_numbers, std::vector<uint32_t> ®nums, int base) { @@ -524,11 +593,23 @@ ProcessGDBRemote::BuildDynamicRegisterInfo (bool force) // 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()); + } } if (GetGDBServerRegisterInfo ()) @@ -561,12 +642,12 @@ ProcessGDBRemote::BuildDynamicRegisterInfo (bool force) 0, // byte size reg_offset, // offset eEncodingUint, // encoding - eFormatHex, // formate + eFormatHex, // format { - LLDB_INVALID_REGNUM, // GCC reg num + LLDB_INVALID_REGNUM, // eh_frame reg num LLDB_INVALID_REGNUM, // DWARF reg num LLDB_INVALID_REGNUM, // generic reg num - reg_num, // GDB reg num + reg_num, // process plugin reg num reg_num // native register number }, NULL, @@ -635,9 +716,9 @@ ProcessGDBRemote::BuildDynamicRegisterInfo (bool force) { set_name.SetCString(value.c_str()); } - else if (name.compare("gcc") == 0) + else if (name.compare("gcc") == 0 || name.compare("ehframe") == 0) { - reg_info.kinds[eRegisterKindGCC] = StringConvert::ToUInt32(value.c_str(), LLDB_INVALID_REGNUM, 0); + reg_info.kinds[eRegisterKindEHFrame] = StringConvert::ToUInt32(value.c_str(), LLDB_INVALID_REGNUM, 0); } else if (name.compare("dwarf") == 0) { @@ -671,6 +752,8 @@ ProcessGDBRemote::BuildDynamicRegisterInfo (bool force) reg_info.invalidate_regs = invalidate_regs.data(); } + AugmentRegisterInfoViaABI (reg_info, reg_name, GetABI ()); + m_register_info.AddRegister(reg_info, reg_name, alt_name, set_name); } else @@ -711,11 +794,12 @@ ProcessGDBRemote::BuildDynamicRegisterInfo (bool force) if (!target_arch.IsValid()) { if (remote_arch.IsValid() - && remote_arch.GetMachine() == llvm::Triple::arm + && (remote_arch.GetMachine() == llvm::Triple::arm || remote_arch.GetMachine() == llvm::Triple::thumb) && remote_arch.GetTriple().getVendor() == llvm::Triple::Apple) m_register_info.HardcodeARMRegisters(from_scratch); } - else if (target_arch.GetMachine() == llvm::Triple::arm) + else if (target_arch.GetMachine() == llvm::Triple::arm + || target_arch.GetMachine() == llvm::Triple::thumb) { m_register_info.HardcodeARMRegisters(from_scratch); } @@ -779,20 +863,21 @@ ProcessGDBRemote::DoConnectRemote (Stream *strm, const char *remote_url) if (GetTarget().GetNonStopModeEnabled()) HandleStopReplySequence(); - if (!m_target.GetArchitecture().IsValid()) + Target &target = GetTarget(); + if (!target.GetArchitecture().IsValid()) { if (m_gdb_comm.GetProcessArchitecture().IsValid()) { - m_target.SetArchitecture(m_gdb_comm.GetProcessArchitecture()); + target.SetArchitecture(m_gdb_comm.GetProcessArchitecture()); } else { - m_target.SetArchitecture(m_gdb_comm.GetHostArchitecture()); + target.SetArchitecture(m_gdb_comm.GetHostArchitecture()); } } const StateType state = SetThreadStopInfo (response); - if (state == eStateStopped) + if (state != eStateInvalid) { SetPrivateState (state); } @@ -910,27 +995,22 @@ ProcessGDBRemote::DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info) ObjectFile * object_file = exe_module->GetObjectFile(); if (object_file) { - // Make sure we aren't already connected? - if (!m_gdb_comm.IsConnected()) - { - error = LaunchAndConnectToDebugserver (launch_info); - } - + error = EstablishConnectionIfNeeded (launch_info); if (error.Success()) { lldb_utility::PseudoTerminal pty; const bool disable_stdio = (launch_flags & eLaunchFlagDisableSTDIO) != 0; - PlatformSP platform_sp (m_target.GetPlatform()); + 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("/dev/null", false); + stdin_file_spec.SetFile(FileSystem::DEV_NULL, false); if (!stdout_file_spec) - stdout_file_spec.SetFile("/dev/null", false); + stdout_file_spec.SetFile(FileSystem::DEV_NULL, false); if (!stderr_file_spec) - stderr_file_spec.SetFile("/dev/null", false); + stderr_file_spec.SetFile(FileSystem::DEV_NULL, false); } else if (platform_sp && platform_sp->IsHost()) { @@ -977,7 +1057,7 @@ ProcessGDBRemote::DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info) m_gdb_comm.SetDisableASLR (launch_flags & eLaunchFlagDisableASLR); m_gdb_comm.SetDetachOnError (launch_flags & eLaunchFlagDetachOnError); - m_gdb_comm.SendLaunchArchPacket (m_target.GetArchitecture().GetArchitectureName()); + m_gdb_comm.SendLaunchArchPacket (GetTarget().GetArchitecture().GetArchitectureName()); const char * launch_event_data = launch_info.GetLaunchEventData(); if (launch_event_data != NULL && *launch_event_data != '\0') @@ -1044,13 +1124,13 @@ ProcessGDBRemote::DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info) if (process_arch.IsValid()) { - m_target.MergeArchitecture(process_arch); + GetTarget().MergeArchitecture(process_arch); } else { const ArchSpec &host_arch = m_gdb_comm.GetHostArchitecture(); if (host_arch.IsValid()) - m_target.MergeArchitecture(host_arch); + GetTarget().MergeArchitecture(host_arch); } SetPrivateState (SetThreadStopInfo (response)); @@ -1226,8 +1306,8 @@ ProcessGDBRemote::DidLaunchOrAttach (ArchSpec& process_arch) // 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.GetTriple().getVendor() == llvm::Triple::Apple) + 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) @@ -1295,21 +1375,7 @@ ProcessGDBRemote::DoAttachToProcessWithID (lldb::pid_t attach_pid, const Process Clear(); if (attach_pid != LLDB_INVALID_PROCESS_ID) { - // Make sure we aren't already connected? - if (!m_gdb_comm.IsConnected()) - { - error = LaunchAndConnectToDebugserver (attach_info); - - if (error.Fail()) - { - const char *error_string = error.AsCString(); - if (error_string == NULL) - error_string = "unable to launch " DEBUGSERVER_BASENAME; - - SetExitStatus (-1, error_string); - } - } - + error = EstablishConnectionIfNeeded (attach_info); if (error.Success()) { m_gdb_comm.SetDetachOnError(attach_info.GetDetachOnError()); @@ -1319,6 +1385,8 @@ ProcessGDBRemote::DoAttachToProcessWithID (lldb::pid_t attach_pid, const Process SetID (attach_pid); m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncContinue, new EventDataBytes (packet, packet_len)); } + else + SetExitStatus (-1, error.AsCString()); } return error; @@ -1333,21 +1401,7 @@ ProcessGDBRemote::DoAttachToProcessWithName (const char *process_name, const Pro if (process_name && process_name[0]) { - // Make sure we aren't already connected? - if (!m_gdb_comm.IsConnected()) - { - error = LaunchAndConnectToDebugserver (attach_info); - - if (error.Fail()) - { - const char *error_string = error.AsCString(); - if (error_string == NULL) - error_string = "unable to launch " DEBUGSERVER_BASENAME; - - SetExitStatus (-1, error_string); - } - } - + error = EstablishConnectionIfNeeded (attach_info); if (error.Success()) { StreamString packet; @@ -1371,11 +1425,13 @@ ProcessGDBRemote::DoAttachToProcessWithName (const char *process_name, const Pro else packet.PutCString("vAttachName"); packet.PutChar(';'); - packet.PutBytesAsRawHex8(process_name, strlen(process_name), lldb::endian::InlHostByteOrder(), lldb::endian::InlHostByteOrder()); + packet.PutBytesAsRawHex8(process_name, strlen(process_name), endian::InlHostByteOrder(), endian::InlHostByteOrder()); m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncContinue, new EventDataBytes (packet.GetData(), packet.GetSize())); } + else + SetExitStatus (-1, error.AsCString()); } return error; } @@ -1403,6 +1459,8 @@ ProcessGDBRemote::WillResume () 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(); } @@ -1694,12 +1752,14 @@ ProcessGDBRemote::ClearThreadIDList () { Mutex::Locker locker(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) @@ -1717,18 +1777,39 @@ ProcessGDBRemote::UpdateThreadIDsFromStopReplyThreadsValue (std::string &value) 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(); +} + bool ProcessGDBRemote::UpdateThreadIDList () { Mutex::Locker locker(m_thread_list_real.GetMutex()); - if (m_threads_info_sp) + if (m_jthreadsinfo_sp) { // If we have the JSON threads info, we can get the thread list from that - StructuredData::Array *thread_infos = m_threads_info_sp->GetAsArray(); + 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) @@ -1751,25 +1832,43 @@ ProcessGDBRemote::UpdateThreadIDList () // 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); - // 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++) + //Mutex::Locker stop_stack_lock(m_last_stop_packet_mutex); + Mutex::Locker stop_stack_lock; + if (stop_stack_lock.TryLock(m_last_stop_packet_mutex)) { - // Get the thread stop info - StringExtractorGDBRemote &stop_info = m_stop_packet_stack[i]; - const std::string &stop_info_str = stop_info.GetStringRef(); - const size_t threads_pos = stop_info_str.find(";threads:"); - if (threads_pos != std::string::npos) + // 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++) { - const size_t start = threads_pos + strlen(";threads:"); - const size_t end = stop_info_str.find(';', start); - if (end != std::string::npos) + // 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) { - std::string value = stop_info_str.substr(start, end - start); - if (UpdateThreadIDsFromStopReplyThreadsValue(value)) - return true; + 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; + } } } } @@ -1826,6 +1925,25 @@ ProcessGDBRemote::UpdateThreadList (ThreadList &old_thread_list, ThreadList &new __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.AddThread(thread_sp); } } @@ -1846,13 +1964,14 @@ ProcessGDBRemote::UpdateThreadList (ThreadList &old_thread_list, ThreadList &new return true; } + bool -ProcessGDBRemote::CalculateThreadStopInfo (ThreadGDBRemote *thread) +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 (m_threads_info_sp) + if (thread_infos_sp) { - StructuredData::Array *thread_infos = m_threads_info_sp->GetAsArray(); + StructuredData::Array *thread_infos = thread_infos_sp->GetAsArray(); if (thread_infos) { lldb::tid_t tid; @@ -1865,12 +1984,36 @@ ProcessGDBRemote::CalculateThreadStopInfo (ThreadGDBRemote *thread) if (thread_dict->GetValueForKeyAsInteger<lldb::tid_t>("tid", tid, LLDB_INVALID_THREAD_ID)) { if (tid == thread->GetID()) - return SetThreadStopInfo(thread_dict); + return (bool)SetThreadStopInfo(thread_dict); } } } } } + 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; + + // 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; @@ -1926,8 +2069,6 @@ ProcessGDBRemote::SetThreadStopInfo (lldb::tid_t tid, gdb_thread->PrivateSetRegisterValue (pair.first, reg_value_extractor); } - // Clear the stop info just in case we don't set it to anything - thread_sp->SetStopInfo (StopInfoSP()); thread_sp->SetName (thread_name.empty() ? NULL : thread_name.c_str()); gdb_thread->SetThreadDispatchQAddr (thread_dispatch_qaddr); @@ -1937,145 +2078,159 @@ ProcessGDBRemote::SetThreadStopInfo (lldb::tid_t tid, else gdb_thread->ClearQueueInfo(); - - 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 + // Make sure we update our thread stop reason just once + if (!thread_sp->StopInfoIsUpToDate()) { - bool handled = false; - bool did_exec = false; - if (!reason.empty()) + 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) { - if (reason.compare("trace") == 0) - { - thread_sp->SetStopInfo (StopInfo::CreateStopReasonToTrace (*thread_sp)); - handled = true; - } - else if (reason.compare("breakpoint") == 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()) { - addr_t pc = thread_sp->GetRegisterContext()->GetPC(); - lldb::BreakpointSiteSP bp_site_sp = thread_sp->GetProcess()->GetBreakpointSiteList().FindByAddress(pc); - if (bp_site_sp) + if (reason.compare("trace") == 0) { - // 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. + thread_sp->SetStopInfo (StopInfo::CreateStopReasonToTrace (*thread_sp)); handled = true; - if (bp_site_sp->ValidForThisThread (thread_sp.get())) - { - thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID (*thread_sp, bp_site_sp->GetID())); - } - else + } + 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) { - StopInfoSP invalid_stop_info_sp; - thread_sp->SetStopInfo (invalid_stop_info_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) + else if (reason.compare("trap") == 0) { - WatchpointSP wp_sp = GetTarget().GetWatchpointList().FindByAddress(wp_addr); - if (wp_sp) + // 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) + 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) { - wp_sp->SetHardwareIndex(wp_index); - watch_id = wp_sp->GetID(); + 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; } - if (watch_id == LLDB_INVALID_WATCH_ID) + else if (reason.compare("exception") == 0) { - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_WATCHPOINTS)); - if (log) log->Printf ("failed to find watchpoint"); + 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; } - 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 (!handled && signo && did_exec == false) - { - if (signo == SIGTRAP) + if (!handled && signo && did_exec == false) { - // 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 (signo == SIGTRAP) { - // 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())) + // 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(m_breakpoint_pc_offset != 0) - thread_sp->GetRegisterContext()->SetPC(pc); - thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID (*thread_sp, bp_site_sp->GetID())); + // 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 { - StopInfoSP invalid_stop_info_sp; - thread_sp->SetStopInfo (invalid_stop_info_sp); + // 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())); } } - 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 (!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 + if (!description.empty()) { - thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithException (*thread_sp, description.c_str())); + 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())); + } } } } @@ -2084,7 +2239,7 @@ ProcessGDBRemote::SetThreadStopInfo (lldb::tid_t tid, return thread_sp; } -StateType +lldb::ThreadSP ProcessGDBRemote::SetThreadStopInfo (StructuredData::Dictionary *thread_dict) { static ConstString g_key_tid("tid"); @@ -2101,6 +2256,7 @@ ProcessGDBRemote::SetThreadStopInfo (StructuredData::Dictionary *thread_dict) 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; @@ -2159,7 +2315,7 @@ ProcessGDBRemote::SetThreadStopInfo (StructuredData::Dictionary *thread_dict) } else if (key == g_key_name) { - thread_name = std::move(object->GetStringValue()); + thread_name = object->GetStringValue(); } else if (key == g_key_qaddr) { @@ -2168,7 +2324,7 @@ ProcessGDBRemote::SetThreadStopInfo (StructuredData::Dictionary *thread_dict) else if (key == g_key_queue_name) { queue_vars_valid = true; - queue_name = std::move(object->GetStringValue()); + queue_name = object->GetStringValue(); } else if (key == g_key_queue_kind) { @@ -2192,11 +2348,11 @@ ProcessGDBRemote::SetThreadStopInfo (StructuredData::Dictionary *thread_dict) } else if (key == g_key_reason) { - reason = std::move(object->GetStringValue()); + reason = object->GetStringValue(); } else if (key == g_key_description) { - description = std::move(object->GetStringValue()); + description = object->GetStringValue(); } else if (key == g_key_registers) { @@ -2207,7 +2363,7 @@ ProcessGDBRemote::SetThreadStopInfo (StructuredData::Dictionary *thread_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] = std::move(object->GetStringValue()); + expedited_register_map[reg] = object->GetStringValue(); return true; // Keep iterating through all array items }); } @@ -2245,24 +2401,24 @@ ProcessGDBRemote::SetThreadStopInfo (StructuredData::Dictionary *thread_dict) } } + else if (key == g_key_signal) + signo = object->GetIntegerValue(LLDB_INVALID_SIGNAL_NUMBER); return true; // Keep iterating through all dictionary key/value pairs }); - SetThreadStopInfo (tid, - expedited_register_map, - signo, - thread_name, - reason, - description, - exc_type, - exc_data, - thread_dispatch_qaddr, - queue_vars_valid, - queue_name, - queue_kind, - queue_serial); - - return eStateExited; + return SetThreadStopInfo (tid, + expedited_register_map, + signo, + thread_name, + reason, + description, + exc_type, + exc_data, + thread_dispatch_qaddr, + queue_vars_valid, + queue_name, + queue_kind, + queue_serial); } StateType @@ -2348,6 +2504,39 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet) 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; @@ -2431,7 +2620,7 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet) if (mem_cache_addr != LLDB_INVALID_ADDRESS) { StringExtractor bytes; - bytes.GetStringRef() = std::move(pair.second.str()); + 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); @@ -2455,6 +2644,10 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet) 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); @@ -2509,6 +2702,7 @@ ProcessGDBRemote::RefreshStateAfterStop () { Mutex::Locker locker(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. @@ -2545,11 +2739,6 @@ ProcessGDBRemote::RefreshStateAfterStop () m_initial_tid = LLDB_INVALID_THREAD_ID; } - // Fetch the threads via an efficient packet that gets stop infos for all threads - // only if we have more than one thread - if (m_thread_ids.size() > 1) - m_threads_info_sp = m_gdb_comm.GetThreadsInfo(); - // Let all threads recover from stopping and do any clean up based // on the previous thread state (if any). m_thread_list_real.RefreshStateAfterStop(); @@ -2824,6 +3013,12 @@ ProcessGDBRemote::SetLastStopPacket (const StringExtractorGDBRemote &response) { // Lock the thread stack while we access it Mutex::Locker stop_stack_lock(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 @@ -2831,6 +3026,11 @@ ProcessGDBRemote::SetLastStopPacket (const StringExtractorGDBRemote &response) } } +void +ProcessGDBRemote::SetUnixSignals(const UnixSignalsSP &signals_sp) +{ + Process::SetUnixSignals(std::make_shared<GDBRemoteSignals>(signals_sp)); +} //------------------------------------------------------------------ // Process Queries @@ -2839,7 +3039,7 @@ ProcessGDBRemote::SetLastStopPacket (const StringExtractorGDBRemote &response) bool ProcessGDBRemote::IsAlive () { - return m_gdb_comm.IsConnected() && m_private_state.GetValue() != eStateExited; + return m_gdb_comm.IsConnected() && Process::IsAlive(); } addr_t @@ -2859,6 +3059,35 @@ ProcessGDBRemote::GetImageInfoAddress() 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); + } + } + } +} + //------------------------------------------------------------------ // Process Memory //------------------------------------------------------------------ @@ -2877,14 +3106,8 @@ ProcessGDBRemote::DoReadMemory (addr_t addr, void *buf, size_t size, Error &erro char packet[64]; int packet_len; bool binary_memory_read = m_gdb_comm.GetxPacketSupported(); - if (binary_memory_read) - { - packet_len = ::snprintf (packet, sizeof(packet), "x0x%" PRIx64 ",0x%" PRIx64, (uint64_t)addr, (uint64_t)size); - } - else - { - packet_len = ::snprintf (packet, sizeof(packet), "m%" PRIx64 ",%" PRIx64, (uint64_t)addr, (uint64_t)size); - } + 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) @@ -2940,7 +3163,7 @@ ProcessGDBRemote::DoWriteMemory (addr_t addr, const void *buf, size_t size, Erro StreamString packet; packet.Printf("M%" PRIx64 ",%" PRIx64 ":", addr, (uint64_t)size); - packet.PutBytesAsRawHex8(buf, size, lldb::endian::InlHostByteOrder(), lldb::endian::InlHostByteOrder()); + packet.PutBytesAsRawHex8(buf, size, endian::InlHostByteOrder(), endian::InlHostByteOrder()); StringExtractorGDBRemote response; if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetData(), packet.GetSize(), response, true) == GDBRemoteCommunication::PacketResult::Success) { @@ -3377,6 +3600,27 @@ ProcessGDBRemote::DoSignal (int signo) } 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"); + + 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; +} + +Error ProcessGDBRemote::LaunchAndConnectToDebugserver (const ProcessInfo &process_info) { Error error; @@ -3401,14 +3645,22 @@ ProcessGDBRemote::LaunchAndConnectToDebugserver (const ProcessInfo &process_info // 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 = NULL; + const char *hostname = nullptr; uint16_t port = 0; #endif - error = m_gdb_comm.StartDebugserverProcess (hostname, - port, + StreamString url_str; + const char* url = nullptr; + if (hostname != nullptr) + { + url_str.Printf("%s:%u", hostname, port); + url = url_str.GetData(); + } + + error = m_gdb_comm.StartDebugserverProcess (url, + GetTarget().GetPlatform().get(), debugserver_launch_info, - port); + &port); if (error.Success ()) m_debugserver_pid = debugserver_launch_info.GetProcessID(); @@ -3653,164 +3905,174 @@ ProcessGDBRemote::AsyncThread (void *arg) if (log) log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") thread starting...", __FUNCTION__, arg, process->GetID()); - Listener listener ("ProcessGDBRemote::AsyncThread"); EventSP event_sp; - const uint32_t desired_event_mask = eBroadcastBitAsyncContinue | - eBroadcastBitAsyncThreadShouldExit; - - if (listener.StartListeningForEvents (&process->m_async_broadcaster, desired_event_mask) == desired_event_mask) + bool done = false; + while (!done) { - listener.StartListeningForEvents (&process->m_gdb_comm, Communication::eBroadcastBitReadThreadDidExit | - GDBRemoteCommunication::eBroadcastBitGdbReadThreadGotNotify); - - 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.WaitForEvent (NULL, event_sp)) { - if (log) - log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") listener.WaitForEvent (NULL, event_sp)...", __FUNCTION__, arg, process->GetID()); - if (listener.WaitForEvent (NULL, event_sp)) + const uint32_t event_type = event_sp->GetType(); + if (event_sp->BroadcasterIs (&process->m_async_broadcaster)) { - 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) { - if (log) - log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") Got an event of type: %d...", __FUNCTION__, arg, process->GetID(), event_type); + case eBroadcastBitAsyncContinue: + { + const EventDataBytes *continue_packet = EventDataBytes::GetEventDataFromEvent(event_sp.get()); - switch (event_type) - { - case eBroadcastBitAsyncContinue: + if (continue_packet) { - const EventDataBytes *continue_packet = EventDataBytes::GetEventDataFromEvent(event_sp.get()); + 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 (continue_packet) + if (::strstr (continue_cstr, "vAttach") == NULL) + process->SetPrivateState(eStateRunning); + StringExtractorGDBRemote response; + + // If in Non-Stop-Mode + if (process->GetTarget().GetNonStopModeEnabled()) { - 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)) { - // send the vCont packet - if (!process->GetGDBRemote().SendvContPacket(process, continue_cstr, continue_cstr_len, response)) - { - // Something went wrong - done = true; - break; - } + // 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 (); + } + // If in All-Stop-Mode + else + { + StateType stop_state = process->GetGDBRemote().SendContinuePacketAndWaitForResponse (process, continue_cstr, continue_cstr_len, response); - switch (stop_state) - { - case eStateStopped: - case eStateCrashed: - case eStateSuspended: - process->SetLastStopPacket (response); - process->SetPrivateState (stop_state); - break; + // 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 (); - case eStateExited: + 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('-') == ';') { - 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)) { - std::string desc_token; - while (response.GetNameColonValue (desc_token, desc_string)) + if (desc_token == "description") { - if (desc_token == "description") - { - extractor.GetStringRef().swap(desc_string); - extractor.SetFilePos(0); - extractor.GetHexByteString (desc_string); - desc_cstr = desc_string.c_str(); - } + 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: + 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; + 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; + 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; - } + 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 (event_sp->BroadcasterIs (&process->m_gdb_comm)) + } + else if (event_sp->BroadcasterIs (&process->m_gdb_comm)) + { + switch (event_type) { - 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; - } + case Communication::eBroadcastBitReadThreadDidExit: + process->SetExitStatus (-1, "lost connection"); + 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; + 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; - } + } + else + { + if (log) + log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") listener.WaitForEvent (NULL, event_sp) => false", __FUNCTION__, arg, process->GetID()); + done = true; } } @@ -3864,10 +4126,10 @@ ProcessGDBRemote::StartNoticingNewThreads() } else { - PlatformSP platform_sp (m_target.GetPlatform()); + PlatformSP platform_sp (GetTarget().GetPlatform()); if (platform_sp) { - m_thread_create_bp_sp = platform_sp->SetThreadCreationBreakpoint(m_target); + m_thread_create_bp_sp = platform_sp->SetThreadCreationBreakpoint(GetTarget()); if (m_thread_create_bp_sp) { if (log && log->GetVerbose()) @@ -3986,6 +4248,9 @@ ProcessGDBRemote::GetLoadedDynamicLibrariesInfos (lldb::addr_t image_list_addres if (m_gdb_comm.GetLoadedDynamicLibrariesInfosSupported()) { + // Scope for the scoped timeout object + GDBRemoteCommunication::ScopedTimeout timeout (m_gdb_comm, 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); @@ -4009,8 +4274,6 @@ ProcessGDBRemote::GetLoadedDynamicLibrariesInfos (lldb::addr_t image_list_addres { if (!response.Empty()) { - // The packet has already had the 0x7d xor quoting stripped out at the - // GDBRemoteCommunication packet receive level. object_sp = StructuredData::ParseJSON (response.GetStringRef()); } } @@ -4019,7 +4282,6 @@ ProcessGDBRemote::GetLoadedDynamicLibrariesInfos (lldb::addr_t image_list_addres return object_sp; } - // Establish the largest memory read/write payloads we should use. // If the remote stub has a max packet size, stay under that size. // @@ -4113,6 +4375,18 @@ ProcessGDBRemote::GetModuleSpec(const FileSpec& module_file_spec, return true; } +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 { typedef std::vector<std::string> stringVec; @@ -4135,15 +4409,15 @@ struct GdbServerTargetInfo }; bool -ParseRegisters (XMLNode feature_node, GdbServerTargetInfo &target_info, GDBRemoteDynamicRegisterInfo &dyn_reg_info) +ParseRegisters (XMLNode feature_node, GdbServerTargetInfo &target_info, GDBRemoteDynamicRegisterInfo &dyn_reg_info, ABISP abi_sp) { if (!feature_node) return false; - uint32_t prev_reg_num = 0; + uint32_t cur_reg_num = 0; uint32_t reg_offset = 0; - feature_node.ForEachChildElementWithName("reg", [&target_info, &dyn_reg_info, &prev_reg_num, ®_offset](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; @@ -4158,19 +4432,19 @@ ParseRegisters (XMLNode feature_node, GdbServerTargetInfo &target_info, GDBRemot 0, // byte size reg_offset, // offset eEncodingUint, // encoding - eFormatHex, // formate + eFormatHex, // format { - LLDB_INVALID_REGNUM, // GCC reg num + LLDB_INVALID_REGNUM, // eh_frame reg num LLDB_INVALID_REGNUM, // DWARF reg num LLDB_INVALID_REGNUM, // generic reg num - prev_reg_num, // GDB reg num - prev_reg_num // native register number + cur_reg_num, // process plugin reg num + cur_reg_num // native register number }, NULL, NULL }; - reg_node.ForEachAttribute([&target_info, &gdb_group, &gdb_type, ®_name, &alt_name, &set_name, &value_regs, &invalidate_regs, &encoding_set, &format_set, ®_info, &prev_reg_num, ®_offset](const llvm::StringRef &name, const llvm::StringRef &value) -> bool { + 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](const llvm::StringRef &name, const llvm::StringRef &value) -> bool { if (name == "name") { reg_name.SetString(value); @@ -4192,9 +4466,7 @@ ParseRegisters (XMLNode feature_node, GdbServerTargetInfo &target_info, GDBRemot const uint32_t regnum = StringConvert::ToUInt32(value.data(), LLDB_INVALID_REGNUM, 0); if (regnum != LLDB_INVALID_REGNUM) { - reg_info.kinds[eRegisterKindGDB] = regnum; - reg_info.kinds[eRegisterKindLLDB] = regnum; - prev_reg_num = regnum; + reg_info.kinds[eRegisterKindProcessPlugin] = regnum; } } else if (name == "offset") @@ -4240,9 +4512,9 @@ ParseRegisters (XMLNode feature_node, GdbServerTargetInfo &target_info, GDBRemot if (pos != target_info.reg_set_map.end()) set_name = pos->second.name; } - else if (name == "gcc_regnum") + else if (name == "gcc_regnum" || name == "ehframe_regnum") { - reg_info.kinds[eRegisterKindGCC] = StringConvert::ToUInt32(value.data(), LLDB_INVALID_REGNUM, 0); + reg_info.kinds[eRegisterKindEHFrame] = StringConvert::ToUInt32(value.data(), LLDB_INVALID_REGNUM, 0); } else if (name == "dwarf_regnum") { @@ -4305,7 +4577,8 @@ ParseRegisters (XMLNode feature_node, GdbServerTargetInfo &target_info, GDBRemot reg_info.invalidate_regs = invalidate_regs.data(); } - ++prev_reg_num; + ++cur_reg_num; + 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 @@ -4401,7 +4674,7 @@ ProcessGDBRemote::GetGDBServerRegisterInfo () if (feature_node) { - ParseRegisters(feature_node, target_info, this->m_register_info); + ParseRegisters(feature_node, target_info, this->m_register_info, GetABI()); } for (const auto &include : target_info.includes) @@ -4419,7 +4692,7 @@ ProcessGDBRemote::GetGDBServerRegisterInfo () XMLNode include_feature_node = include_xml_document.GetRootElement("feature"); if (include_feature_node) { - ParseRegisters(include_feature_node, target_info, this->m_register_info); + ParseRegisters(include_feature_node, target_info, this->m_register_info, GetABI()); } } this->m_register_info.Finalize(GetTarget().GetArchitecture()); @@ -4489,7 +4762,8 @@ ProcessGDBRemote::GetLoadedModuleList (GDBLoadedModuleInfoList & list) { // 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") { @@ -4504,13 +4778,15 @@ ProcessGDBRemote::GetLoadedModuleList (GDBLoadedModuleInfoList & list) { 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:0x08%" PRIx64 ", base:0x08%" PRIx64 ", ld:0x08%" PRIx64 ", name:'%s')", lm, base, ld, name.c_str()); + 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); @@ -4552,15 +4828,19 @@ ProcessGDBRemote::GetLoadedModuleList (GDBLoadedModuleInfoList & list) 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%" PRIx64 ", name:'%s')", base, name.c_str()); + log->Printf ("found (base:0x%08" PRIx64 "[%s], name:'%s')", base, (base_is_offset ? "offset" : "absolute"), name.c_str()); } list.add (module); @@ -4577,7 +4857,7 @@ ProcessGDBRemote::GetLoadedModuleList (GDBLoadedModuleInfoList & list) } lldb::ModuleSP -ProcessGDBRemote::LoadModuleAtAddress (const FileSpec &file, lldb::addr_t base_addr) +ProcessGDBRemote::LoadModuleAtAddress (const FileSpec &file, lldb::addr_t base_addr, bool value_is_offset) { Target &target = m_process->GetTarget(); ModuleList &modules = target.GetImages(); @@ -4588,11 +4868,11 @@ ProcessGDBRemote::LoadModuleAtAddress (const FileSpec &file, lldb::addr_t base_a ModuleSpec module_spec (file, target.GetArchitecture()); if ((module_sp = modules.FindFirstModule (module_spec))) { - module_sp->SetLoadAddress (target, base_addr, true, changed); + module_sp->SetLoadAddress (target, base_addr, value_is_offset, changed); } else if ((module_sp = target.GetSharedModule (module_spec))) { - module_sp->SetLoadAddress (target, base_addr, true, changed); + module_sp->SetLoadAddress (target, base_addr, value_is_offset, changed); } return module_sp; @@ -4615,10 +4895,12 @@ ProcessGDBRemote::LoadModules () { std::string mod_name; lldb::addr_t mod_base; + 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; @@ -4630,7 +4912,7 @@ ProcessGDBRemote::LoadModules () marker += 1; FileSpec file (mod_name.c_str()+marker, true); - lldb::ModuleSP module_sp = LoadModuleAtAddress (file, mod_base); + lldb::ModuleSP module_sp = LoadModuleAtAddress (file, mod_base, mod_base_is_offset); if (module_sp.get()) new_modules.Append (module_sp); @@ -4638,7 +4920,7 @@ ProcessGDBRemote::LoadModules () if (new_modules.GetSize() > 0) { - Target & target = m_target; + Target &target = GetTarget(); new_modules.ForEach ([&target](const lldb::ModuleSP module_sp) -> bool { diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 45c74ea..5474982 100644 --- a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -11,12 +11,14 @@ #define liblldb_ProcessGDBRemote_h_ // C Includes - // C++ Includes -#include <list> +#include <atomic> +#include <map> +#include <string> #include <vector> // Other libraries and framework includes +// Project includes #include "lldb/Core/ArchSpec.h" #include "lldb/Core/Broadcaster.h" #include "lldb/Core/ConstString.h" @@ -42,11 +44,12 @@ class ThreadGDBRemote; class ProcessGDBRemote : public Process { public: - //------------------------------------------------------------------ - // Constructors and Destructors - //------------------------------------------------------------------ + ProcessGDBRemote(lldb::TargetSP target_sp, Listener &listener); + + ~ProcessGDBRemote() override; + static lldb::ProcessSP - CreateInstance (Target& target, + CreateInstance (lldb::TargetSP target_sp, Listener &listener, const FileSpec *crash_file_path); @@ -66,18 +69,10 @@ public: GetPluginDescriptionStatic(); //------------------------------------------------------------------ - // Constructors and Destructors - //------------------------------------------------------------------ - ProcessGDBRemote(Target& target, Listener &listener); - - virtual - ~ProcessGDBRemote(); - - //------------------------------------------------------------------ // Check if a given Process //------------------------------------------------------------------ bool - CanDebug (Target &target, bool plugin_specified_by_name) override; + CanDebug (lldb::TargetSP target_sp, bool plugin_specified_by_name) override; CommandObject * GetPluginCommandObject() override; @@ -152,6 +147,9 @@ public: void RefreshStateAfterStop() override; + void + SetUnixSignals(const lldb::UnixSignalsSP &signals_sp); + //------------------------------------------------------------------ // Process Queries //------------------------------------------------------------------ @@ -161,6 +159,9 @@ public: lldb::addr_t GetImageInfoAddress() override; + void + WillPublicStop () override; + //------------------------------------------------------------------ // Process Memory //------------------------------------------------------------------ @@ -238,6 +239,11 @@ public: const ArchSpec& arch, ModuleSpec &module_spec) override; + bool + GetHostOSVersion(uint32_t &major, + uint32_t &minor, + uint32_t &update) override; + size_t LoadModules() override; @@ -257,20 +263,63 @@ protected: class GDBLoadedModuleInfoList; + //------------------------------------------------------------------ + /// 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 + Mutex m_last_stop_packet_mutex; + GDBRemoteDynamicRegisterInfo m_register_info; + Broadcaster m_async_broadcaster; + Listener m_async_listener; + HostThread m_async_thread; + 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); + return state == lldb::eStateRunning || IsStepping(state); } bool IsStepping ( lldb::StateType state) { - return state == lldb::eStateStepping; + return state == lldb::eStateStepping; } + bool CanResume ( lldb::StateType state) { @@ -306,6 +355,9 @@ protected: ThreadList &new_thread_list) override; Error + EstablishConnectionIfNeeded (const ProcessInfo &process_info); + + Error LaunchAndConnectToDebugserver (const ProcessInfo &process_info); void @@ -333,46 +385,10 @@ protected: CalculateThreadStopInfo (ThreadGDBRemote *thread); size_t - UpdateThreadIDsFromStopReplyThreadsValue (std::string &value); + UpdateThreadPCsFromStopReplyThreadsValue (std::string &value); - //------------------------------------------------------------------ - /// 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 - Mutex m_last_stop_packet_mutex; - GDBRemoteDynamicRegisterInfo m_register_info; - Broadcaster m_async_broadcaster; - HostThread m_async_thread; - 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 - StructuredData::ObjectSP m_threads_info_sp; // Stop info 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 inital thread ID, given by stub on attach + size_t + UpdateThreadIDsFromStopReplyThreadsValue (std::string &value); bool HandleNotifyPacket(StringExtractorGDBRemote &packet); @@ -396,7 +412,10 @@ protected: lldb::StateType SetThreadStopInfo (StringExtractor& stop_packet); - lldb::StateType + bool + GetThreadStopInfoFromJSON (ThreadGDBRemote *thread, const StructuredData::ObjectSP &thread_infos_sp); + + lldb::ThreadSP SetThreadStopInfo (StructuredData::Dictionary *thread_dict); lldb::ThreadSP @@ -445,7 +464,7 @@ protected: GetLoadedModuleList (GDBLoadedModuleInfoList &); lldb::ModuleSP - LoadModuleAtAddress (const FileSpec &file, lldb::addr_t base_addr); + LoadModuleAtAddress (const FileSpec &file, lldb::addr_t base_addr, bool value_is_offset); private: //------------------------------------------------------------------ @@ -458,10 +477,9 @@ private: lldb::user_id_t break_loc_id); DISALLOW_COPY_AND_ASSIGN (ProcessGDBRemote); - }; } // namespace process_gdb_remote } // namespace lldb_private -#endif // liblldb_ProcessGDBRemote_h_ +#endif // liblldb_ProcessGDBRemote_h_ diff --git a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp index d2a6503..9b410d8 100644 --- a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp +++ b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp @@ -313,6 +313,14 @@ ThreadGDBRemote::PrivateSetRegisterValue (uint32_t reg, StringExtractor &respons } 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()); diff --git a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h index 175433a..24693ba 100644 --- a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h +++ b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h @@ -10,8 +10,12 @@ #ifndef liblldb_ThreadGDBRemote_h_ #define liblldb_ThreadGDBRemote_h_ +// C Includes +// C++ Includes #include <string> +// Other libraries and framework includes +// Project includes #include "lldb/Core/StructuredData.h" #include "lldb/Target/Process.h" #include "lldb/Target/Thread.h" @@ -28,8 +32,7 @@ class ThreadGDBRemote : public Thread public: ThreadGDBRemote (Process &process, lldb::tid_t tid); - virtual - ~ThreadGDBRemote (); + ~ThreadGDBRemote() override; void WillResume (lldb::StateType resume_state) override; @@ -101,30 +104,27 @@ public: 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::QueueKind m_queue_kind; // Queue info from stop reply/stop info for thread + uint64_t m_queue_serial; // Queue info from stop reply/stop info for thread + bool PrivateSetRegisterValue (uint32_t reg, StringExtractor &response); bool + PrivateSetRegisterValue (uint32_t reg, + uint64_t regval); + + bool CachedQueueInfoIsValid() const { return m_queue_kind != lldb::eQueueKindUnknown; } - //------------------------------------------------------------------ - // Member variables. - //------------------------------------------------------------------ - std::string m_thread_name; - std::string m_dispatch_queue_name; - lldb::addr_t m_thread_dispatch_qaddr; - lldb::QueueKind m_queue_kind; // Queue info from stop reply/stop info for thread - uint64_t m_queue_serial; // Queue info from stop reply/stop info for thread - //------------------------------------------------------------------ - // Member variables. - //------------------------------------------------------------------ - void SetStopInfoFromPacket (StringExtractor &stop_packet, uint32_t stop_id); @@ -135,4 +135,4 @@ protected: } // namespace process_gdb_remote } // namespace lldb_private -#endif // liblldb_ThreadGDBRemote_h_ +#endif // liblldb_ThreadGDBRemote_h_ |