diff options
| author | Ed Maste <emaste@FreeBSD.org> | 2015-07-03 16:57:06 +0000 | 
|---|---|---|
| committer | Ed Maste <emaste@FreeBSD.org> | 2015-07-03 16:57:06 +0000 | 
| commit | 5e95aa85bb660d45e9905ef1d7180b2678280660 (patch) | |
| tree | 3c2e41c3be19b7fc7666ed45a5f91ec3b6e35f2a /source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp | |
| parent | 12bd4897ff0678fa663e09d78ebc22dd255ceb86 (diff) | |
Notes
Diffstat (limited to 'source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp')
| -rw-r--r-- | source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp | 1095 | 
1 files changed, 896 insertions, 199 deletions
| diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index 0f99688fc823..ae0a2f5e66c5 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -11,16 +11,19 @@  #include "GDBRemoteCommunicationClient.h"  // C Includes +#include <math.h>  #include <sys/stat.h>  // C++ Includes  #include <sstream> +#include <numeric>  // Other libraries and framework includes  #include "llvm/ADT/STLExtras.h"  #include "llvm/ADT/Triple.h"  #include "lldb/Interpreter/Args.h"  #include "lldb/Core/Log.h" +#include "lldb/Core/ModuleSpec.h"  #include "lldb/Core/State.h"  #include "lldb/Core/StreamGDBRemote.h"  #include "lldb/Core/StreamString.h" @@ -30,7 +33,10 @@  #include "lldb/Host/HostInfo.h"  #include "lldb/Host/StringConvert.h"  #include "lldb/Host/TimeValue.h" +#include "lldb/Symbol/Symbol.h"  #include "lldb/Target/Target.h" +#include "lldb/Target/MemoryRegionInfo.h" +#include "lldb/Target/UnixSignals.h"  // Project includes  #include "Utility/StringExtractorGDBRemote.h" @@ -38,18 +44,19 @@  #include "ProcessGDBRemoteLog.h"  #include "lldb/Host/Config.h" +#if defined (HAVE_LIBCOMPRESSION) +#include <compression.h> +#endif +  using namespace lldb;  using namespace lldb_private; - -#if defined(LLDB_DISABLE_POSIX) && !defined(SIGSTOP) -#define SIGSTOP 17 -#endif +using namespace lldb_private::process_gdb_remote;  //----------------------------------------------------------------------  // GDBRemoteCommunicationClient constructor  //---------------------------------------------------------------------- -GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) : -    GDBRemoteCommunication("gdb-remote.client", "gdb-remote.client.rx_packet", is_platform), +GDBRemoteCommunicationClient::GDBRemoteCommunicationClient() : +    GDBRemoteCommunication("gdb-remote.client", "gdb-remote.client.rx_packet"),      m_supports_not_sending_acks (eLazyBoolCalculate),      m_supports_thread_suffix (eLazyBoolCalculate),      m_supports_threads_in_stop_reply (eLazyBoolCalculate), @@ -77,6 +84,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) :      m_supports_qXfer_auxv_read (eLazyBoolCalculate),      m_supports_qXfer_libraries_read (eLazyBoolCalculate),      m_supports_qXfer_libraries_svr4_read (eLazyBoolCalculate), +    m_supports_qXfer_features_read (eLazyBoolCalculate),      m_supports_augmented_libraries_svr4_read (eLazyBoolCalculate),      m_supports_jThreadExtendedInfo (eLazyBoolCalculate),      m_supports_qProcessInfoPID (true), @@ -91,6 +99,8 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) :      m_supports_z4 (true),      m_supports_QEnvironment (true),      m_supports_QEnvironmentHexEncoded (true), +    m_supports_qSymbol (true), +    m_supports_jThreadsInfo (true),      m_curr_pid (LLDB_INVALID_PROCESS_ID),      m_curr_tid (LLDB_INVALID_THREAD_ID),      m_curr_tid_run (LLDB_INVALID_THREAD_ID), @@ -130,7 +140,7 @@ GDBRemoteCommunicationClient::~GDBRemoteCommunicationClient()  bool  GDBRemoteCommunicationClient::HandshakeWithServer (Error *error_ptr)  { -    ResetDiscoverableSettings(); +    ResetDiscoverableSettings(false);      // Start the read thread after we send the handshake ack since if we      // fail to send the handshake ack, there is no reason to continue... @@ -142,7 +152,7 @@ GDBRemoteCommunicationClient::HandshakeWithServer (Error *error_ptr)          PacketResult packet_result = PacketResult::Success;          const uint32_t timeout_usec = 10 * 1000; // Wait for 10 ms for a response          while (packet_result == PacketResult::Success) -            packet_result = WaitForPacketWithTimeoutMicroSecondsNoLock (response, timeout_usec); +            packet_result = ReadPacket (response, timeout_usec, false);          // The return value from QueryNoAckModeSupported() is true if the packet          // was sent and _any_ response (including UNIMPLEMENTED) was received), @@ -150,11 +160,6 @@ GDBRemoteCommunicationClient::HandshakeWithServer (Error *error_ptr)          // a live connection to a remote GDB server...          if (QueryNoAckModeSupported())          { -#if 0 -            // Set above line to "#if 1" to test packet speed if remote GDB server -            // supports the qSpeedTest packet... -            TestPacketSpeed(10000); -#endif              return true;          }          else @@ -172,13 +177,24 @@ GDBRemoteCommunicationClient::HandshakeWithServer (Error *error_ptr)  }  bool +GDBRemoteCommunicationClient::GetEchoSupported () +{ +    if (m_supports_qEcho == eLazyBoolCalculate) +    { +        GetRemoteQSupported(); +    } +    return m_supports_qEcho == eLazyBoolYes; +} + + +bool  GDBRemoteCommunicationClient::GetAugmentedLibrariesSVR4ReadSupported ()  {      if (m_supports_augmented_libraries_svr4_read == eLazyBoolCalculate)      {          GetRemoteQSupported();      } -    return (m_supports_augmented_libraries_svr4_read == eLazyBoolYes); +    return m_supports_augmented_libraries_svr4_read == eLazyBoolYes;  }  bool @@ -188,7 +204,7 @@ GDBRemoteCommunicationClient::GetQXferLibrariesSVR4ReadSupported ()      {          GetRemoteQSupported();      } -    return (m_supports_qXfer_libraries_svr4_read == eLazyBoolYes); +    return m_supports_qXfer_libraries_svr4_read == eLazyBoolYes;  }  bool @@ -198,7 +214,7 @@ GDBRemoteCommunicationClient::GetQXferLibrariesReadSupported ()      {          GetRemoteQSupported();      } -    return (m_supports_qXfer_libraries_read == eLazyBoolYes); +    return m_supports_qXfer_libraries_read == eLazyBoolYes;  }  bool @@ -208,7 +224,17 @@ GDBRemoteCommunicationClient::GetQXferAuxvReadSupported ()      {          GetRemoteQSupported();      } -    return (m_supports_qXfer_auxv_read == eLazyBoolYes); +    return m_supports_qXfer_auxv_read == eLazyBoolYes; +} + +bool +GDBRemoteCommunicationClient::GetQXferFeaturesReadSupported () +{ +    if (m_supports_qXfer_features_read == eLazyBoolCalculate) +    { +        GetRemoteQSupported(); +    } +    return m_supports_qXfer_features_read == eLazyBoolYes;  }  uint64_t @@ -234,13 +260,10 @@ GDBRemoteCommunicationClient::QueryNoAckModeSupported ()          const uint32_t minimum_timeout = 6;          uint32_t old_timeout = GetPacketTimeoutInMicroSeconds() / lldb_private::TimeValue::MicroSecPerSec; -        SetPacketTimeout (std::max (old_timeout, minimum_timeout)); +        GDBRemoteCommunication::ScopedTimeout timeout (*this, std::max (old_timeout, minimum_timeout));          StringExtractorGDBRemote response; -        PacketResult packet_send_result = SendPacketAndWaitForResponse("QStartNoAckMode", response, false); -        SetPacketTimeout (old_timeout); - -        if (packet_send_result == PacketResult::Success) +        if (SendPacketAndWaitForResponse("QStartNoAckMode", response, false) == PacketResult::Success)          {              if (response.IsOKResponse())              { @@ -311,58 +334,64 @@ GDBRemoteCommunicationClient::GetSyncThreadStateSupported ()  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_supports_p = eLazyBoolCalculate; -    m_supports_x = eLazyBoolCalculate; -    m_supports_QSaveRegisterState = eLazyBoolCalculate; -    m_qHostInfo_is_valid = eLazyBoolCalculate; -    m_curr_pid_is_valid = eLazyBoolCalculate; +GDBRemoteCommunicationClient::ResetDiscoverableSettings (bool did_exec) +{ +    if (did_exec == false) +    { +        // Hard reset everything, this is when we first connect to a GDB server +        m_supports_not_sending_acks = eLazyBoolCalculate; +        m_supports_thread_suffix = eLazyBoolCalculate; +        m_supports_threads_in_stop_reply = eLazyBoolCalculate; +        m_supports_vCont_c = eLazyBoolCalculate; +        m_supports_vCont_C = eLazyBoolCalculate; +        m_supports_vCont_s = eLazyBoolCalculate; +        m_supports_vCont_S = eLazyBoolCalculate; +        m_supports_p = eLazyBoolCalculate; +        m_supports_x = eLazyBoolCalculate; +        m_supports_QSaveRegisterState = eLazyBoolCalculate; +        m_qHostInfo_is_valid = eLazyBoolCalculate; +        m_curr_pid_is_valid = eLazyBoolCalculate; +        m_qGDBServerVersion_is_valid = eLazyBoolCalculate; +        m_supports_alloc_dealloc_memory = eLazyBoolCalculate; +        m_supports_memory_region_info = eLazyBoolCalculate; +        m_prepare_for_reg_writing_reply = eLazyBoolCalculate; +        m_attach_or_wait_reply = eLazyBoolCalculate; +        m_avoid_g_packets = eLazyBoolCalculate; +        m_supports_qXfer_auxv_read = eLazyBoolCalculate; +        m_supports_qXfer_libraries_read = eLazyBoolCalculate; +        m_supports_qXfer_libraries_svr4_read = eLazyBoolCalculate; +        m_supports_qXfer_features_read = eLazyBoolCalculate; +        m_supports_augmented_libraries_svr4_read = eLazyBoolCalculate; +        m_supports_qProcessInfoPID = true; +        m_supports_qfProcessInfo = true; +        m_supports_qUserName = true; +        m_supports_qGroupName = true; +        m_supports_qThreadStopInfo = true; +        m_supports_z0 = true; +        m_supports_z1 = true; +        m_supports_z2 = true; +        m_supports_z3 = true; +        m_supports_z4 = true; +        m_supports_QEnvironment = true; +        m_supports_QEnvironmentHexEncoded = true; +        m_supports_qSymbol = true; +        m_host_arch.Clear(); +        m_os_version_major = UINT32_MAX; +        m_os_version_minor = UINT32_MAX; +        m_os_version_update = UINT32_MAX; +        m_os_build.clear(); +        m_os_kernel.clear(); +        m_hostname.clear(); +        m_gdb_server_name.clear(); +        m_gdb_server_version = UINT32_MAX; +        m_default_packet_timeout = 0; +        m_max_packet_size = 0; +    } + +    // These flags should be reset when we first connect to a GDB server +    // and when our inferior process execs      m_qProcessInfo_is_valid = eLazyBoolCalculate; -    m_qGDBServerVersion_is_valid = eLazyBoolCalculate; -    m_supports_alloc_dealloc_memory = eLazyBoolCalculate; -    m_supports_memory_region_info = eLazyBoolCalculate; -    m_prepare_for_reg_writing_reply = eLazyBoolCalculate; -    m_attach_or_wait_reply = eLazyBoolCalculate; -    m_avoid_g_packets = eLazyBoolCalculate; -    m_supports_qXfer_auxv_read = eLazyBoolCalculate; -    m_supports_qXfer_libraries_read = eLazyBoolCalculate; -    m_supports_qXfer_libraries_svr4_read = eLazyBoolCalculate; -    m_supports_augmented_libraries_svr4_read = eLazyBoolCalculate; - -    m_supports_qProcessInfoPID = true; -    m_supports_qfProcessInfo = true; -    m_supports_qUserName = true; -    m_supports_qGroupName = true; -    m_supports_qThreadStopInfo = true; -    m_supports_z0 = true; -    m_supports_z1 = true; -    m_supports_z2 = true; -    m_supports_z3 = true; -    m_supports_z4 = true; -    m_supports_QEnvironment = true; -    m_supports_QEnvironmentHexEncoded = true; -     -    m_host_arch.Clear();      m_process_arch.Clear(); -    m_os_version_major = UINT32_MAX; -    m_os_version_minor = UINT32_MAX; -    m_os_version_update = UINT32_MAX; -    m_os_build.clear(); -    m_os_kernel.clear(); -    m_hostname.clear(); -    m_gdb_server_name.clear(); -    m_gdb_server_version = UINT32_MAX; -    m_default_packet_timeout = 0; - -    m_max_packet_size = 0;  }  void @@ -373,10 +402,21 @@ GDBRemoteCommunicationClient::GetRemoteQSupported ()      m_supports_qXfer_libraries_read = eLazyBoolNo;      m_supports_qXfer_libraries_svr4_read = eLazyBoolNo;      m_supports_augmented_libraries_svr4_read = eLazyBoolNo; +    m_supports_qXfer_features_read = eLazyBoolNo;      m_max_packet_size = UINT64_MAX;  // It's supposed to always be there, but if not, we assume no limit +    // build the qSupported packet +    std::vector<std::string> features = {"xmlRegisters=i386,arm,mips"}; +    StreamString packet; +    packet.PutCString( "qSupported" ); +    for ( uint32_t i = 0; i < features.size( ); ++i ) +    { +        packet.PutCString( i==0 ? ":" : ";"); +        packet.PutCString( features[i].c_str( ) ); +    } +      StringExtractorGDBRemote response; -    if (SendPacketAndWaitForResponse("qSupported", +    if (SendPacketAndWaitForResponse(packet.GetData(),                                       response,                                       /*send_async=*/false) == PacketResult::Success)      { @@ -392,6 +432,66 @@ GDBRemoteCommunicationClient::GetRemoteQSupported ()          }          if (::strstr (response_cstr, "qXfer:libraries:read+"))              m_supports_qXfer_libraries_read = eLazyBoolYes; +        if (::strstr (response_cstr, "qXfer:features:read+")) +            m_supports_qXfer_features_read = eLazyBoolYes; + + +        // Look for a list of compressions in the features list e.g. +        // qXfer:features:read+;PacketSize=20000;qEcho+;SupportedCompressions=zlib-deflate,lzma +        const char *features_list = ::strstr (response_cstr, "qXfer:features:"); +        if (features_list) +        { +            const char *compressions = ::strstr (features_list, "SupportedCompressions="); +            if (compressions) +            { +                std::vector<std::string> supported_compressions; +                compressions += sizeof ("SupportedCompressions=") - 1; +                const char *end_of_compressions = strchr (compressions, ';'); +                if (end_of_compressions == NULL) +                { +                    end_of_compressions = strchr (compressions, '\0'); +                } +                const char *current_compression = compressions; +                while (current_compression < end_of_compressions) +                { +                    const char *next_compression_name = strchr (current_compression, ','); +                    const char *end_of_this_word = next_compression_name; +                    if (next_compression_name == NULL || end_of_compressions < next_compression_name) +                    { +                        end_of_this_word = end_of_compressions; +                    } + +                    if (end_of_this_word) +                    { +                        if (end_of_this_word == current_compression) +                        { +                            current_compression++; +                        } +                        else +                        { +                            std::string this_compression (current_compression, end_of_this_word - current_compression); +                            supported_compressions.push_back (this_compression); +                            current_compression = end_of_this_word + 1; +                        } +                    } +                    else +                    { +                        supported_compressions.push_back (current_compression); +                        current_compression = end_of_compressions; +                    } +                } + +                if (supported_compressions.size() > 0) +                { +                    MaybeEnableCompression (supported_compressions); +                } +            } +        } + +        if (::strstr (response_cstr, "qEcho")) +            m_supports_qEcho = eLazyBoolYes; +        else +            m_supports_qEcho = eLazyBoolNo;          const char *packet_size_str = ::strstr (response_cstr, "PacketSize=");          if (packet_size_str) @@ -509,6 +609,32 @@ GDBRemoteCommunicationClient::GetpPacketSupported (lldb::tid_t tid)      return m_supports_p;  } +StructuredData::ObjectSP +GDBRemoteCommunicationClient::GetThreadsInfo() +{ +    // Get information on all threads at one using the "jThreadsInfo" packet +    StructuredData::ObjectSP object_sp; + +    if (m_supports_jThreadsInfo) +    { +        StringExtractorGDBRemote response; +        m_supports_jThreadExtendedInfo = eLazyBoolNo; +        if (SendPacketAndWaitForResponse("jThreadsInfo", response, false) == PacketResult::Success) +        { +            if (response.IsUnsupportedResponse()) +            { +                m_supports_jThreadsInfo = false; +            } +            else if (!response.Empty()) +            { +                object_sp = StructuredData::ParseJSON (response.GetStringRef()); +            } +        } +    } +    return object_sp; +} + +  bool  GDBRemoteCommunicationClient::GetThreadExtendedInfoSupported ()  { @@ -619,7 +745,7 @@ GDBRemoteCommunicationClient::SendPacketAndWaitForResponseNoLock (const char *pa  {      PacketResult packet_result = SendPacketNoLock (payload, payload_length);      if (packet_result == PacketResult::Success) -        packet_result = WaitForPacketWithTimeoutMicroSecondsNoLock (response, GetPacketTimeoutInMicroSeconds ()); +        packet_result = ReadPacket (response, GetPacketTimeoutInMicroSeconds (), true);      return packet_result;  } @@ -635,6 +761,12 @@ GDBRemoteCommunicationClient::SendPacketAndWaitForResponse      PacketResult packet_result = PacketResult::ErrorSendFailed;      Mutex::Locker locker;      Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); + +    // In order to stop async notifications from being processed in the middle of the +    // send/recieve sequence Hijack the broadcast. Then rebroadcast any events when we are done. +    static Listener hijack_listener("lldb.NotifyHijacker"); +    HijackBroadcaster(&hijack_listener, eBroadcastBitGdbReadThreadGotNotify);     +      if (GetSequenceMutex (locker))      {          packet_result = SendPacketAndWaitForResponseNoLock (payload, payload_length, response); @@ -726,6 +858,15 @@ GDBRemoteCommunicationClient::SendPacketAndWaitForResponse                  log->Printf("error: failed to get packet sequence mutex, not sending packet '%*s'", (int) payload_length, payload);          }      } + +    // Remove our Hijacking listner from the broadcast. +    RestoreBroadcaster(); + +    // If a notification event occured, rebroadcast since it can now be processed safely.   +    EventSP event_sp; +    if (hijack_listener.GetNextEvent(event_sp)) +        BroadcastEvent(event_sp); +      return packet_result;  } @@ -822,6 +963,57 @@ GDBRemoteCommunicationClient::HarmonizeThreadIdsForProfileData      return final_output.str();  } +bool +GDBRemoteCommunicationClient::SendvContPacket +( +    ProcessGDBRemote *process, +    const char *payload, +    size_t packet_length, +    StringExtractorGDBRemote &response +) +{ + +    m_curr_tid = LLDB_INVALID_THREAD_ID; +    Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); +    if (log) +        log->Printf("GDBRemoteCommunicationClient::%s ()", __FUNCTION__); + +    // we want to lock down packet sending while we continue +    Mutex::Locker locker(m_sequence_mutex); + +    // here we broadcast this before we even send the packet!! +    // this signals doContinue() to exit +    BroadcastEvent(eBroadcastBitRunPacketSent, NULL); + +    // set the public state to running +    m_public_is_running.SetValue(true, eBroadcastNever); + +    // Set the starting continue packet into "continue_packet". This packet +    // may change if we are interrupted and we continue after an async packet... +    std::string continue_packet(payload, packet_length); + +    if (log) +        log->Printf("GDBRemoteCommunicationClient::%s () sending vCont packet: %s", __FUNCTION__, continue_packet.c_str()); + +    if (SendPacketNoLock(continue_packet.c_str(), continue_packet.size()) != PacketResult::Success) +         return false; + +    // set the private state to running and broadcast this +    m_private_is_running.SetValue(true, eBroadcastAlways); + +    if (log) +        log->Printf("GDBRemoteCommunicationClient::%s () ReadPacket(%s)", __FUNCTION__, continue_packet.c_str()); + +    // wait for the response to the vCont +    if (ReadPacket(response, UINT32_MAX, false) == PacketResult::Success) +    { +        if (response.IsOKResponse()) +            return true; +    } + +    return false; +} +  StateType  GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse  ( @@ -844,7 +1036,10 @@ GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse      // Set the starting continue packet into "continue_packet". This packet      // may change if we are interrupted and we continue after an async packet...      std::string continue_packet(payload, packet_length); -     + +    const auto sigstop_signo = process->GetUnixSignals().GetSignalNumberFromName("SIGSTOP"); +    const auto sigint_signo = process->GetUnixSignals().GetSignalNumberFromName("SIGINT"); +      bool got_async_packet = false;      while (state == eStateRunning) @@ -864,9 +1059,9 @@ GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse          got_async_packet = false;          if (log) -            log->Printf ("GDBRemoteCommunicationClient::%s () WaitForPacket(%s)", __FUNCTION__, continue_packet.c_str()); +            log->Printf ("GDBRemoteCommunicationClient::%s () ReadPacket(%s)", __FUNCTION__, continue_packet.c_str()); -        if (WaitForPacketWithTimeoutMicroSecondsNoLock(response, UINT32_MAX) == PacketResult::Success) +        if (ReadPacket(response, UINT32_MAX, false) == PacketResult::Success)          {              if (response.Empty())                  state = eStateInvalid; @@ -914,16 +1109,16 @@ GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse                              // 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) +                            if (signo != sigint_signo && signo != sigstop_signo)                              {                                  continue_after_async = false; -                                // We didn't get a a SIGINT or SIGSTOP, so try for a +                                // We didn't get 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) == PacketResult::Success) +                                if (ReadPacket (extra_stop_reply_packet, timeout_usec, false) == PacketResult::Success)                                  {                                      switch (extra_stop_reply_packet.GetChar())                                      { @@ -1101,7 +1296,7 @@ GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse          else          {              if (log) -                log->Printf ("GDBRemoteCommunicationClient::%s () WaitForPacket(...) => false", __FUNCTION__); +                log->Printf ("GDBRemoteCommunicationClient::%s () ReadPacket(...) => false", __FUNCTION__);              state = eStateInvalid;          }      } @@ -1287,7 +1482,7 @@ GDBRemoteCommunicationClient::SendArgumentsPacket (const ProcessLaunchInfo &laun      const char *arg = NULL;      const Args &launch_args = launch_info.GetArguments();      if (exe_file) -        exe_path = exe_file.GetPath(); +        exe_path = exe_file.GetPath(false);      else      {          arg = launch_args.GetArgumentAtIndex(0); @@ -1576,6 +1771,105 @@ GDBRemoteCommunicationClient::GetGDBServerVersion()      return m_qGDBServerVersion_is_valid == eLazyBoolYes;  } +void +GDBRemoteCommunicationClient::MaybeEnableCompression (std::vector<std::string> supported_compressions) +{ +    CompressionType avail_type = CompressionType::None; +    std::string avail_name; + +#if defined (HAVE_LIBCOMPRESSION) +    // libcompression is weak linked so test if compression_decode_buffer() is available +    if (compression_decode_buffer != NULL && avail_type == CompressionType::None) +    { +        for (auto compression : supported_compressions) +        { +            if (compression == "lzfse") +            { +                avail_type = CompressionType::LZFSE; +                avail_name = compression; +                break; +            } +        } +    } +#endif + +#if defined (HAVE_LIBCOMPRESSION) +    // libcompression is weak linked so test if compression_decode_buffer() is available +    if (compression_decode_buffer != NULL && avail_type == CompressionType::None) +    { +        for (auto compression : supported_compressions) +        { +            if (compression == "zlib-deflate") +            { +                avail_type = CompressionType::ZlibDeflate; +                avail_name = compression; +                break; +            } +        } +    } +#endif + +#if defined (HAVE_LIBZ) +    if (avail_type == CompressionType::None) +    { +        for (auto compression : supported_compressions) +        { +            if (compression == "zlib-deflate") +            { +                avail_type = CompressionType::ZlibDeflate; +                avail_name = compression; +                break; +            } +        } +    } +#endif + +#if defined (HAVE_LIBCOMPRESSION) +    // libcompression is weak linked so test if compression_decode_buffer() is available +    if (compression_decode_buffer != NULL && avail_type == CompressionType::None) +    { +        for (auto compression : supported_compressions) +        { +            if (compression == "lz4") +            { +                avail_type = CompressionType::LZ4; +                avail_name = compression; +                break; +            } +        } +    } +#endif + +#if defined (HAVE_LIBCOMPRESSION) +    // libcompression is weak linked so test if compression_decode_buffer() is available +    if (compression_decode_buffer != NULL && avail_type == CompressionType::None) +    { +        for (auto compression : supported_compressions) +        { +            if (compression == "lzma") +            { +                avail_type = CompressionType::LZMA; +                avail_name = compression; +                break; +            } +        } +    } +#endif + +    if (avail_type != CompressionType::None) +    { +        StringExtractorGDBRemote response; +        std::string packet = "QEnableCompression:type:" + avail_name + ";"; +        if (SendPacketAndWaitForResponse (packet.c_str(), response, false) !=  PacketResult::Success) +            return; +     +        if (response.IsOKResponse()) +        { +            m_compression_type = avail_type; +        } +    } +} +  const char *  GDBRemoteCommunicationClient::GetGDBServerProgramName()  { @@ -1596,6 +1890,22 @@ GDBRemoteCommunicationClient::GetGDBServerProgramVersion()  }  bool +GDBRemoteCommunicationClient::GetDefaultThreadId (lldb::tid_t &tid) +{ +    StringExtractorGDBRemote response; +    if (SendPacketAndWaitForResponse("qC",response,false) !=  PacketResult::Success) +        return false; + +    if (!response.IsNormalResponse()) +        return false; + +    if (response.GetChar() == 'Q' && response.GetChar() == 'C') +        tid = response.GetHexMaxU32(true, -1); + +    return true; +} + +bool  GDBRemoteCommunicationClient::GetHostInfo (bool force)  {      Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_PROCESS)); @@ -2167,13 +2477,14 @@ GDBRemoteCommunicationClient::GetWatchpointsTriggerAfterInstruction (bool &after  }  int -GDBRemoteCommunicationClient::SetSTDIN (char const *path) +GDBRemoteCommunicationClient::SetSTDIN(const FileSpec &file_spec)  { -    if (path && path[0]) +    if (file_spec)      { +        std::string path{file_spec.GetPath(false)};          StreamString packet;          packet.PutCString("QSetSTDIN:"); -        packet.PutBytesAsRawHex8(path, strlen(path)); +        packet.PutCStringAsRawHex8(path.c_str());          StringExtractorGDBRemote response;          if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) @@ -2189,14 +2500,15 @@ GDBRemoteCommunicationClient::SetSTDIN (char const *path)  }  int -GDBRemoteCommunicationClient::SetSTDOUT (char const *path) +GDBRemoteCommunicationClient::SetSTDOUT(const FileSpec &file_spec)  { -    if (path && path[0]) +    if (file_spec)      { +        std::string path{file_spec.GetPath(false)};          StreamString packet;          packet.PutCString("QSetSTDOUT:"); -        packet.PutBytesAsRawHex8(path, strlen(path)); -         +        packet.PutCStringAsRawHex8(path.c_str()); +          StringExtractorGDBRemote response;          if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success)          { @@ -2211,14 +2523,15 @@ GDBRemoteCommunicationClient::SetSTDOUT (char const *path)  }  int -GDBRemoteCommunicationClient::SetSTDERR (char const *path) +GDBRemoteCommunicationClient::SetSTDERR(const FileSpec &file_spec)  { -    if (path && path[0]) +    if (file_spec)      { +        std::string path{file_spec.GetPath(false)};          StreamString packet;          packet.PutCString("QSetSTDERR:"); -        packet.PutBytesAsRawHex8(path, strlen(path)); -         +        packet.PutCStringAsRawHex8(path.c_str()); +          StringExtractorGDBRemote response;          if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success)          { @@ -2233,7 +2546,7 @@ GDBRemoteCommunicationClient::SetSTDERR (char const *path)  }  bool -GDBRemoteCommunicationClient::GetWorkingDir (std::string &cwd) +GDBRemoteCommunicationClient::GetWorkingDir(FileSpec &working_dir)  {      StringExtractorGDBRemote response;      if (SendPacketAndWaitForResponse ("qGetWorkingDir", response, false) == PacketResult::Success) @@ -2242,21 +2555,24 @@ GDBRemoteCommunicationClient::GetWorkingDir (std::string &cwd)              return false;          if (response.IsErrorResponse())              return false; -        response.GetHexByteString (cwd); +        std::string cwd; +        response.GetHexByteString(cwd); +        working_dir.SetFile(cwd, false, GetHostArchitecture());          return !cwd.empty();      }      return false;  }  int -GDBRemoteCommunicationClient::SetWorkingDir (char const *path) +GDBRemoteCommunicationClient::SetWorkingDir(const FileSpec &working_dir)  { -    if (path && path[0]) +    if (working_dir)      { +        std::string path{working_dir.GetPath(false)};          StreamString packet;          packet.PutCString("QSetWorkingDir:"); -        packet.PutBytesAsRawHex8(path, strlen(path)); -         +        packet.PutCStringAsRawHex8(path.c_str()); +          StringExtractorGDBRemote response;          if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success)          { @@ -2653,6 +2969,9 @@ GDBRemoteCommunicationClient::FindProcesses (const ProcessInstanceInfoMatch &mat              }          }          StringExtractorGDBRemote response; +        // Increase timeout as the first qfProcessInfo packet takes a long time +        // on Android. The value of 1min was arrived at empirically. +        GDBRemoteCommunication::ScopedTimeout timeout (*this, 60);          if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success)          {              do @@ -2734,87 +3053,184 @@ GDBRemoteCommunicationClient::GetGroupName (uint32_t gid, std::string &name)      return false;  } +bool +GDBRemoteCommunicationClient::SetNonStopMode (const bool enable) +{ +    // Form non-stop packet request +    char packet[32]; +    const int packet_len = ::snprintf(packet, sizeof(packet), "QNonStop:%1d", (int)enable); +    assert(packet_len < (int)sizeof(packet)); + +    StringExtractorGDBRemote response; +    // Send to target +    if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) +        if (response.IsOKResponse()) +            return true; + +    // Failed or not supported +    return false; + +} + +static void +MakeSpeedTestPacket(StreamString &packet, uint32_t send_size, uint32_t recv_size) +{ +    packet.Clear(); +    packet.Printf ("qSpeedTest:response_size:%i;data:", recv_size); +    uint32_t bytes_left = send_size; +    while (bytes_left > 0) +    { +        if (bytes_left >= 26) +        { +            packet.PutCString("abcdefghijklmnopqrstuvwxyz"); +            bytes_left -= 26; +        } +        else +        { +            packet.Printf ("%*.*s;", bytes_left, bytes_left, "abcdefghijklmnopqrstuvwxyz"); +            bytes_left = 0; +        } +    } +} + +template<typename T> +T calculate_standard_deviation(const std::vector<T> &v) +{ +    T sum = std::accumulate(std::begin(v), std::end(v), T(0)); +    T mean =  sum / (T)v.size(); +    T accum = T(0); +    std::for_each (std::begin(v), std::end(v), [&](const T d) { +        T delta = d - mean; +        accum += delta * delta; +    }); + +    T stdev = sqrt(accum / (v.size()-1)); +    return stdev; +} +  void -GDBRemoteCommunicationClient::TestPacketSpeed (const uint32_t num_packets) +GDBRemoteCommunicationClient::TestPacketSpeed (const uint32_t num_packets, uint32_t max_send, uint32_t max_recv, bool json, Stream &strm)  {      uint32_t i;      TimeValue start_time, end_time;      uint64_t total_time_nsec;      if (SendSpeedTestPacket (0, 0))      { -        static uint32_t g_send_sizes[] = { 0, 64, 128, 512, 1024 }; -        static uint32_t g_recv_sizes[] = { 0, 64, 128, 512, 1024 }; //, 4*1024, 8*1024, 16*1024, 32*1024, 48*1024, 64*1024, 96*1024, 128*1024 }; -        const size_t k_num_send_sizes = llvm::array_lengthof(g_send_sizes); -        const size_t k_num_recv_sizes = llvm::array_lengthof(g_recv_sizes); -        const uint64_t k_recv_amount = 4*1024*1024; // Receive 4MB -        for (uint32_t send_idx = 0; send_idx < k_num_send_sizes; ++send_idx) -        { -            const uint32_t send_size = g_send_sizes[send_idx]; -            for (uint32_t recv_idx = 0; recv_idx < k_num_recv_sizes; ++recv_idx) -            { -                const uint32_t recv_size = g_recv_sizes[recv_idx]; -                StreamString packet; -                packet.Printf ("qSpeedTest:response_size:%i;data:", recv_size); -                uint32_t bytes_left = send_size; -                while (bytes_left > 0) +        StreamString packet; +        if (json) +            strm.Printf("{ \"packet_speeds\" : {\n    \"num_packets\" : %u,\n    \"results\" : [", num_packets); +        else +            strm.Printf("Testing sending %u packets of various sizes:\n", num_packets); +        strm.Flush(); + +        uint32_t result_idx = 0; +        uint32_t send_size; +        std::vector<float> packet_times; + +        for (send_size = 0; send_size <= max_send; send_size ? send_size *= 2 : send_size = 4) +        { +            for (uint32_t recv_size = 0; recv_size <= max_recv; recv_size ? recv_size *= 2 : recv_size = 4) +            { +                MakeSpeedTestPacket (packet, send_size, recv_size); + +                packet_times.clear(); +                // Test how long it takes to send 'num_packets' packets +                start_time = TimeValue::Now(); +                for (i=0; i<num_packets; ++i)                  { -                    if (bytes_left >= 26) -                    { -                        packet.PutCString("abcdefghijklmnopqrstuvwxyz"); -                        bytes_left -= 26; -                    } -                    else -                    { -                        packet.Printf ("%*.*s;", bytes_left, bytes_left, "abcdefghijklmnopqrstuvwxyz"); -                        bytes_left = 0; -                    } +                    TimeValue packet_start_time = TimeValue::Now(); +                    StringExtractorGDBRemote response; +                    SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false); +                    TimeValue packet_end_time = TimeValue::Now(); +                    uint64_t packet_time_nsec = packet_end_time.GetAsNanoSecondsSinceJan1_1970() - packet_start_time.GetAsNanoSecondsSinceJan1_1970(); +                    packet_times.push_back((float)packet_time_nsec);                  } +                end_time = TimeValue::Now(); +                total_time_nsec = end_time.GetAsNanoSecondsSinceJan1_1970() - start_time.GetAsNanoSecondsSinceJan1_1970(); -                start_time = TimeValue::Now(); -                if (recv_size == 0) +                float packets_per_second = (((float)num_packets)/(float)total_time_nsec) * (float)TimeValue::NanoSecPerSec; +                float total_ms = (float)total_time_nsec/(float)TimeValue::NanoSecPerMilliSec; +                float average_ms_per_packet = total_ms / num_packets; +                const float standard_deviation = calculate_standard_deviation<float>(packet_times); +                if (json)                  { -                    for (i=0; i<num_packets; ++i) -                    { -                        StringExtractorGDBRemote response; -                        SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false); -                    } +                    strm.Printf ("%s\n     {\"send_size\" : %6" PRIu32 ", \"recv_size\" : %6" PRIu32 ", \"total_time_nsec\" : %12" PRIu64 ", \"standard_deviation_nsec\" : %9" PRIu64 " }", result_idx > 0 ? "," : "", send_size, recv_size, total_time_nsec, (uint64_t)standard_deviation); +                    ++result_idx;                  }                  else                  { -                    uint32_t bytes_read = 0; -                    while (bytes_read < k_recv_amount) -                    { -                        StringExtractorGDBRemote response; -                        SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false); -                        bytes_read += recv_size; -                    } +                    strm.Printf ("qSpeedTest(send=%-7u, recv=%-7u) in %" PRIu64 ".%9.9" PRIu64 " sec for %9.2f packets/sec (%10.6f ms per packet) with standard deviation of %10.6f ms\n", +                                 send_size, +                                 recv_size, +                                 total_time_nsec / TimeValue::NanoSecPerSec, +                                 total_time_nsec % TimeValue::NanoSecPerSec, +                                 packets_per_second, +                                 average_ms_per_packet, +                                 standard_deviation/(float)TimeValue::NanoSecPerMilliSec); +                } +                strm.Flush(); +            } +        } + +        const uint64_t k_recv_amount = 4*1024*1024; // Receive amount in bytes + +        const float k_recv_amount_mb = (float)k_recv_amount/(1024.0f*1024.0f); +        if (json) +            strm.Printf("\n    ]\n  },\n  \"download_speed\" : {\n    \"byte_size\" : %" PRIu64 ",\n    \"results\" : [", k_recv_amount); +        else +            strm.Printf("Testing receiving %2.1fMB of data using varying receive packet sizes:\n", k_recv_amount_mb); +        strm.Flush(); +        send_size = 0; +        result_idx = 0; +        for (uint32_t recv_size = 32; recv_size <= max_recv; recv_size *= 2) +        { +            MakeSpeedTestPacket (packet, send_size, recv_size); + +            // If we have a receive size, test how long it takes to receive 4MB of data +            if (recv_size > 0) +            { +                start_time = TimeValue::Now(); +                uint32_t bytes_read = 0; +                uint32_t packet_count = 0; +                while (bytes_read < k_recv_amount) +                { +                    StringExtractorGDBRemote response; +                    SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false); +                    bytes_read += recv_size; +                    ++packet_count;                  }                  end_time = TimeValue::Now();                  total_time_nsec = end_time.GetAsNanoSecondsSinceJan1_1970() - start_time.GetAsNanoSecondsSinceJan1_1970(); -                if (recv_size == 0) +                float mb_second = ((((float)k_recv_amount)/(float)total_time_nsec) * (float)TimeValue::NanoSecPerSec) / (1024.0*1024.0); +                float packets_per_second = (((float)packet_count)/(float)total_time_nsec) * (float)TimeValue::NanoSecPerSec; +                float total_ms = (float)total_time_nsec/(float)TimeValue::NanoSecPerMilliSec; +                float average_ms_per_packet = total_ms / packet_count; + +                if (json)                  { -                    float packets_per_second = (((float)num_packets)/(float)total_time_nsec) * (float)TimeValue::NanoSecPerSec; -                    printf ("%u qSpeedTest(send=%-7u, recv=%-7u) 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); +                    strm.Printf ("%s\n     {\"send_size\" : %6" PRIu32 ", \"recv_size\" : %6" PRIu32 ", \"total_time_nsec\" : %12" PRIu64 " }", result_idx > 0 ? "," : "", send_size, recv_size, total_time_nsec); +                    ++result_idx;                  }                  else                  { -                    float mb_second = ((((float)k_recv_amount)/(float)total_time_nsec) * (float)TimeValue::NanoSecPerSec) / (1024.0*1024.0); -                    printf ("%u qSpeedTest(send=%-7u, recv=%-7u) sent 4MB in %" PRIu64 ".%9.9" PRIu64 " sec for %f MB/sec.\n", -                            num_packets, -                            send_size, -                            recv_size, -                            total_time_nsec / TimeValue::NanoSecPerSec, -                            total_time_nsec % TimeValue::NanoSecPerSec, -                            mb_second); +                    strm.Printf ("qSpeedTest(send=%-7u, recv=%-7u) %6u packets needed to receive %2.1fMB in %" PRIu64 ".%9.9" PRIu64 " sec for %f MB/sec for %9.2f packets/sec (%10.6f ms per packet)\n", +                                 send_size, +                                 recv_size, +                                 packet_count, +                                 k_recv_amount_mb, +                                 total_time_nsec / TimeValue::NanoSecPerSec, +                                 total_time_nsec % TimeValue::NanoSecPerSec, +                                 mb_second, +                                 packets_per_second, +                                 average_ms_per_packet);                  } +                strm.Flush();              }          } +        if (json) +            strm.Printf("\n    ]\n  }\n}\n"); +        else +            strm.EOL();      }  } @@ -2869,10 +3285,9 @@ GDBRemoteCommunicationClient::LaunchGDBserverAndGetPort (lldb::pid_t &pid, const      int packet_len = stream.GetSize();      // give the process a few seconds to startup -    const uint32_t old_packet_timeout = SetPacketTimeout (10); -    auto result = SendPacketAndWaitForResponse(packet, packet_len, response, false); -    SetPacketTimeout (old_packet_timeout); -    if (result == PacketResult::Success) +    GDBRemoteCommunication::ScopedTimeout timeout (*this, 10); +     +    if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success)      {          std::string name;          std::string value; @@ -3109,22 +3524,23 @@ GDBRemoteCommunicationClient::GetShlibInfoAddr()  }  lldb_private::Error -GDBRemoteCommunicationClient::RunShellCommand (const char *command,           // Shouldn't be NULL -                                               const char *working_dir,       // Pass NULL to use the current working directory -                                               int *status_ptr,               // Pass NULL if you don't want the process exit status -                                               int *signo_ptr,                // Pass NULL if you don't want the signal that caused the process to exit -                                               std::string *command_output,   // Pass NULL if you don't want the command output -                                               uint32_t timeout_sec)          // Timeout in seconds to wait for shell program to finish +GDBRemoteCommunicationClient::RunShellCommand(const char *command,           // Shouldn't be NULL +                                              const FileSpec &working_dir,   // Pass empty FileSpec to use the current working directory +                                              int *status_ptr,               // Pass NULL if you don't want the process exit status +                                              int *signo_ptr,                // Pass NULL if you don't want the signal that caused the process to exit +                                              std::string *command_output,   // Pass NULL if you don't want the command output +                                              uint32_t timeout_sec)          // Timeout in seconds to wait for shell program to finish  {      lldb_private::StreamString stream;      stream.PutCString("qPlatform_shell:");      stream.PutBytesAsRawHex8(command, strlen(command));      stream.PutChar(',');      stream.PutHex32(timeout_sec); -    if (working_dir && *working_dir) +    if (working_dir)      { +        std::string path{working_dir.GetPath(false)};          stream.PutChar(','); -        stream.PutBytesAsRawHex8(working_dir, strlen(working_dir)); +        stream.PutCStringAsRawHex8(path.c_str());      }      const char *packet = stream.GetData();      int packet_len = stream.GetSize(); @@ -3157,43 +3573,49 @@ GDBRemoteCommunicationClient::RunShellCommand (const char *command,           //  }  Error -GDBRemoteCommunicationClient::MakeDirectory (const char *path, -                                             uint32_t file_permissions) +GDBRemoteCommunicationClient::MakeDirectory(const FileSpec &file_spec, +                                            uint32_t file_permissions)  { +    std::string path{file_spec.GetPath(false)};      lldb_private::StreamString stream;      stream.PutCString("qPlatform_mkdir:");      stream.PutHex32(file_permissions);      stream.PutChar(','); -    stream.PutBytesAsRawHex8(path, strlen(path)); +    stream.PutCStringAsRawHex8(path.c_str());      const char *packet = stream.GetData();      int packet_len = stream.GetSize();      StringExtractorGDBRemote response; -    if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) -    { -        return Error(response.GetHexMaxU32(false, UINT32_MAX), eErrorTypePOSIX); -    } -    return Error(); +    if (SendPacketAndWaitForResponse(packet, packet_len, response, false) != PacketResult::Success) +        return Error("failed to send '%s' packet", packet); + +    if (response.GetChar() != 'F') +        return Error("invalid response to '%s' packet", packet); + +    return Error(response.GetU32(UINT32_MAX), eErrorTypePOSIX);  }  Error -GDBRemoteCommunicationClient::SetFilePermissions (const char *path, -                                                  uint32_t file_permissions) +GDBRemoteCommunicationClient::SetFilePermissions(const FileSpec &file_spec, +                                                 uint32_t file_permissions)  { +    std::string path{file_spec.GetPath(false)};      lldb_private::StreamString stream;      stream.PutCString("qPlatform_chmod:");      stream.PutHex32(file_permissions);      stream.PutChar(','); -    stream.PutBytesAsRawHex8(path, strlen(path)); +    stream.PutCStringAsRawHex8(path.c_str());      const char *packet = stream.GetData();      int packet_len = stream.GetSize();      StringExtractorGDBRemote response; -    if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) -    { -        return Error(response.GetHexMaxU32(false, UINT32_MAX), eErrorTypePOSIX); -    } -    return Error(); -     + +    if (SendPacketAndWaitForResponse(packet, packet_len, response, false) != PacketResult::Success) +        return Error("failed to send '%s' packet", packet); + +    if (response.GetChar() != 'F') +        return Error("invalid response to '%s' packet", packet); + +    return Error(response.GetU32(UINT32_MAX), eErrorTypePOSIX);  }  static uint64_t @@ -3225,15 +3647,14 @@ GDBRemoteCommunicationClient::OpenFile (const lldb_private::FileSpec& file_spec,                                          mode_t mode,                                          Error &error)  { +    std::string path(file_spec.GetPath(false));      lldb_private::StreamString stream;      stream.PutCString("vFile:open:"); -    std::string path (file_spec.GetPath());      if (path.empty())          return UINT64_MAX;      stream.PutCStringAsRawHex8(path.c_str());      stream.PutChar(','); -    const uint32_t posix_open_flags = File::ConvertOpenOptionsForPOSIXOpen(flags); -    stream.PutHex32(posix_open_flags); +    stream.PutHex32(flags);      stream.PutChar(',');      stream.PutHex32(mode);      const char* packet = stream.GetData(); @@ -3266,9 +3687,9 @@ GDBRemoteCommunicationClient::CloseFile (lldb::user_id_t fd,  lldb::user_id_t  GDBRemoteCommunicationClient::GetFileSize (const lldb_private::FileSpec& file_spec)  { +    std::string path(file_spec.GetPath(false));      lldb_private::StreamString stream;      stream.PutCString("vFile:size:"); -    std::string path (file_spec.GetPath());      stream.PutCStringAsRawHex8(path.c_str());      const char* packet = stream.GetData();      int packet_len = stream.GetSize(); @@ -3284,12 +3705,14 @@ GDBRemoteCommunicationClient::GetFileSize (const lldb_private::FileSpec& file_sp  }  Error -GDBRemoteCommunicationClient::GetFilePermissions(const char *path, uint32_t &file_permissions) +GDBRemoteCommunicationClient::GetFilePermissions(const FileSpec &file_spec, +                                                 uint32_t &file_permissions)  { +    std::string path{file_spec.GetPath(false)};      Error error;      lldb_private::StreamString stream;      stream.PutCString("vFile:mode:"); -    stream.PutCStringAsRawHex8(path); +    stream.PutCStringAsRawHex8(path.c_str());      const char* packet = stream.GetData();      int packet_len = stream.GetSize();      StringExtractorGDBRemote response; @@ -3408,16 +3831,18 @@ GDBRemoteCommunicationClient::WriteFile (lldb::user_id_t fd,  }  Error -GDBRemoteCommunicationClient::CreateSymlink (const char *src, const char *dst) +GDBRemoteCommunicationClient::CreateSymlink(const FileSpec &src, const FileSpec &dst)  { +    std::string src_path{src.GetPath(false)}, +                dst_path{dst.GetPath(false)};      Error error;      lldb_private::StreamGDBRemote stream;      stream.PutCString("vFile:symlink:");      // the unix symlink() command reverses its parameters where the dst if first,      // so we follow suit here -    stream.PutCStringAsRawHex8(dst); +    stream.PutCStringAsRawHex8(dst_path.c_str());      stream.PutChar(','); -    stream.PutCStringAsRawHex8(src); +    stream.PutCStringAsRawHex8(src_path.c_str());      const char* packet = stream.GetData();      int packet_len = stream.GetSize();      StringExtractorGDBRemote response; @@ -3451,14 +3876,15 @@ GDBRemoteCommunicationClient::CreateSymlink (const char *src, const char *dst)  }  Error -GDBRemoteCommunicationClient::Unlink (const char *path) +GDBRemoteCommunicationClient::Unlink(const FileSpec &file_spec)  { +    std::string path{file_spec.GetPath(false)};      Error error;      lldb_private::StreamGDBRemote stream;      stream.PutCString("vFile:unlink:");      // the unix symlink() command reverses its parameters where the dst if first,      // so we follow suit here -    stream.PutCStringAsRawHex8(path); +    stream.PutCStringAsRawHex8(path.c_str());      const char* packet = stream.GetData();      int packet_len = stream.GetSize();      StringExtractorGDBRemote response; @@ -3495,9 +3921,9 @@ GDBRemoteCommunicationClient::Unlink (const char *path)  bool  GDBRemoteCommunicationClient::GetFileExists (const lldb_private::FileSpec& file_spec)  { +    std::string path(file_spec.GetPath(false));      lldb_private::StreamString stream;      stream.PutCString("vFile:exists:"); -    std::string path (file_spec.GetPath());      stream.PutCStringAsRawHex8(path.c_str());      const char* packet = stream.GetData();      int packet_len = stream.GetSize(); @@ -3519,9 +3945,9 @@ GDBRemoteCommunicationClient::CalculateMD5 (const lldb_private::FileSpec& file_s                                              uint64_t &high,                                              uint64_t &low)  { +    std::string path(file_spec.GetPath(false));      lldb_private::StreamString stream;      stream.PutCString("vFile:MD5:"); -    std::string path (file_spec.GetPath());      stream.PutCStringAsRawHex8(path.c_str());      const char* packet = stream.GetData();      int packet_len = stream.GetSize(); @@ -3639,7 +4065,7 @@ GDBRemoteCommunicationClient::SaveRegisterState (lldb::tid_t tid, uint32_t &save              if (thread_suffix_supported)                  ::snprintf (packet, sizeof(packet), "QSaveRegisterState;thread:%4.4" PRIx64 ";", tid);              else -                ::strncpy (packet, "QSaveRegisterState", sizeof(packet)); +                ::snprintf(packet, sizeof(packet), "QSaveRegisterState");              StringExtractorGDBRemote response; @@ -3703,3 +4129,274 @@ GDBRemoteCommunicationClient::RestoreRegisterState (lldb::tid_t tid, uint32_t sa      }      return false;  } + +bool +GDBRemoteCommunicationClient::GetModuleInfo (const FileSpec& module_file_spec, +                                             const lldb_private::ArchSpec& arch_spec, +                                             ModuleSpec &module_spec) +{ +    std::string module_path = module_file_spec.GetPath (false); +    if (module_path.empty ()) +        return false; + +    StreamString packet; +    packet.PutCString("qModuleInfo:"); +    packet.PutCStringAsRawHex8(module_path.c_str()); +    packet.PutCString(";"); +    const auto& triple = arch_spec.GetTriple().getTriple(); +    packet.PutCStringAsRawHex8(triple.c_str()); + +    StringExtractorGDBRemote response; +    if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) != PacketResult::Success) +        return false; + +    if (response.IsErrorResponse () || response.IsUnsupportedResponse ()) +        return false; + +    std::string name; +    std::string value; +    bool success; +    StringExtractor extractor; + +    module_spec.Clear (); +    module_spec.GetFileSpec () = module_file_spec; + +    while (response.GetNameColonValue (name, value)) +    { +        if (name == "uuid" || name == "md5") +        { +            extractor.GetStringRef ().swap (value); +            extractor.SetFilePos (0); +            extractor.GetHexByteString (value); +            module_spec.GetUUID().SetFromCString (value.c_str(), value.size() / 2); +        } +        else if (name == "triple") +        { +            extractor.GetStringRef ().swap (value); +            extractor.SetFilePos (0); +            extractor.GetHexByteString (value); +            module_spec.GetArchitecture().SetTriple (value.c_str ()); +        } +        else if (name == "file_offset") +        { +            const auto ival = StringConvert::ToUInt64 (value.c_str (), 0, 16, &success); +            if (success) +                module_spec.SetObjectOffset (ival); +        } +        else if (name == "file_size") +        { +            const auto ival = StringConvert::ToUInt64 (value.c_str (), 0, 16, &success); +            if (success) +                module_spec.SetObjectSize (ival); +        } +        else if (name == "file_path") +        { +            extractor.GetStringRef ().swap (value); +            extractor.SetFilePos (0); +            extractor.GetHexByteString (value); +            module_spec.GetFileSpec() = FileSpec(value.c_str(), false, arch_spec); +        } +    } + +    return true; +} + +// query the target remote for extended information using the qXfer packet +// +// example: object='features', annex='target.xml', out=<xml output> +// return:  'true'  on success +//          'false' on failure (err set) +bool +GDBRemoteCommunicationClient::ReadExtFeature (const lldb_private::ConstString object, +                                              const lldb_private::ConstString annex, +                                              std::string & out, +                                              lldb_private::Error & err) { + +    std::stringstream output; +    StringExtractorGDBRemote chunk; + +    uint64_t size = GetRemoteMaxPacketSize(); +    if (size == 0) +        size = 0x1000; +    size = size - 1; // Leave space for the 'm' or 'l' character in the response +    int offset = 0; +    bool active = true; + +    // loop until all data has been read +    while ( active ) { + +        // send query extended feature packet +        std::stringstream packet; +        packet << "qXfer:"  +               << object.AsCString("") << ":read:"  +               << annex.AsCString("")  << ":"  +               << std::hex << offset  << ","  +               << std::hex << size; + +        GDBRemoteCommunication::PacketResult res = +            SendPacketAndWaitForResponse( packet.str().c_str(), +                                          chunk, +                                          false ); + +        if ( res != GDBRemoteCommunication::PacketResult::Success ) { +            err.SetErrorString( "Error sending $qXfer packet" ); +            return false; +        } + +        const std::string & str = chunk.GetStringRef( ); +        if ( str.length() == 0 ) { +            // should have some data in chunk +            err.SetErrorString( "Empty response from $qXfer packet" ); +            return false; +        } + +        // check packet code +        switch ( str[0] ) { +            // last chunk +        case ( 'l' ): +            active = false; +            // fall through intentional + +            // more chunks +        case ( 'm' ) : +            if ( str.length() > 1 ) +                output << &str[1]; +            offset += size; +            break; + +            // unknown chunk +        default: +            err.SetErrorString( "Invalid continuation code from $qXfer packet" ); +            return false; +        } +    } + +    out = output.str( ); +    err.Success( ); +    return true; +} + +// Notify the target that gdb is prepared to serve symbol lookup requests. +//  packet: "qSymbol::" +//  reply: +//  OK                  The target does not need to look up any (more) symbols. +//  qSymbol:<sym_name>  The target requests the value of symbol sym_name (hex encoded). +//                      LLDB may provide the value by sending another qSymbol packet +//                      in the form of"qSymbol:<sym_value>:<sym_name>". + +void +GDBRemoteCommunicationClient::ServeSymbolLookups(lldb_private::Process *process) +{ +    if (m_supports_qSymbol) +    { +        Mutex::Locker locker; +        if (GetSequenceMutex(locker, "GDBRemoteCommunicationClient::ServeSymbolLookups() failed due to not getting the sequence mutex")) +        { +            StreamString packet; +            packet.PutCString ("qSymbol::"); +            while (1) +            { +                StringExtractorGDBRemote response; +                if (SendPacketAndWaitForResponseNoLock(packet.GetData(), packet.GetSize(), response) == PacketResult::Success) +                { +                    if (response.IsOKResponse()) +                    { +                        // 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 +                    { +                        llvm::StringRef response_str(response.GetStringRef()); +                        if (response_str.startswith("qSymbol:")) +                        { +                            response.SetFilePos(strlen("qSymbol:")); +                            std::string symbol_name; +                            if (response.GetHexByteString(symbol_name)) +                            { +                                if (symbol_name.empty()) +                                    return; + +                                addr_t symbol_load_addr = LLDB_INVALID_ADDRESS; +                                lldb_private::SymbolContextList sc_list; +                                if (process->GetTarget().GetImages().FindSymbolsWithNameAndType(ConstString(symbol_name), eSymbolTypeAny, sc_list)) +                                { +                                    const size_t num_scs = sc_list.GetSize(); +                                    for (size_t sc_idx=0; sc_idx<num_scs && symbol_load_addr == LLDB_INVALID_ADDRESS; ++sc_idx) +                                    { +                                        SymbolContext sc; +                                        if (sc_list.GetContextAtIndex(sc_idx, sc)) +                                        { +                                            if (sc.symbol) +                                            { +                                                switch (sc.symbol->GetType()) +                                                { +                                                case eSymbolTypeInvalid: +                                                case eSymbolTypeAbsolute: +                                                case eSymbolTypeUndefined: +                                                case eSymbolTypeSourceFile: +                                                case eSymbolTypeHeaderFile: +                                                case eSymbolTypeObjectFile: +                                                case eSymbolTypeCommonBlock: +                                                case eSymbolTypeBlock: +                                                case eSymbolTypeLocal: +                                                case eSymbolTypeParam: +                                                case eSymbolTypeVariable: +                                                case eSymbolTypeVariableType: +                                                case eSymbolTypeLineEntry: +                                                case eSymbolTypeLineHeader: +                                                case eSymbolTypeScopeBegin: +                                                case eSymbolTypeScopeEnd: +                                                case eSymbolTypeAdditional: +                                                case eSymbolTypeCompiler: +                                                case eSymbolTypeInstrumentation: +                                                case eSymbolTypeTrampoline: +                                                    break; + +                                                case eSymbolTypeCode: +                                                case eSymbolTypeResolver: +                                                case eSymbolTypeData: +                                                case eSymbolTypeRuntime: +                                                case eSymbolTypeException: +                                                case eSymbolTypeObjCClass: +                                                case eSymbolTypeObjCMetaClass: +                                                case eSymbolTypeObjCIVar: +                                                case eSymbolTypeReExported: +                                                    symbol_load_addr = sc.symbol->GetLoadAddress(&process->GetTarget()); +                                                    break; +                                                } +                                            } +                                        } +                                    } +                                } +                                // This is the normal path where our symbol lookup was successful and we want +                                // to send a packet with the new symbol value and see if another lookup needs to be +                                // done. + +                                // Change "packet" to contain the requested symbol value and name +                                packet.Clear(); +                                packet.PutCString("qSymbol:"); +                                if (symbol_load_addr != LLDB_INVALID_ADDRESS) +                                    packet.Printf("%" PRIx64, symbol_load_addr); +                                packet.PutCString(":"); +                                packet.PutBytesAsRawHex8(symbol_name.data(), symbol_name.size()); +                                continue; // go back to the while loop and send "packet" and wait for another response +                            } +                        } +                    } +                } +            } +            // If we make it here, the symbol request packet response wasn't valid or +            // our symbol lookup failed so we must abort +            return; + +        } +    } +} + | 
