diff options
| author | Ed Maste <emaste@FreeBSD.org> | 2013-08-23 17:46:38 +0000 | 
|---|---|---|
| committer | Ed Maste <emaste@FreeBSD.org> | 2013-08-23 17:46:38 +0000 | 
| commit | f034231a6a1fd5d6395206c1651de8cd9402cca3 (patch) | |
| tree | f561dabc721ad515599172c16da3a4400b7f4aec /source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp | |
Notes
Diffstat (limited to 'source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp')
| -rw-r--r-- | source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp | 2348 | 
1 files changed, 2348 insertions, 0 deletions
| diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp new file mode 100644 index 000000000000..ca594a8f3fd5 --- /dev/null +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -0,0 +1,2348 @@ +//===-- GDBRemoteCommunicationClient.cpp ------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + + +#include "GDBRemoteCommunicationClient.h" + +// C Includes +// C++ Includes +#include <sstream> + +// Other libraries and framework includes +#include "llvm/ADT/Triple.h" +#include "lldb/Interpreter/Args.h" +#include "lldb/Core/ConnectionFileDescriptor.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/State.h" +#include "lldb/Core/StreamString.h" +#include "lldb/Host/Endian.h" +#include "lldb/Host/Host.h" +#include "lldb/Host/TimeValue.h" + +// Project includes +#include "Utility/StringExtractorGDBRemote.h" +#include "ProcessGDBRemote.h" +#include "ProcessGDBRemoteLog.h" + +using namespace lldb; +using namespace lldb_private; + +//---------------------------------------------------------------------- +// GDBRemoteCommunicationClient constructor +//---------------------------------------------------------------------- +GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) : +    GDBRemoteCommunication("gdb-remote.client", "gdb-remote.client.rx_packet", is_platform), +    m_supports_not_sending_acks (eLazyBoolCalculate), +    m_supports_thread_suffix (eLazyBoolCalculate), +    m_supports_threads_in_stop_reply (eLazyBoolCalculate), +    m_supports_vCont_all (eLazyBoolCalculate), +    m_supports_vCont_any (eLazyBoolCalculate), +    m_supports_vCont_c (eLazyBoolCalculate), +    m_supports_vCont_C (eLazyBoolCalculate), +    m_supports_vCont_s (eLazyBoolCalculate), +    m_supports_vCont_S (eLazyBoolCalculate), +    m_qHostInfo_is_valid (eLazyBoolCalculate), +    m_qProcessInfo_is_valid (eLazyBoolCalculate), +    m_supports_alloc_dealloc_memory (eLazyBoolCalculate), +    m_supports_memory_region_info  (eLazyBoolCalculate), +    m_supports_watchpoint_support_info  (eLazyBoolCalculate), +    m_supports_detach_stay_stopped (eLazyBoolCalculate), +    m_watchpoints_trigger_after_instruction(eLazyBoolCalculate), +    m_attach_or_wait_reply(eLazyBoolCalculate), +    m_prepare_for_reg_writing_reply (eLazyBoolCalculate), +    m_supports_qProcessInfoPID (true), +    m_supports_qfProcessInfo (true), +    m_supports_qUserName (true), +    m_supports_qGroupName (true), +    m_supports_qThreadStopInfo (true), +    m_supports_z0 (true), +    m_supports_z1 (true), +    m_supports_z2 (true), +    m_supports_z3 (true), +    m_supports_z4 (true), +    m_curr_tid (LLDB_INVALID_THREAD_ID), +    m_curr_tid_run (LLDB_INVALID_THREAD_ID), +    m_num_supported_hardware_watchpoints (0), +    m_async_mutex (Mutex::eMutexTypeRecursive), +    m_async_packet_predicate (false), +    m_async_packet (), +    m_async_response (), +    m_async_signal (-1), +    m_thread_id_to_used_usec_map (), +    m_host_arch(), +    m_process_arch(), +    m_os_version_major (UINT32_MAX), +    m_os_version_minor (UINT32_MAX), +    m_os_version_update (UINT32_MAX) +{ +} + +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +GDBRemoteCommunicationClient::~GDBRemoteCommunicationClient() +{ +    if (IsConnected()) +        Disconnect(); +} + +bool +GDBRemoteCommunicationClient::HandshakeWithServer (Error *error_ptr) +{ +    // Start the read thread after we send the handshake ack since if we +    // fail to send the handshake ack, there is no reason to continue... +    if (SendAck()) +        return true; +     +    if (error_ptr) +        error_ptr->SetErrorString("failed to send the handshake ack"); +    return false; +} + +void +GDBRemoteCommunicationClient::QueryNoAckModeSupported () +{ +    if (m_supports_not_sending_acks == eLazyBoolCalculate) +    { +        m_send_acks = true; +        m_supports_not_sending_acks = eLazyBoolNo; + +        StringExtractorGDBRemote response; +        if (SendPacketAndWaitForResponse("QStartNoAckMode", response, false)) +        { +            if (response.IsOKResponse()) +            { +                m_send_acks = false; +                m_supports_not_sending_acks = eLazyBoolYes; +            } +        } +    } +} + +void +GDBRemoteCommunicationClient::GetListThreadsInStopReplySupported () +{ +    if (m_supports_threads_in_stop_reply == eLazyBoolCalculate) +    { +        m_supports_threads_in_stop_reply = eLazyBoolNo; +         +        StringExtractorGDBRemote response; +        if (SendPacketAndWaitForResponse("QListThreadsInStopReply", response, false)) +        { +            if (response.IsOKResponse()) +                m_supports_threads_in_stop_reply = eLazyBoolYes; +        } +    } +} + +bool +GDBRemoteCommunicationClient::GetVAttachOrWaitSupported () +{ +    if (m_attach_or_wait_reply == eLazyBoolCalculate) +    { +        m_attach_or_wait_reply = eLazyBoolNo; +         +        StringExtractorGDBRemote response; +        if (SendPacketAndWaitForResponse("qVAttachOrWaitSupported", response, false)) +        { +            if (response.IsOKResponse()) +                m_attach_or_wait_reply = eLazyBoolYes; +        } +    } +    if (m_attach_or_wait_reply == eLazyBoolYes) +        return true; +    else +        return false; +} + +bool +GDBRemoteCommunicationClient::GetSyncThreadStateSupported () +{ +    if (m_prepare_for_reg_writing_reply == eLazyBoolCalculate) +    { +        m_prepare_for_reg_writing_reply = eLazyBoolNo; +         +        StringExtractorGDBRemote response; +        if (SendPacketAndWaitForResponse("qSyncThreadStateSupported", response, false)) +        { +            if (response.IsOKResponse()) +                m_prepare_for_reg_writing_reply = eLazyBoolYes; +        } +    } +    if (m_prepare_for_reg_writing_reply == eLazyBoolYes) +        return true; +    else +        return false; +} + + +void +GDBRemoteCommunicationClient::ResetDiscoverableSettings() +{ +    m_supports_not_sending_acks = eLazyBoolCalculate; +    m_supports_thread_suffix = eLazyBoolCalculate; +    m_supports_threads_in_stop_reply = eLazyBoolCalculate; +    m_supports_vCont_c = eLazyBoolCalculate; +    m_supports_vCont_C = eLazyBoolCalculate; +    m_supports_vCont_s = eLazyBoolCalculate; +    m_supports_vCont_S = eLazyBoolCalculate; +    m_qHostInfo_is_valid = eLazyBoolCalculate; +    m_qProcessInfo_is_valid = eLazyBoolCalculate; +    m_supports_alloc_dealloc_memory = eLazyBoolCalculate; +    m_supports_memory_region_info = eLazyBoolCalculate; +    m_prepare_for_reg_writing_reply = eLazyBoolCalculate; +    m_attach_or_wait_reply = eLazyBoolCalculate; + +    m_supports_qProcessInfoPID = true; +    m_supports_qfProcessInfo = true; +    m_supports_qUserName = true; +    m_supports_qGroupName = true; +    m_supports_qThreadStopInfo = true; +    m_supports_z0 = true; +    m_supports_z1 = true; +    m_supports_z2 = true; +    m_supports_z3 = true; +    m_supports_z4 = true; +    m_host_arch.Clear(); +    m_process_arch.Clear(); +} + + +bool +GDBRemoteCommunicationClient::GetThreadSuffixSupported () +{ +    if (m_supports_thread_suffix == eLazyBoolCalculate) +    { +        StringExtractorGDBRemote response; +        m_supports_thread_suffix = eLazyBoolNo; +        if (SendPacketAndWaitForResponse("QThreadSuffixSupported", response, false)) +        { +            if (response.IsOKResponse()) +                m_supports_thread_suffix = eLazyBoolYes; +        } +    } +    return m_supports_thread_suffix; +} +bool +GDBRemoteCommunicationClient::GetVContSupported (char flavor) +{ +    if (m_supports_vCont_c == eLazyBoolCalculate) +    { +        StringExtractorGDBRemote response; +        m_supports_vCont_any = eLazyBoolNo; +        m_supports_vCont_all = eLazyBoolNo; +        m_supports_vCont_c = eLazyBoolNo; +        m_supports_vCont_C = eLazyBoolNo; +        m_supports_vCont_s = eLazyBoolNo; +        m_supports_vCont_S = eLazyBoolNo; +        if (SendPacketAndWaitForResponse("vCont?", response, false)) +        { +            const char *response_cstr = response.GetStringRef().c_str(); +            if (::strstr (response_cstr, ";c")) +                m_supports_vCont_c = eLazyBoolYes; + +            if (::strstr (response_cstr, ";C")) +                m_supports_vCont_C = eLazyBoolYes; + +            if (::strstr (response_cstr, ";s")) +                m_supports_vCont_s = eLazyBoolYes; + +            if (::strstr (response_cstr, ";S")) +                m_supports_vCont_S = eLazyBoolYes; + +            if (m_supports_vCont_c == eLazyBoolYes && +                m_supports_vCont_C == eLazyBoolYes && +                m_supports_vCont_s == eLazyBoolYes && +                m_supports_vCont_S == eLazyBoolYes) +            { +                m_supports_vCont_all = eLazyBoolYes; +            } +             +            if (m_supports_vCont_c == eLazyBoolYes || +                m_supports_vCont_C == eLazyBoolYes || +                m_supports_vCont_s == eLazyBoolYes || +                m_supports_vCont_S == eLazyBoolYes) +            { +                m_supports_vCont_any = eLazyBoolYes; +            } +        } +    } +     +    switch (flavor) +    { +    case 'a': return m_supports_vCont_any; +    case 'A': return m_supports_vCont_all; +    case 'c': return m_supports_vCont_c; +    case 'C': return m_supports_vCont_C; +    case 's': return m_supports_vCont_s; +    case 'S': return m_supports_vCont_S; +    default: break; +    } +    return false; +} + + +size_t +GDBRemoteCommunicationClient::SendPacketAndWaitForResponse +( +    const char *payload, +    StringExtractorGDBRemote &response, +    bool send_async +) +{ +    return SendPacketAndWaitForResponse (payload,  +                                         ::strlen (payload), +                                         response, +                                         send_async); +} + +size_t +GDBRemoteCommunicationClient::SendPacketAndWaitForResponse +( +    const char *payload, +    size_t payload_length, +    StringExtractorGDBRemote &response, +    bool send_async +) +{ +    Mutex::Locker locker; +    Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); +    size_t response_len = 0; +    if (GetSequenceMutex (locker)) +    { +        if (SendPacketNoLock (payload, payload_length)) +           response_len = WaitForPacketWithTimeoutMicroSecondsNoLock (response, GetPacketTimeoutInMicroSeconds ()); +        else  +        { +            if (log) +                log->Printf("error: failed to send '%*s'", (int) payload_length, payload);    +        } +    } +    else +    { +        if (send_async) +        { +            if (IsRunning()) +            { +                Mutex::Locker async_locker (m_async_mutex); +                m_async_packet.assign(payload, payload_length); +                m_async_packet_predicate.SetValue (true, eBroadcastNever); +                 +                if (log)  +                    log->Printf ("async: async packet = %s", m_async_packet.c_str()); + +                bool timed_out = false; +                if (SendInterrupt(locker, 2, timed_out)) +                { +                    if (m_interrupt_sent) +                    { +                        m_interrupt_sent = false; +                        TimeValue timeout_time; +                        timeout_time = TimeValue::Now(); +                        timeout_time.OffsetWithSeconds (m_packet_timeout); + +                        if (log)  +                            log->Printf ("async: sent interrupt"); + +                        if (m_async_packet_predicate.WaitForValueEqualTo (false, &timeout_time, &timed_out)) +                        { +                            if (log)  +                                log->Printf ("async: got response"); + +                            // Swap the response buffer to avoid malloc and string copy +                            response.GetStringRef().swap (m_async_response.GetStringRef()); +                            response_len = response.GetStringRef().size(); +                        } +                        else +                        { +                            if (log)  +                                log->Printf ("async: timed out waiting for response"); +                        } +                         +                        // Make sure we wait until the continue packet has been sent again... +                        if (m_private_is_running.WaitForValueEqualTo (true, &timeout_time, &timed_out)) +                        { +                            if (log) +                            { +                                if (timed_out)  +                                    log->Printf ("async: timed out waiting for process to resume, but process was resumed"); +                                else +                                    log->Printf ("async: async packet sent"); +                            } +                        } +                        else +                        { +                            if (log)  +                                log->Printf ("async: timed out waiting for process to resume"); +                        } +                    } +                    else +                    { +                        // We had a racy condition where we went to send the interrupt +                        // yet we were able to get the lock, so the process must have +                        // just stopped? +                        if (log)  +                            log->Printf ("async: got lock without sending interrupt"); +                        // Send the packet normally since we got the lock +                        if (SendPacketNoLock (payload, payload_length)) +                            response_len = WaitForPacketWithTimeoutMicroSecondsNoLock (response, GetPacketTimeoutInMicroSeconds ()); +                        else  +                        { +                            if (log) +                                log->Printf("error: failed to send '%*s'", (int) payload_length, payload);    +                        } +                    } +                } +                else +                { +                    if (log)  +                        log->Printf ("async: failed to interrupt"); +                } +            } +            else +            { +                if (log)  +                    log->Printf ("async: not running, async is ignored"); +            } +        } +        else +        { +            if (log)  +                log->Printf("error: failed to get packet sequence mutex, not sending packet '%*s'", (int) payload_length, payload); +        } +    } +    if (response_len == 0) +    { +        if (log)  +            log->Printf("error: failed to get response for '%*s'", (int) payload_length, payload); +    }         +    return response_len; +} + +static const char *end_delimiter = "--end--;"; +static const int end_delimiter_len = 8; + +std::string +GDBRemoteCommunicationClient::HarmonizeThreadIdsForProfileData +(   ProcessGDBRemote *process, +    StringExtractorGDBRemote& profileDataExtractor +) +{ +    std::map<uint64_t, uint32_t> new_thread_id_to_used_usec_map; +    std::stringstream final_output; +    std::string name, value; + +    // Going to assuming thread_used_usec comes first, else bail out. +    while (profileDataExtractor.GetNameColonValue(name, value)) +    { +        if (name.compare("thread_used_id") == 0) +        { +            StringExtractor threadIDHexExtractor(value.c_str()); +            uint64_t thread_id = threadIDHexExtractor.GetHexMaxU64(false, 0); +             +            bool has_used_usec = false; +            uint32_t curr_used_usec = 0; +            std::string usec_name, usec_value; +            uint32_t input_file_pos = profileDataExtractor.GetFilePos(); +            if (profileDataExtractor.GetNameColonValue(usec_name, usec_value)) +            { +                if (usec_name.compare("thread_used_usec") == 0) +                { +                    has_used_usec = true; +                    curr_used_usec = strtoull(usec_value.c_str(), NULL, 0); +                } +                else +                { +                    // We didn't find what we want, it is probably +                    // an older version. Bail out. +                    profileDataExtractor.SetFilePos(input_file_pos); +                } +            } + +            if (has_used_usec) +            { +                uint32_t prev_used_usec = 0; +                std::map<uint64_t, uint32_t>::iterator iterator = m_thread_id_to_used_usec_map.find(thread_id); +                if (iterator != m_thread_id_to_used_usec_map.end()) +                { +                    prev_used_usec = m_thread_id_to_used_usec_map[thread_id]; +                } +                 +                uint32_t real_used_usec = curr_used_usec - prev_used_usec; +                // A good first time record is one that runs for at least 0.25 sec +                bool good_first_time = (prev_used_usec == 0) && (real_used_usec > 250000); +                bool good_subsequent_time = (prev_used_usec > 0) && +                    ((real_used_usec > 0) || (process->HasAssignedIndexIDToThread(thread_id))); +                 +                if (good_first_time || good_subsequent_time) +                { +                    // We try to avoid doing too many index id reservation, +                    // resulting in fast increase of index ids. +                     +                    final_output << name << ":"; +                    int32_t index_id = process->AssignIndexIDToThread(thread_id); +                    final_output << index_id << ";"; +                     +                    final_output << usec_name << ":" << usec_value << ";"; +                } +                else +                { +                    // Skip past 'thread_used_name'. +                    std::string local_name, local_value; +                    profileDataExtractor.GetNameColonValue(local_name, local_value); +                } +                 +                // Store current time as previous time so that they can be compared later. +                new_thread_id_to_used_usec_map[thread_id] = curr_used_usec; +            } +            else +            { +                // Bail out and use old string. +                final_output << name << ":" << value << ";"; +            } +        } +        else +        { +            final_output << name << ":" << value << ";"; +        } +    } +    final_output << end_delimiter; +    m_thread_id_to_used_usec_map = new_thread_id_to_used_usec_map; +     +    return final_output.str(); +} + +StateType +GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse +( +    ProcessGDBRemote *process, +    const char *payload, +    size_t packet_length, +    StringExtractorGDBRemote &response +) +{ +    m_curr_tid = LLDB_INVALID_THREAD_ID; +    Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); +    if (log) +        log->Printf ("GDBRemoteCommunicationClient::%s ()", __FUNCTION__); + +    Mutex::Locker locker(m_sequence_mutex); +    StateType state = eStateRunning; + +    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... +    std::string continue_packet(payload, packet_length); +     +    bool got_async_packet = false; +     +    while (state == eStateRunning) +    { +        if (!got_async_packet) +        { +            if (log) +                log->Printf ("GDBRemoteCommunicationClient::%s () sending continue packet: %s", __FUNCTION__, continue_packet.c_str()); +            if (SendPacketNoLock(continue_packet.c_str(), continue_packet.size()) == 0) +                state = eStateInvalid; +         +            m_private_is_running.SetValue (true, eBroadcastAlways); +        } +         +        got_async_packet = false; + +        if (log) +            log->Printf ("GDBRemoteCommunicationClient::%s () WaitForPacket(%s)", __FUNCTION__, continue_packet.c_str()); + +        if (WaitForPacketWithTimeoutMicroSecondsNoLock(response, UINT32_MAX)) +        { +            if (response.Empty()) +                state = eStateInvalid; +            else +            { +                const char stop_type = response.GetChar(); +                if (log) +                    log->Printf ("GDBRemoteCommunicationClient::%s () got packet: %s", __FUNCTION__, response.GetStringRef().c_str()); +                switch (stop_type) +                { +                case 'T': +                case 'S': +                    { +                        if (process->GetStopID() == 0) +                        { +                            if (process->GetID() == LLDB_INVALID_PROCESS_ID) +                            { +                                lldb::pid_t pid = GetCurrentProcessID (); +                                if (pid != LLDB_INVALID_PROCESS_ID) +                                    process->SetID (pid); +                            } +                            process->BuildDynamicRegisterInfo (true); +                        } + +                        // Privately notify any internal threads that we have stopped +                        // in case we wanted to interrupt our process, yet we might +                        // send a packet and continue without returning control to the +                        // user. +                        m_private_is_running.SetValue (false, eBroadcastAlways); + +                        const uint8_t signo = response.GetHexU8 (UINT8_MAX); + +                        bool continue_after_async = m_async_signal != -1 || m_async_packet_predicate.GetValue(); +                        if (continue_after_async || m_interrupt_sent) +                        { +                            // We sent an interrupt packet to stop the inferior process +                            // for an async signal or to send an async packet while running +                            // but we might have been single stepping and received the +                            // stop packet for the step instead of for the interrupt packet. +                            // Typically when an interrupt is sent a SIGINT or SIGSTOP +                            // is used, so if we get anything else, we need to try and +                            // get another stop reply packet that may have been sent +                            // due to sending the interrupt when the target is stopped +                            // which will just re-send a copy of the last stop reply +                            // packet. If we don't do this, then the reply for our +                            // async packet will be the repeat stop reply packet and cause +                            // a lot of trouble for us! +                            if (signo != SIGINT && signo != SIGSTOP) +                            { +                                continue_after_async = false; + +                                // We didn't get a a SIGINT or SIGSTOP, so try for a +                                // very brief time (1 ms) 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; +                                if (WaitForPacketWithTimeoutMicroSecondsNoLock (extra_stop_reply_packet, timeout_usec)) +                                { +                                    switch (extra_stop_reply_packet.GetChar()) +                                    { +                                    case 'T': +                                    case 'S': +                                        // We did get an extra stop reply, which means +                                        // our interrupt didn't stop the target so we +                                        // shouldn't continue after the async signal +                                        // or packet is sent... +                                        continue_after_async = false; +                                        break; +                                    } +                                } +                            } +                        } + +                        if (m_async_signal != -1) +                        { +                            if (log) +                                log->Printf ("async: send signo = %s", Host::GetSignalAsCString (m_async_signal)); + +                            // Save off the async signal we are supposed to send +                            const int async_signal = m_async_signal; +                            // Clear the async signal member so we don't end up +                            // sending the signal multiple times... +                            m_async_signal = -1; +                            // Check which signal we stopped with +                            if (signo == async_signal) +                            { +                                if (log)  +                                    log->Printf ("async: stopped with signal %s, we are done running", Host::GetSignalAsCString (signo)); + +                                // We already stopped with a signal that we wanted +                                // to stop with, so we are done +                            } +                            else +                            { +                                // We stopped with a different signal that the one +                                // we wanted to stop with, so now we must resume +                                // with the signal we want +                                char signal_packet[32]; +                                int signal_packet_len = 0; +                                signal_packet_len = ::snprintf (signal_packet, +                                                                sizeof (signal_packet), +                                                                "C%2.2x", +                                                                async_signal); + +                                if (log)  +                                    log->Printf ("async: stopped with signal %s, resume with %s",  +                                                       Host::GetSignalAsCString (signo), +                                                       Host::GetSignalAsCString (async_signal)); + +                                // Set the continue packet to resume even if the +                                // interrupt didn't cause our stop (ignore continue_after_async) +                                continue_packet.assign(signal_packet, signal_packet_len); +                                continue; +                            } +                        } +                        else if (m_async_packet_predicate.GetValue()) +                        { +                            Log * packet_log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS)); + +                            // We are supposed to send an asynchronous packet while +                            // we are running.  +                            m_async_response.Clear(); +                            if (m_async_packet.empty()) +                            { +                                if (packet_log)  +                                    packet_log->Printf ("async: error: empty async packet");                             + +                            } +                            else +                            { +                                if (packet_log)  +                                    packet_log->Printf ("async: sending packet"); +                                 +                                SendPacketAndWaitForResponse (&m_async_packet[0],  +                                                              m_async_packet.size(), +                                                              m_async_response, +                                                              false); +                            } +                            // Let the other thread that was trying to send the async +                            // packet know that the packet has been sent and response is +                            // ready... +                            m_async_packet_predicate.SetValue(false, eBroadcastAlways); + +                            if (packet_log)  +                                packet_log->Printf ("async: sent packet, continue_after_async = %i", continue_after_async); + +                            // Set the continue packet to resume if our interrupt +                            // for the async packet did cause the stop +                            if (continue_after_async) +                            { +                                // Reverting this for now as it is causing deadlocks +                                // in programs (<rdar://problem/11529853>). In the future +                                // we should check our thread list and "do the right thing" +                                // for new threads that show up while we stop and run async +                                // packets. Setting the packet to 'c' to continue all threads +                                // is the right thing to do 99.99% of the time because if a +                                // thread was single stepping, and we sent an interrupt, we +                                // will notice above that we didn't stop due to an interrupt +                                // but stopped due to stepping and we would _not_ continue. +                                continue_packet.assign (1, 'c'); +                                continue; +                            } +                        } +                        // Stop with signal and thread info +                        state = eStateStopped; +                    } +                    break; + +                case 'W': +                case 'X': +                    // process exited +                    state = eStateExited; +                    break; + +                case 'O': +                    // STDOUT +                    { +                        got_async_packet = true; +                        std::string inferior_stdout; +                        inferior_stdout.reserve(response.GetBytesLeft () / 2); +                        char ch; +                        while ((ch = response.GetHexU8()) != '\0') +                            inferior_stdout.append(1, ch); +                        process->AppendSTDOUT (inferior_stdout.c_str(), inferior_stdout.size()); +                    } +                    break; + +                case 'A': +                    // Async miscellaneous reply. Right now, only profile data is coming through this channel. +                    { +                        got_async_packet = true; +                        std::string input = response.GetStringRef().substr(1); // '1' to move beyond 'A' +                        if (m_partial_profile_data.length() > 0) +                        { +                            m_partial_profile_data.append(input); +                            input = m_partial_profile_data; +                            m_partial_profile_data.clear(); +                        } +                         +                        size_t found, pos = 0, len = input.length(); +                        while ((found = input.find(end_delimiter, pos)) != std::string::npos) +                        { +                            StringExtractorGDBRemote profileDataExtractor(input.substr(pos, found).c_str()); +                            std::string profile_data = HarmonizeThreadIdsForProfileData(process, profileDataExtractor); +                            process->BroadcastAsyncProfileData (profile_data); +                             +                            pos = found + end_delimiter_len; +                        } +                         +                        if (pos < len) +                        { +                            // Last incomplete chunk. +                            m_partial_profile_data = input.substr(pos); +                        } +                    } +                    break; + +                case 'E': +                    // ERROR +                    state = eStateInvalid; +                    break; + +                default: +                    if (log) +                        log->Printf ("GDBRemoteCommunicationClient::%s () unrecognized async packet", __FUNCTION__); +                    state = eStateInvalid; +                    break; +                } +            } +        } +        else +        { +            if (log) +                log->Printf ("GDBRemoteCommunicationClient::%s () WaitForPacket(...) => false", __FUNCTION__); +            state = eStateInvalid; +        } +    } +    if (log) +        log->Printf ("GDBRemoteCommunicationClient::%s () => %s", __FUNCTION__, StateAsCString(state)); +    response.SetFilePos(0); +    m_private_is_running.SetValue (false, eBroadcastAlways); +    m_public_is_running.SetValue (false, eBroadcastAlways); +    return state; +} + +bool +GDBRemoteCommunicationClient::SendAsyncSignal (int signo) +{ +    Mutex::Locker async_locker (m_async_mutex); +    m_async_signal = signo; +    bool timed_out = false; +    Mutex::Locker locker; +    if (SendInterrupt (locker, 1, timed_out)) +        return true; +    m_async_signal = -1; +    return false; +} + +// This function takes a mutex locker as a parameter in case the GetSequenceMutex +// actually succeeds. If it doesn't succeed in acquiring the sequence mutex  +// (the expected result), then it will send the halt packet. If it does succeed +// then the caller that requested the interrupt will want to keep the sequence +// locked down so that no one else can send packets while the caller has control. +// This function usually gets called when we are running and need to stop the  +// target. It can also be used when we are running and and we need to do something +// else (like read/write memory), so we need to interrupt the running process +// (gdb remote protocol requires this), and do what we need to do, then resume. + +bool +GDBRemoteCommunicationClient::SendInterrupt +( +    Mutex::Locker& locker,  +    uint32_t seconds_to_wait_for_stop,              +    bool &timed_out +) +{ +    timed_out = false; +    Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_PROCESS | GDBR_LOG_PACKETS)); + +    if (IsRunning()) +    { +        // Only send an interrupt if our debugserver is running... +        if (GetSequenceMutex (locker)) +        { +            if (log) +                log->Printf ("SendInterrupt () - got sequence mutex without having to interrupt"); +        } +        else +        { +            // Someone has the mutex locked waiting for a response or for the +            // inferior to stop, so send the interrupt on the down low... +            char ctrl_c = '\x03'; +            ConnectionStatus status = eConnectionStatusSuccess; +            size_t bytes_written = Write (&ctrl_c, 1, status, NULL); +            if (log) +                log->PutCString("send packet: \\x03"); +            if (bytes_written > 0) +            { +                m_interrupt_sent = true; +                if (seconds_to_wait_for_stop) +                { +                    TimeValue timeout; +                    if (seconds_to_wait_for_stop) +                    { +                        timeout = TimeValue::Now(); +                        timeout.OffsetWithSeconds (seconds_to_wait_for_stop); +                    } +                    if (m_private_is_running.WaitForValueEqualTo (false, &timeout, &timed_out)) +                    { +                        if (log) +                            log->PutCString ("SendInterrupt () - sent interrupt, private state stopped"); +                        return true; +                    } +                    else +                    { +                        if (log) +                            log->Printf ("SendInterrupt () - sent interrupt, timed out wating for async thread resume"); +                    } +                } +                else +                { +                    if (log) +                        log->Printf ("SendInterrupt () - sent interrupt, not waiting for stop..."); +                    return true; +                } +            } +            else +            { +                if (log) +                    log->Printf ("SendInterrupt () - failed to write interrupt"); +            } +            return false; +        } +    } +    else +    { +        if (log) +            log->Printf ("SendInterrupt () - not running"); +    } +    return true; +} + +lldb::pid_t +GDBRemoteCommunicationClient::GetCurrentProcessID () +{ +    StringExtractorGDBRemote response; +    if (SendPacketAndWaitForResponse("qC", strlen("qC"), response, false)) +    { +        if (response.GetChar() == 'Q') +            if (response.GetChar() == 'C') +                return response.GetHexMaxU32 (false, LLDB_INVALID_PROCESS_ID); +    } +    return LLDB_INVALID_PROCESS_ID; +} + +bool +GDBRemoteCommunicationClient::GetLaunchSuccess (std::string &error_str) +{ +    error_str.clear(); +    StringExtractorGDBRemote response; +    if (SendPacketAndWaitForResponse("qLaunchSuccess", strlen("qLaunchSuccess"), response, false)) +    { +        if (response.IsOKResponse()) +            return true; +        if (response.GetChar() == 'E') +        { +            // A string the describes what failed when launching... +            error_str = response.GetStringRef().substr(1); +        } +        else +        { +            error_str.assign ("unknown error occurred launching process"); +        } +    } +    else +    { +        error_str.assign ("timed out waiting for app to launch"); +    } +    return false; +} + +int +GDBRemoteCommunicationClient::SendArgumentsPacket (char const *argv[]) +{ +    if (argv && argv[0]) +    { +        StreamString packet; +        packet.PutChar('A'); +        const char *arg; +        for (uint32_t i = 0; (arg = argv[i]) != NULL; ++i) +        { +            const int arg_len = strlen(arg); +            if (i > 0) +                packet.PutChar(','); +            packet.Printf("%i,%i,", arg_len * 2, i); +            packet.PutBytesAsRawHex8 (arg, arg_len); +        } + +        StringExtractorGDBRemote response; +        if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) +        { +            if (response.IsOKResponse()) +                return 0; +            uint8_t error = response.GetError(); +            if (error) +                return error; +        } +    } +    return -1; +} + +int +GDBRemoteCommunicationClient::SendEnvironmentPacket (char const *name_equal_value) +{ +    if (name_equal_value && name_equal_value[0]) +    { +        StreamString packet; +        packet.Printf("QEnvironment:%s", name_equal_value); +        StringExtractorGDBRemote response; +        if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) +        { +            if (response.IsOKResponse()) +                return 0; +            uint8_t error = response.GetError(); +            if (error) +                return error; +        } +    } +    return -1; +} + +int +GDBRemoteCommunicationClient::SendLaunchArchPacket (char const *arch) +{ +    if (arch && arch[0]) +    { +        StreamString packet; +        packet.Printf("QLaunchArch:%s", arch); +        StringExtractorGDBRemote response; +        if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) +        { +            if (response.IsOKResponse()) +                return 0; +            uint8_t error = response.GetError(); +            if (error) +                return error; +        } +    } +    return -1; +} + +bool +GDBRemoteCommunicationClient::GetOSVersion (uint32_t &major,  +                                            uint32_t &minor,  +                                            uint32_t &update) +{ +    if (GetHostInfo ()) +    { +        if (m_os_version_major != UINT32_MAX) +        { +            major = m_os_version_major; +            minor = m_os_version_minor; +            update = m_os_version_update; +            return true; +        } +    } +    return false; +} + +bool +GDBRemoteCommunicationClient::GetOSBuildString (std::string &s) +{ +    if (GetHostInfo ()) +    { +        if (!m_os_build.empty()) +        { +            s = m_os_build; +            return true; +        } +    } +    s.clear(); +    return false; +} + + +bool +GDBRemoteCommunicationClient::GetOSKernelDescription (std::string &s) +{ +    if (GetHostInfo ()) +    { +        if (!m_os_kernel.empty()) +        { +            s = m_os_kernel; +            return true; +        } +    } +    s.clear(); +    return false; +} + +bool +GDBRemoteCommunicationClient::GetHostname (std::string &s) +{ +    if (GetHostInfo ()) +    { +        if (!m_hostname.empty()) +        { +            s = m_hostname; +            return true; +        } +    } +    s.clear(); +    return false; +} + +ArchSpec +GDBRemoteCommunicationClient::GetSystemArchitecture () +{ +    if (GetHostInfo ()) +        return m_host_arch; +    return ArchSpec(); +} + +const lldb_private::ArchSpec & +GDBRemoteCommunicationClient::GetProcessArchitecture () +{ +    if (m_qProcessInfo_is_valid == eLazyBoolCalculate) +        GetCurrentProcessInfo (); +    return m_process_arch; +} + + +bool +GDBRemoteCommunicationClient::GetHostInfo (bool force) +{ +    if (force || m_qHostInfo_is_valid == eLazyBoolCalculate) +    { +        m_qHostInfo_is_valid = eLazyBoolNo; +        StringExtractorGDBRemote response; +        if (SendPacketAndWaitForResponse ("qHostInfo", response, false)) +        { +            if (response.IsNormalResponse()) +            { +                std::string name; +                std::string value; +                uint32_t cpu = LLDB_INVALID_CPUTYPE; +                uint32_t sub = 0; +                std::string arch_name; +                std::string os_name; +                std::string vendor_name; +                std::string triple; +                uint32_t pointer_byte_size = 0; +                StringExtractor extractor; +                ByteOrder byte_order = eByteOrderInvalid; +                uint32_t num_keys_decoded = 0; +                while (response.GetNameColonValue(name, value)) +                { +                    if (name.compare("cputype") == 0) +                    { +                        // exception type in big endian hex +                        cpu = Args::StringToUInt32 (value.c_str(), LLDB_INVALID_CPUTYPE, 0); +                        if (cpu != LLDB_INVALID_CPUTYPE) +                            ++num_keys_decoded; +                    } +                    else if (name.compare("cpusubtype") == 0) +                    { +                        // exception count in big endian hex +                        sub = Args::StringToUInt32 (value.c_str(), 0, 0); +                        if (sub != 0) +                            ++num_keys_decoded; +                    } +                    else if (name.compare("arch") == 0) +                    { +                        arch_name.swap (value); +                        ++num_keys_decoded; +                    } +                    else if (name.compare("triple") == 0) +                    { +                        // The triple comes as ASCII hex bytes since it contains '-' chars +                        extractor.GetStringRef().swap(value); +                        extractor.SetFilePos(0); +                        extractor.GetHexByteString (triple); +                        ++num_keys_decoded; +                    } +                    else if (name.compare("os_build") == 0) +                    { +                        extractor.GetStringRef().swap(value); +                        extractor.SetFilePos(0); +                        extractor.GetHexByteString (m_os_build); +                        ++num_keys_decoded; +                    } +                    else if (name.compare("hostname") == 0) +                    { +                        extractor.GetStringRef().swap(value); +                        extractor.SetFilePos(0); +                        extractor.GetHexByteString (m_hostname); +                        ++num_keys_decoded; +                    } +                    else if (name.compare("os_kernel") == 0) +                    { +                        extractor.GetStringRef().swap(value); +                        extractor.SetFilePos(0); +                        extractor.GetHexByteString (m_os_kernel); +                        ++num_keys_decoded; +                    } +                    else if (name.compare("ostype") == 0) +                    { +                        os_name.swap (value); +                        ++num_keys_decoded; +                    } +                    else if (name.compare("vendor") == 0) +                    { +                        vendor_name.swap(value); +                        ++num_keys_decoded; +                    } +                    else if (name.compare("endian") == 0) +                    { +                        ++num_keys_decoded; +                        if (value.compare("little") == 0) +                            byte_order = eByteOrderLittle; +                        else if (value.compare("big") == 0) +                            byte_order = eByteOrderBig; +                        else if (value.compare("pdp") == 0) +                            byte_order = eByteOrderPDP; +                        else +                            --num_keys_decoded; +                    } +                    else if (name.compare("ptrsize") == 0) +                    { +                        pointer_byte_size = Args::StringToUInt32 (value.c_str(), 0, 0); +                        if (pointer_byte_size != 0) +                            ++num_keys_decoded; +                    } +                    else if (name.compare("os_version") == 0) +                    { +                        Args::StringToVersion (value.c_str(),  +                                               m_os_version_major, +                                               m_os_version_minor, +                                               m_os_version_update); +                        if (m_os_version_major != UINT32_MAX) +                            ++num_keys_decoded; +                    } +                    else if (name.compare("watchpoint_exceptions_received") == 0) +                    { +                        ++num_keys_decoded; +                        if (strcmp(value.c_str(),"before") == 0) +                            m_watchpoints_trigger_after_instruction = eLazyBoolNo; +                        else if (strcmp(value.c_str(),"after") == 0) +                            m_watchpoints_trigger_after_instruction = eLazyBoolYes; +                        else +                            --num_keys_decoded; +                    } + +                } +                 +                if (num_keys_decoded > 0) +                    m_qHostInfo_is_valid = eLazyBoolYes; + +                if (triple.empty()) +                { +                    if (arch_name.empty()) +                    { +                        if (cpu != LLDB_INVALID_CPUTYPE) +                        { +                            m_host_arch.SetArchitecture (eArchTypeMachO, cpu, sub); +                            if (pointer_byte_size) +                            { +                                assert (pointer_byte_size == m_host_arch.GetAddressByteSize()); +                            } +                            if (byte_order != eByteOrderInvalid) +                            { +                                assert (byte_order == m_host_arch.GetByteOrder()); +                            } + +                            if (!os_name.empty() && vendor_name.compare("apple") == 0 && os_name.find("darwin") == 0) +                            { +                                switch (m_host_arch.GetMachine()) +                                { +                                case llvm::Triple::arm: +                                case llvm::Triple::thumb: +                                    os_name = "ios"; +                                    break; +                                default: +                                    os_name = "macosx"; +                                    break; +                                } +                            } +                            if (!vendor_name.empty()) +                                m_host_arch.GetTriple().setVendorName (llvm::StringRef (vendor_name)); +                            if (!os_name.empty()) +                                m_host_arch.GetTriple().setOSName (llvm::StringRef (os_name)); +                                 +                        } +                    } +                    else +                    { +                        std::string triple; +                        triple += arch_name; +                        if (!vendor_name.empty() || !os_name.empty()) +                        { +                            triple += '-'; +                            if (vendor_name.empty()) +                                triple += "unknown"; +                            else +                                triple += vendor_name; +                            triple += '-'; +                            if (os_name.empty()) +                                triple += "unknown"; +                            else +                                triple += os_name; +                        } +                        m_host_arch.SetTriple (triple.c_str()); +                         +                        llvm::Triple &host_triple = m_host_arch.GetTriple(); +                        if (host_triple.getVendor() == llvm::Triple::Apple && host_triple.getOS() == llvm::Triple::Darwin) +                        { +                            switch (m_host_arch.GetMachine()) +                            { +                                case llvm::Triple::arm: +                                case llvm::Triple::thumb: +                                    host_triple.setOS(llvm::Triple::IOS); +                                    break; +                                default: +                                    host_triple.setOS(llvm::Triple::MacOSX); +                                    break; +                            } +                        } +                        if (pointer_byte_size) +                        { +                            assert (pointer_byte_size == m_host_arch.GetAddressByteSize()); +                        } +                        if (byte_order != eByteOrderInvalid) +                        { +                            assert (byte_order == m_host_arch.GetByteOrder()); +                        } +                         +                    } +                } +                else +                { +                    m_host_arch.SetTriple (triple.c_str()); +                    if (pointer_byte_size) +                    { +                        assert (pointer_byte_size == m_host_arch.GetAddressByteSize()); +                    } +                    if (byte_order != eByteOrderInvalid) +                    { +                        assert (byte_order == m_host_arch.GetByteOrder()); +                    } +                }        +            } +        } +    } +    return m_qHostInfo_is_valid == eLazyBoolYes; +} + +int +GDBRemoteCommunicationClient::SendAttach  +( +    lldb::pid_t pid,  +    StringExtractorGDBRemote& response +) +{ +    if (pid != LLDB_INVALID_PROCESS_ID) +    { +        char packet[64]; +        const int packet_len = ::snprintf (packet, sizeof(packet), "vAttach;%" PRIx64, pid); +        assert (packet_len < (int)sizeof(packet)); +        if (SendPacketAndWaitForResponse (packet, packet_len, response, false)) +        { +            if (response.IsErrorResponse()) +                return response.GetError(); +            return 0; +        } +    } +    return -1; +} + +const lldb_private::ArchSpec & +GDBRemoteCommunicationClient::GetHostArchitecture () +{ +    if (m_qHostInfo_is_valid == eLazyBoolCalculate) +        GetHostInfo (); +    return m_host_arch; +} + +addr_t +GDBRemoteCommunicationClient::AllocateMemory (size_t size, uint32_t permissions) +{ +    if (m_supports_alloc_dealloc_memory != eLazyBoolNo) +    { +        m_supports_alloc_dealloc_memory = eLazyBoolYes; +        char packet[64]; +        const int packet_len = ::snprintf (packet, sizeof(packet), "_M%" PRIx64 ",%s%s%s", +                                           (uint64_t)size, +                                           permissions & lldb::ePermissionsReadable ? "r" : "", +                                           permissions & lldb::ePermissionsWritable ? "w" : "", +                                           permissions & lldb::ePermissionsExecutable ? "x" : ""); +        assert (packet_len < (int)sizeof(packet)); +        StringExtractorGDBRemote response; +        if (SendPacketAndWaitForResponse (packet, packet_len, response, false)) +        { +            if (!response.IsErrorResponse()) +                return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS); +        } +        else +        { +            m_supports_alloc_dealloc_memory = eLazyBoolNo; +        } +    } +    return LLDB_INVALID_ADDRESS; +} + +bool +GDBRemoteCommunicationClient::DeallocateMemory (addr_t addr) +{ +    if (m_supports_alloc_dealloc_memory != eLazyBoolNo) +    { +        m_supports_alloc_dealloc_memory = eLazyBoolYes; +        char packet[64]; +        const int packet_len = ::snprintf(packet, sizeof(packet), "_m%" PRIx64, (uint64_t)addr); +        assert (packet_len < (int)sizeof(packet)); +        StringExtractorGDBRemote response; +        if (SendPacketAndWaitForResponse (packet, packet_len, response, false)) +        { +            if (response.IsOKResponse()) +                return true; +        } +        else +        { +            m_supports_alloc_dealloc_memory = eLazyBoolNo; +        } +    } +    return false; +} + +Error +GDBRemoteCommunicationClient::Detach (bool keep_stopped) +{ +    Error error; +     +    if (keep_stopped) +    { +        if (m_supports_detach_stay_stopped == eLazyBoolCalculate) +        { +            char packet[64]; +            const int packet_len = ::snprintf(packet, sizeof(packet), "qSupportsDetachAndStayStopped:"); +            assert (packet_len < (int)sizeof(packet)); +            StringExtractorGDBRemote response; +            if (SendPacketAndWaitForResponse (packet, packet_len, response, false)) +            { +                m_supports_detach_stay_stopped = eLazyBoolYes;         +            } +            else +            { +                m_supports_detach_stay_stopped = eLazyBoolNo; +            } +        } + +        if (m_supports_detach_stay_stopped == eLazyBoolNo) +        { +            error.SetErrorString("Stays stopped not supported by this target."); +            return error; +        } +        else +        { +            size_t num_sent = SendPacket ("D1", 2); +            if (num_sent == 0) +                error.SetErrorString ("Sending extended disconnect packet failed."); +        } +    } +    else +    { +        size_t num_sent = SendPacket ("D", 1); +        if (num_sent == 0) +            error.SetErrorString ("Sending disconnect packet failed."); +    } +    return error; +} + +Error +GDBRemoteCommunicationClient::GetMemoryRegionInfo (lldb::addr_t addr,  +                                                  lldb_private::MemoryRegionInfo ®ion_info) +{ +    Error error; +    region_info.Clear(); + +    if (m_supports_memory_region_info != eLazyBoolNo) +    { +        m_supports_memory_region_info = eLazyBoolYes; +        char packet[64]; +        const int packet_len = ::snprintf(packet, sizeof(packet), "qMemoryRegionInfo:%" PRIx64, (uint64_t)addr); +        assert (packet_len < (int)sizeof(packet)); +        StringExtractorGDBRemote response; +        if (SendPacketAndWaitForResponse (packet, packet_len, response, false)) +        { +            std::string name; +            std::string value; +            addr_t addr_value; +            bool success = true; +            bool saw_permissions = false; +            while (success && response.GetNameColonValue(name, value)) +            { +                if (name.compare ("start") == 0) +                { +                    addr_value = Args::StringToUInt64(value.c_str(), LLDB_INVALID_ADDRESS, 16, &success); +                    if (success) +                        region_info.GetRange().SetRangeBase(addr_value); +                } +                else if (name.compare ("size") == 0) +                { +                    addr_value = Args::StringToUInt64(value.c_str(), 0, 16, &success); +                    if (success) +                        region_info.GetRange().SetByteSize (addr_value); +                } +                else if (name.compare ("permissions") == 0 && region_info.GetRange().IsValid()) +                { +                    saw_permissions = true; +                    if (region_info.GetRange().Contains (addr)) +                    { +                        if (value.find('r') != std::string::npos) +                            region_info.SetReadable (MemoryRegionInfo::eYes); +                        else +                            region_info.SetReadable (MemoryRegionInfo::eNo); + +                        if (value.find('w') != std::string::npos) +                            region_info.SetWritable (MemoryRegionInfo::eYes); +                        else +                            region_info.SetWritable (MemoryRegionInfo::eNo); + +                        if (value.find('x') != std::string::npos) +                            region_info.SetExecutable (MemoryRegionInfo::eYes); +                        else +                            region_info.SetExecutable (MemoryRegionInfo::eNo); +                    } +                    else +                    { +                        // The reported region does not contain this address -- we're looking at an unmapped page +                        region_info.SetReadable (MemoryRegionInfo::eNo); +                        region_info.SetWritable (MemoryRegionInfo::eNo); +                        region_info.SetExecutable (MemoryRegionInfo::eNo); +                    } +                } +                else if (name.compare ("error") == 0) +                { +                    StringExtractorGDBRemote name_extractor; +                    // Swap "value" over into "name_extractor" +                    name_extractor.GetStringRef().swap(value); +                    // Now convert the HEX bytes into a string value +                    name_extractor.GetHexByteString (value); +                    error.SetErrorString(value.c_str()); +                } +            } + +            // We got a valid address range back but no permissions -- which means this is an unmapped page +            if (region_info.GetRange().IsValid() && saw_permissions == false) +            { +                region_info.SetReadable (MemoryRegionInfo::eNo); +                region_info.SetWritable (MemoryRegionInfo::eNo); +                region_info.SetExecutable (MemoryRegionInfo::eNo); +            } +        } +        else +        { +            m_supports_memory_region_info = eLazyBoolNo; +        } +    } + +    if (m_supports_memory_region_info == eLazyBoolNo) +    { +        error.SetErrorString("qMemoryRegionInfo is not supported"); +    } +    if (error.Fail()) +        region_info.Clear(); +    return error; + +} + +Error +GDBRemoteCommunicationClient::GetWatchpointSupportInfo (uint32_t &num) +{ +    Error error; + +    if (m_supports_watchpoint_support_info == eLazyBoolYes) +    { +        num = m_num_supported_hardware_watchpoints; +        return error; +    } + +    // Set num to 0 first. +    num = 0; +    if (m_supports_watchpoint_support_info != eLazyBoolNo) +    { +        char packet[64]; +        const int packet_len = ::snprintf(packet, sizeof(packet), "qWatchpointSupportInfo:"); +        assert (packet_len < (int)sizeof(packet)); +        StringExtractorGDBRemote response; +        if (SendPacketAndWaitForResponse (packet, packet_len, response, false)) +        { +            m_supports_watchpoint_support_info = eLazyBoolYes;         +            std::string name; +            std::string value; +            while (response.GetNameColonValue(name, value)) +            { +                if (name.compare ("num") == 0) +                { +                    num = Args::StringToUInt32(value.c_str(), 0, 0); +                    m_num_supported_hardware_watchpoints = num; +                } +            } +        } +        else +        { +            m_supports_watchpoint_support_info = eLazyBoolNo; +        } +    } + +    if (m_supports_watchpoint_support_info == eLazyBoolNo) +    { +        error.SetErrorString("qWatchpointSupportInfo is not supported"); +    } +    return error; + +} + +lldb_private::Error +GDBRemoteCommunicationClient::GetWatchpointSupportInfo (uint32_t &num, bool& after) +{ +    Error error(GetWatchpointSupportInfo(num)); +    if (error.Success()) +        error = GetWatchpointsTriggerAfterInstruction(after); +    return error; +} + +lldb_private::Error +GDBRemoteCommunicationClient::GetWatchpointsTriggerAfterInstruction (bool &after) +{ +    Error error; +     +    // we assume watchpoints will happen after running the relevant opcode +    // and we only want to override this behavior if we have explicitly +    // received a qHostInfo telling us otherwise +    if (m_qHostInfo_is_valid != eLazyBoolYes) +        after = true; +    else +        after = (m_watchpoints_trigger_after_instruction != eLazyBoolNo); +    return error; +} + +int +GDBRemoteCommunicationClient::SetSTDIN (char const *path) +{ +    if (path && path[0]) +    { +        StreamString packet; +        packet.PutCString("QSetSTDIN:"); +        packet.PutBytesAsRawHex8(path, strlen(path)); + +        StringExtractorGDBRemote response; +        if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) +        { +            if (response.IsOKResponse()) +                return 0; +            uint8_t error = response.GetError(); +            if (error) +                return error; +        } +    } +    return -1; +} + +int +GDBRemoteCommunicationClient::SetSTDOUT (char const *path) +{ +    if (path && path[0]) +    { +        StreamString packet; +        packet.PutCString("QSetSTDOUT:"); +        packet.PutBytesAsRawHex8(path, strlen(path)); +         +        StringExtractorGDBRemote response; +        if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) +        { +            if (response.IsOKResponse()) +                return 0; +            uint8_t error = response.GetError(); +            if (error) +                return error; +        } +    } +    return -1; +} + +int +GDBRemoteCommunicationClient::SetSTDERR (char const *path) +{ +    if (path && path[0]) +    { +        StreamString packet; +        packet.PutCString("QSetSTDERR:"); +        packet.PutBytesAsRawHex8(path, strlen(path)); +         +        StringExtractorGDBRemote response; +        if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) +        { +            if (response.IsOKResponse()) +                return 0; +            uint8_t error = response.GetError(); +            if (error) +                return error; +        } +    } +    return -1; +} + +int +GDBRemoteCommunicationClient::SetWorkingDir (char const *path) +{ +    if (path && path[0]) +    { +        StreamString packet; +        packet.PutCString("QSetWorkingDir:"); +        packet.PutBytesAsRawHex8(path, strlen(path)); +         +        StringExtractorGDBRemote response; +        if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) +        { +            if (response.IsOKResponse()) +                return 0; +            uint8_t error = response.GetError(); +            if (error) +                return error; +        } +    } +    return -1; +} + +int +GDBRemoteCommunicationClient::SetDisableASLR (bool enable) +{ +    char packet[32]; +    const int packet_len = ::snprintf (packet, sizeof (packet), "QSetDisableASLR:%i", enable ? 1 : 0); +    assert (packet_len < (int)sizeof(packet)); +    StringExtractorGDBRemote response; +    if (SendPacketAndWaitForResponse (packet, packet_len, response, false)) +    { +        if (response.IsOKResponse()) +            return 0; +        uint8_t error = response.GetError(); +        if (error) +            return error; +    } +    return -1; +} + +bool +GDBRemoteCommunicationClient::DecodeProcessInfoResponse (StringExtractorGDBRemote &response, ProcessInstanceInfo &process_info) +{ +    if (response.IsNormalResponse()) +    { +        std::string name; +        std::string value; +        StringExtractor extractor; +         +        while (response.GetNameColonValue(name, value)) +        { +            if (name.compare("pid") == 0) +            { +                process_info.SetProcessID (Args::StringToUInt32 (value.c_str(), LLDB_INVALID_PROCESS_ID, 0)); +            } +            else if (name.compare("ppid") == 0) +            { +                process_info.SetParentProcessID (Args::StringToUInt32 (value.c_str(), LLDB_INVALID_PROCESS_ID, 0)); +            } +            else if (name.compare("uid") == 0) +            { +                process_info.SetUserID (Args::StringToUInt32 (value.c_str(), UINT32_MAX, 0)); +            } +            else if (name.compare("euid") == 0) +            { +                process_info.SetEffectiveUserID (Args::StringToUInt32 (value.c_str(), UINT32_MAX, 0)); +            } +            else if (name.compare("gid") == 0) +            { +                process_info.SetGroupID (Args::StringToUInt32 (value.c_str(), UINT32_MAX, 0)); +            } +            else if (name.compare("egid") == 0) +            { +                process_info.SetEffectiveGroupID (Args::StringToUInt32 (value.c_str(), UINT32_MAX, 0)); +            } +            else if (name.compare("triple") == 0) +            { +                // The triple comes as ASCII hex bytes since it contains '-' chars +                extractor.GetStringRef().swap(value); +                extractor.SetFilePos(0); +                extractor.GetHexByteString (value); +                process_info.GetArchitecture ().SetTriple (value.c_str()); +            } +            else if (name.compare("name") == 0) +            { +                StringExtractor extractor; +                // The process name from ASCII hex bytes since we can't  +                // control the characters in a process name +                extractor.GetStringRef().swap(value); +                extractor.SetFilePos(0); +                extractor.GetHexByteString (value); +                process_info.GetExecutableFile().SetFile (value.c_str(), false); +            } +        } +         +        if (process_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) +            return true; +    } +    return false; +} + +bool +GDBRemoteCommunicationClient::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info) +{ +    process_info.Clear(); +     +    if (m_supports_qProcessInfoPID) +    { +        char packet[32]; +        const int packet_len = ::snprintf (packet, sizeof (packet), "qProcessInfoPID:%" PRIu64, pid); +        assert (packet_len < (int)sizeof(packet)); +        StringExtractorGDBRemote response; +        if (SendPacketAndWaitForResponse (packet, packet_len, response, false)) +        { +            return DecodeProcessInfoResponse (response, process_info); +        } +        else +        { +            m_supports_qProcessInfoPID = false; +            return false; +        } +    } +    return false; +} + +bool +GDBRemoteCommunicationClient::GetCurrentProcessInfo () +{ +    if (m_qProcessInfo_is_valid == eLazyBoolYes) +        return true; +    if (m_qProcessInfo_is_valid == eLazyBoolNo) +        return false; + +    GetHostInfo (); + +    StringExtractorGDBRemote response; +    if (SendPacketAndWaitForResponse ("qProcessInfo", response, false)) +    { +        if (response.IsNormalResponse()) +        { +            std::string name; +            std::string value; +            uint32_t cpu = LLDB_INVALID_CPUTYPE; +            uint32_t sub = 0; +            std::string arch_name; +            std::string os_name; +            std::string vendor_name; +            std::string triple; +            uint32_t pointer_byte_size = 0; +            StringExtractor extractor; +            ByteOrder byte_order = eByteOrderInvalid; +            uint32_t num_keys_decoded = 0; +            while (response.GetNameColonValue(name, value)) +            { +                if (name.compare("cputype") == 0) +                { +                    cpu = Args::StringToUInt32 (value.c_str(), LLDB_INVALID_CPUTYPE, 16); +                    if (cpu != LLDB_INVALID_CPUTYPE) +                        ++num_keys_decoded; +                } +                else if (name.compare("cpusubtype") == 0) +                { +                    sub = Args::StringToUInt32 (value.c_str(), 0, 16); +                    if (sub != 0) +                        ++num_keys_decoded; +                } +                else if (name.compare("ostype") == 0) +                { +                    os_name.swap (value); +                    ++num_keys_decoded; +                } +                else if (name.compare("vendor") == 0) +                { +                    vendor_name.swap(value); +                    ++num_keys_decoded; +                } +                else if (name.compare("endian") == 0) +                { +                    ++num_keys_decoded; +                    if (value.compare("little") == 0) +                        byte_order = eByteOrderLittle; +                    else if (value.compare("big") == 0) +                        byte_order = eByteOrderBig; +                    else if (value.compare("pdp") == 0) +                        byte_order = eByteOrderPDP; +                    else +                        --num_keys_decoded; +                } +                else if (name.compare("ptrsize") == 0) +                { +                    pointer_byte_size = Args::StringToUInt32 (value.c_str(), 0, 16); +                    if (pointer_byte_size != 0) +                        ++num_keys_decoded; +                } +            } +            if (num_keys_decoded > 0) +                m_qProcessInfo_is_valid = eLazyBoolYes; +            if (cpu != LLDB_INVALID_CPUTYPE && !os_name.empty() && !vendor_name.empty()) +            { +                m_process_arch.SetArchitecture (eArchTypeMachO, cpu, sub); +                if (pointer_byte_size) +                { +                    assert (pointer_byte_size == m_process_arch.GetAddressByteSize()); +                } +                m_host_arch.GetTriple().setVendorName (llvm::StringRef (vendor_name)); +                m_host_arch.GetTriple().setOSName (llvm::StringRef (os_name)); +                return true; +            } +        } +    } +    else +    { +        m_qProcessInfo_is_valid = eLazyBoolNo; +    } + +    return false; +} + + +uint32_t +GDBRemoteCommunicationClient::FindProcesses (const ProcessInstanceInfoMatch &match_info, +                                             ProcessInstanceInfoList &process_infos) +{ +    process_infos.Clear(); +     +    if (m_supports_qfProcessInfo) +    { +        StreamString packet; +        packet.PutCString ("qfProcessInfo"); +        if (!match_info.MatchAllProcesses()) +        { +            packet.PutChar (':'); +            const char *name = match_info.GetProcessInfo().GetName(); +            bool has_name_match = false; +            if (name && name[0]) +            { +                has_name_match = true; +                NameMatchType name_match_type = match_info.GetNameMatchType(); +                switch (name_match_type) +                { +                case eNameMatchIgnore:   +                    has_name_match = false; +                    break; + +                case eNameMatchEquals:   +                    packet.PutCString ("name_match:equals;");  +                    break; + +                case eNameMatchContains: +                    packet.PutCString ("name_match:contains;");  +                    break; +                 +                case eNameMatchStartsWith: +                    packet.PutCString ("name_match:starts_with;");  +                    break; +                 +                case eNameMatchEndsWith: +                    packet.PutCString ("name_match:ends_with;");  +                    break; + +                case eNameMatchRegularExpression: +                    packet.PutCString ("name_match:regex;");  +                    break; +                } +                if (has_name_match) +                { +                    packet.PutCString ("name:"); +                    packet.PutBytesAsRawHex8(name, ::strlen(name)); +                    packet.PutChar (';'); +                } +            } +             +            if (match_info.GetProcessInfo().ProcessIDIsValid()) +                packet.Printf("pid:%" PRIu64 ";",match_info.GetProcessInfo().GetProcessID()); +            if (match_info.GetProcessInfo().ParentProcessIDIsValid()) +                packet.Printf("parent_pid:%" PRIu64 ";",match_info.GetProcessInfo().GetParentProcessID()); +            if (match_info.GetProcessInfo().UserIDIsValid()) +                packet.Printf("uid:%u;",match_info.GetProcessInfo().GetUserID()); +            if (match_info.GetProcessInfo().GroupIDIsValid()) +                packet.Printf("gid:%u;",match_info.GetProcessInfo().GetGroupID()); +            if (match_info.GetProcessInfo().EffectiveUserIDIsValid()) +                packet.Printf("euid:%u;",match_info.GetProcessInfo().GetEffectiveUserID()); +            if (match_info.GetProcessInfo().EffectiveGroupIDIsValid()) +                packet.Printf("egid:%u;",match_info.GetProcessInfo().GetEffectiveGroupID()); +            if (match_info.GetProcessInfo().EffectiveGroupIDIsValid()) +                packet.Printf("all_users:%u;",match_info.GetMatchAllUsers() ? 1 : 0); +            if (match_info.GetProcessInfo().GetArchitecture().IsValid()) +            { +                const ArchSpec &match_arch = match_info.GetProcessInfo().GetArchitecture(); +                const llvm::Triple &triple = match_arch.GetTriple(); +                packet.PutCString("triple:"); +                packet.PutCStringAsRawHex8(triple.getTriple().c_str()); +                packet.PutChar (';'); +            } +        } +        StringExtractorGDBRemote response; +        if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) +        { +            do +            { +                ProcessInstanceInfo process_info; +                if (!DecodeProcessInfoResponse (response, process_info)) +                    break; +                process_infos.Append(process_info); +                response.GetStringRef().clear(); +                response.SetFilePos(0); +            } while (SendPacketAndWaitForResponse ("qsProcessInfo", strlen ("qsProcessInfo"), response, false)); +        } +        else +        { +            m_supports_qfProcessInfo = false; +            return 0; +        } +    } +    return process_infos.GetSize(); +     +} + +bool +GDBRemoteCommunicationClient::GetUserName (uint32_t uid, std::string &name) +{ +    if (m_supports_qUserName) +    { +        char packet[32]; +        const int packet_len = ::snprintf (packet, sizeof (packet), "qUserName:%i", uid); +        assert (packet_len < (int)sizeof(packet)); +        StringExtractorGDBRemote response; +        if (SendPacketAndWaitForResponse (packet, packet_len, response, false)) +        { +            if (response.IsNormalResponse()) +            { +                // Make sure we parsed the right number of characters. The response is +                // the hex encoded user name and should make up the entire packet. +                // If there are any non-hex ASCII bytes, the length won't match below.. +                if (response.GetHexByteString (name) * 2 == response.GetStringRef().size()) +                    return true; +            } +        } +        else +        { +            m_supports_qUserName = false; +            return false; +        }         +    } +    return false; + +} + +bool +GDBRemoteCommunicationClient::GetGroupName (uint32_t gid, std::string &name) +{ +    if (m_supports_qGroupName) +    { +        char packet[32]; +        const int packet_len = ::snprintf (packet, sizeof (packet), "qGroupName:%i", gid); +        assert (packet_len < (int)sizeof(packet)); +        StringExtractorGDBRemote response; +        if (SendPacketAndWaitForResponse (packet, packet_len, response, false)) +        { +            if (response.IsNormalResponse()) +            { +                // Make sure we parsed the right number of characters. The response is +                // the hex encoded group name and should make up the entire packet. +                // If there are any non-hex ASCII bytes, the length won't match below.. +                if (response.GetHexByteString (name) * 2 == response.GetStringRef().size()) +                    return true; +            } +        } +        else +        { +            m_supports_qGroupName = false; +            return false; +        } +    } +    return false; +} + +void +GDBRemoteCommunicationClient::TestPacketSpeed (const uint32_t num_packets) +{ +    uint32_t i; +    TimeValue start_time, end_time; +    uint64_t total_time_nsec; +    float packets_per_second; +    if (SendSpeedTestPacket (0, 0)) +    { +        for (uint32_t send_size = 0; send_size <= 1024; send_size *= 2) +        { +            for (uint32_t recv_size = 0; recv_size <= 1024; recv_size *= 2) +            { +                start_time = TimeValue::Now(); +                for (i=0; i<num_packets; ++i) +                { +                    SendSpeedTestPacket (send_size, recv_size); +                } +                end_time = TimeValue::Now(); +                total_time_nsec = end_time.GetAsNanoSecondsSinceJan1_1970() - start_time.GetAsNanoSecondsSinceJan1_1970(); +                packets_per_second = (((float)num_packets)/(float)total_time_nsec) * (float)TimeValue::NanoSecPerSec; +                printf ("%u qSpeedTest(send=%-5u, recv=%-5u) in %" PRIu64 ".%9.9" PRIu64 " sec for %f packets/sec.\n", +                        num_packets,  +                        send_size, +                        recv_size, +                        total_time_nsec / TimeValue::NanoSecPerSec, +                        total_time_nsec % TimeValue::NanoSecPerSec,  +                        packets_per_second); +                if (recv_size == 0) +                    recv_size = 32; +            } +            if (send_size == 0) +                send_size = 32; +        } +    } +    else +    { +        start_time = TimeValue::Now(); +        for (i=0; i<num_packets; ++i) +        { +            GetCurrentProcessID (); +        } +        end_time = TimeValue::Now(); +        total_time_nsec = end_time.GetAsNanoSecondsSinceJan1_1970() - start_time.GetAsNanoSecondsSinceJan1_1970(); +        packets_per_second = (((float)num_packets)/(float)total_time_nsec) * (float)TimeValue::NanoSecPerSec; +        printf ("%u 'qC' packets packets in 0x%" PRIu64 "%9.9" PRIu64 " sec for %f packets/sec.\n", +                num_packets,  +                total_time_nsec / TimeValue::NanoSecPerSec,  +                total_time_nsec % TimeValue::NanoSecPerSec,  +                packets_per_second); +    } +} + +bool +GDBRemoteCommunicationClient::SendSpeedTestPacket (uint32_t send_size, uint32_t recv_size) +{ +    StreamString packet; +    packet.Printf ("qSpeedTest:response_size:%i;data:", recv_size); +    uint32_t bytes_left = send_size; +    while (bytes_left > 0) +    { +        if (bytes_left >= 26) +        { +            packet.PutCString("abcdefghijklmnopqrstuvwxyz"); +            bytes_left -= 26; +        } +        else +        { +            packet.Printf ("%*.*s;", bytes_left, bytes_left, "abcdefghijklmnopqrstuvwxyz"); +            bytes_left = 0; +        } +    } + +    StringExtractorGDBRemote response; +    return SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) > 0; +    return false; +} + +uint16_t +GDBRemoteCommunicationClient::LaunchGDBserverAndGetPort () +{ +    StringExtractorGDBRemote response; +    if (SendPacketAndWaitForResponse("qLaunchGDBServer", strlen("qLaunchGDBServer"), response, false)) +    { +        std::string name; +        std::string value; +        uint16_t port = 0; +        //lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; +        while (response.GetNameColonValue(name, value)) +        { +            if (name.size() == 4 && name.compare("port") == 0) +                port = Args::StringToUInt32(value.c_str(), 0, 0); +//            if (name.size() == 3 && name.compare("pid") == 0) +//                pid = Args::StringToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0); +        } +        return port; +    } +    return 0; +} + +bool +GDBRemoteCommunicationClient::SetCurrentThread (uint64_t tid) +{ +    if (m_curr_tid == tid) +        return true; + +    char packet[32]; +    int packet_len; +    if (tid == UINT64_MAX) +        packet_len = ::snprintf (packet, sizeof(packet), "Hg-1"); +    else +        packet_len = ::snprintf (packet, sizeof(packet), "Hg%" PRIx64, tid); +    assert (packet_len + 1 < (int)sizeof(packet)); +    StringExtractorGDBRemote response; +    if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) +    { +        if (response.IsOKResponse()) +        { +            m_curr_tid = tid; +            return true; +        } +    } +    return false; +} + +bool +GDBRemoteCommunicationClient::SetCurrentThreadForRun (uint64_t tid) +{ +    if (m_curr_tid_run == tid) +        return true; + +    char packet[32]; +    int packet_len; +    if (tid == UINT64_MAX) +        packet_len = ::snprintf (packet, sizeof(packet), "Hc-1"); +    else +        packet_len = ::snprintf (packet, sizeof(packet), "Hc%" PRIx64, tid); + +    assert (packet_len + 1 < (int)sizeof(packet)); +    StringExtractorGDBRemote response; +    if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) +    { +        if (response.IsOKResponse()) +        { +            m_curr_tid_run = tid; +            return true; +        } +    } +    return false; +} + +bool +GDBRemoteCommunicationClient::GetStopReply (StringExtractorGDBRemote &response) +{ +    if (SendPacketAndWaitForResponse("?", 1, response, false)) +        return response.IsNormalResponse(); +    return false; +} + +bool +GDBRemoteCommunicationClient::GetThreadStopInfo (lldb::tid_t tid, StringExtractorGDBRemote &response) +{ +    if (m_supports_qThreadStopInfo) +    { +        char packet[256]; +        int packet_len = ::snprintf(packet, sizeof(packet), "qThreadStopInfo%" PRIx64, tid); +        assert (packet_len < (int)sizeof(packet)); +        if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) +        { +            if (response.IsNormalResponse()) +                return true; +            else +                return false; +        } +        else +        { +            m_supports_qThreadStopInfo = false; +        } +    } +//    if (SetCurrentThread (tid)) +//        return GetStopReply (response); +    return false; +} + + +uint8_t +GDBRemoteCommunicationClient::SendGDBStoppointTypePacket (GDBStoppointType type, bool insert,  addr_t addr, uint32_t length) +{ +    switch (type) +    { +    case eBreakpointSoftware:   if (!m_supports_z0) return UINT8_MAX; break; +    case eBreakpointHardware:   if (!m_supports_z1) return UINT8_MAX; break; +    case eWatchpointWrite:      if (!m_supports_z2) return UINT8_MAX; break; +    case eWatchpointRead:       if (!m_supports_z3) return UINT8_MAX; break; +    case eWatchpointReadWrite:  if (!m_supports_z4) return UINT8_MAX; break; +    } + +    char packet[64]; +    const int packet_len = ::snprintf (packet,  +                                       sizeof(packet),  +                                       "%c%i,%" PRIx64 ",%x", +                                       insert ? 'Z' : 'z',  +                                       type,  +                                       addr,  +                                       length); + +    assert (packet_len + 1 < (int)sizeof(packet)); +    StringExtractorGDBRemote response; +    if (SendPacketAndWaitForResponse(packet, packet_len, response, true)) +    { +        if (response.IsOKResponse()) +            return 0; +        else if (response.IsErrorResponse()) +            return response.GetError(); +    } +    else +    { +        switch (type) +        { +            case eBreakpointSoftware:   m_supports_z0 = false; break; +            case eBreakpointHardware:   m_supports_z1 = false; break; +            case eWatchpointWrite:      m_supports_z2 = false; break; +            case eWatchpointRead:       m_supports_z3 = false; break; +            case eWatchpointReadWrite:  m_supports_z4 = false; break; +        } +    } + +    return UINT8_MAX; +} + +size_t +GDBRemoteCommunicationClient::GetCurrentThreadIDs (std::vector<lldb::tid_t> &thread_ids,  +                                                   bool &sequence_mutex_unavailable) +{ +    Mutex::Locker locker; +    thread_ids.clear(); +     +    if (GetSequenceMutex (locker, "ProcessGDBRemote::UpdateThreadList() failed due to not getting the sequence mutex")) +    { +        sequence_mutex_unavailable = false; +        StringExtractorGDBRemote response; +         +        for (SendPacketNoLock ("qfThreadInfo", strlen("qfThreadInfo")) && WaitForPacketWithTimeoutMicroSecondsNoLock (response, GetPacketTimeoutInMicroSeconds ()); +             response.IsNormalResponse(); +             SendPacketNoLock ("qsThreadInfo", strlen("qsThreadInfo")) && WaitForPacketWithTimeoutMicroSecondsNoLock (response, GetPacketTimeoutInMicroSeconds ())) +        { +            char ch = response.GetChar(); +            if (ch == 'l') +                break; +            if (ch == 'm') +            { +                do +                { +                    tid_t tid = response.GetHexMaxU64(false, LLDB_INVALID_THREAD_ID); +                     +                    if (tid != LLDB_INVALID_THREAD_ID) +                    { +                        thread_ids.push_back (tid); +                    } +                    ch = response.GetChar();    // Skip the command separator +                } while (ch == ',');            // Make sure we got a comma separator +            } +        } +    } +    else +    { +#if defined (LLDB_CONFIGURATION_DEBUG) +        // assert(!"ProcessGDBRemote::UpdateThreadList() failed due to not getting the sequence mutex"); +#else +        Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_PROCESS | GDBR_LOG_PACKETS)); +        if (log) +            log->Printf("error: failed to get packet sequence mutex, not sending packet 'qfThreadInfo'"); +#endif +        sequence_mutex_unavailable = true; +    } +    return thread_ids.size(); +} + +lldb::addr_t +GDBRemoteCommunicationClient::GetShlibInfoAddr() +{ +    if (!IsRunning()) +    { +        StringExtractorGDBRemote response; +        if (SendPacketAndWaitForResponse("qShlibInfoAddr", ::strlen ("qShlibInfoAddr"), response, false)) +        { +            if (response.IsNormalResponse()) +                return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS); +        } +    } +    return LLDB_INVALID_ADDRESS; +} + | 
