diff options
| author | Ed Maste <emaste@FreeBSD.org> | 2013-12-03 18:51:59 +0000 | 
|---|---|---|
| committer | Ed Maste <emaste@FreeBSD.org> | 2013-12-03 18:51:59 +0000 | 
| commit | 86758c718870f701bc69c1ca05495305ed1c5b85 (patch) | |
| tree | b2051e4e4856cc58ac7e2d20242b870b4f355ca1 /source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp | |
| parent | f21a844f60ae6c74fcf1fddca32461acce3c1ee0 (diff) | |
Notes
Diffstat (limited to 'source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp')
| -rw-r--r-- | source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp | 374 | 
1 files changed, 338 insertions, 36 deletions
| diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index 2ac7d20c6c60..2690992eeed3 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -65,6 +65,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) :      m_attach_or_wait_reply(eLazyBoolCalculate),      m_prepare_for_reg_writing_reply (eLazyBoolCalculate),      m_supports_p (eLazyBoolCalculate), +    m_supports_QSaveRegisterState (eLazyBoolCalculate),      m_supports_qProcessInfoPID (true),      m_supports_qfProcessInfo (true),      m_supports_qUserName (true), @@ -110,17 +111,35 @@ GDBRemoteCommunicationClient::~GDBRemoteCommunicationClient()  bool  GDBRemoteCommunicationClient::HandshakeWithServer (Error *error_ptr)  { +    ResetDiscoverableSettings(); +      // 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"); +    { +        // The return value from QueryNoAckModeSupported() is true if the packet +        // was sent and _any_ response (including UNIMPLEMENTED) was received), +        // or false if no response was received. This quickly tells us if we have +        // a live connection to a remote GDB server... +        if (QueryNoAckModeSupported()) +        { +            return true; +        } +        else +        { +            if (error_ptr) +                error_ptr->SetErrorString("failed to get reply to handshake packet"); +        } +    } +    else +    { +        if (error_ptr) +            error_ptr->SetErrorString("failed to send the handshake ack"); +    }      return false;  } -void +bool  GDBRemoteCommunicationClient::QueryNoAckModeSupported ()  {      if (m_supports_not_sending_acks == eLazyBoolCalculate) @@ -136,8 +155,10 @@ GDBRemoteCommunicationClient::QueryNoAckModeSupported ()                  m_send_acks = false;                  m_supports_not_sending_acks = eLazyBoolYes;              } +            return true;          }      } +    return false;  }  void @@ -208,6 +229,7 @@ GDBRemoteCommunicationClient::ResetDiscoverableSettings()      m_supports_vCont_s = eLazyBoolCalculate;      m_supports_vCont_S = eLazyBoolCalculate;      m_supports_p = eLazyBoolCalculate; +    m_supports_QSaveRegisterState = eLazyBoolCalculate;      m_qHostInfo_is_valid = eLazyBoolCalculate;      m_qProcessInfo_is_valid = eLazyBoolCalculate;      m_supports_alloc_dealloc_memory = eLazyBoolCalculate; @@ -987,19 +1009,43 @@ GDBRemoteCommunicationClient::GetLaunchSuccess (std::string &error_str)  }  int -GDBRemoteCommunicationClient::SendArgumentsPacket (char const *argv[]) -{ -    if (argv && argv[0]) +GDBRemoteCommunicationClient::SendArgumentsPacket (const ProcessLaunchInfo &launch_info) +{ +    // Since we don't get the send argv0 separate from the executable path, we need to +    // make sure to use the actual exectuable path found in the launch_info... +    std::vector<const char *> argv; +    FileSpec exe_file = launch_info.GetExecutableFile(); +    std::string exe_path; +    const char *arg = NULL; +    const Args &launch_args = launch_info.GetArguments(); +    if (exe_file) +        exe_path = exe_file.GetPath(); +    else +    { +        arg = launch_args.GetArgumentAtIndex(0); +        if (arg) +            exe_path = arg; +    } +    if (!exe_path.empty()) +    { +        argv.push_back(exe_path.c_str()); +        for (uint32_t i=1; (arg = launch_args.GetArgumentAtIndex(i)) != NULL; ++i) +        { +            if (arg) +                argv.push_back(arg); +        } +    } +    if (!argv.empty())      {          StreamString packet;          packet.PutChar('A'); -        const char *arg; -        for (uint32_t i = 0; (arg = argv[i]) != NULL; ++i) +        for (size_t i = 0, n = argv.size(); i < n; ++i)          { +            arg = argv[i];              const int arg_len = strlen(arg);              if (i > 0)                  packet.PutChar(','); -            packet.Printf("%i,%i,", arg_len * 2, i); +            packet.Printf("%i,%i,", arg_len * 2, (int)i);              packet.PutBytesAsRawHex8 (arg, arg_len);          } @@ -1783,6 +1829,22 @@ GDBRemoteCommunicationClient::SetSTDERR (char const *path)      return -1;  } +bool +GDBRemoteCommunicationClient::GetWorkingDir (std::string &cwd) +{ +    StringExtractorGDBRemote response; +    if (SendPacketAndWaitForResponse ("qGetWorkingDir", response, false)) +    { +        if (response.IsUnsupportedResponse()) +            return false; +        if (response.IsErrorResponse()) +            return false; +        response.GetHexByteString (cwd); +        return !cwd.empty(); +    } +    return false; +} +  int  GDBRemoteCommunicationClient::SetWorkingDir (char const *path)  { @@ -2244,7 +2306,7 @@ GDBRemoteCommunicationClient::LaunchGDBserverAndGetPort (lldb::pid_t &pid)      pid = LLDB_INVALID_PROCESS_ID;      StringExtractorGDBRemote response;      StreamString stream; -    stream.PutCString("qLaunchGDBServer:port:0;"); +    stream.PutCString("qLaunchGDBServer;");      std::string hostname;      if (Host::GetHostname (hostname))      { @@ -2495,7 +2557,7 @@ GDBRemoteCommunicationClient::RunShellCommand (const char *command,           //                                                 uint32_t timeout_sec)          // Timeout in seconds to wait for shell program to finish  {      lldb_private::StreamString stream; -    stream.PutCString("qPlatform_RunCommand:"); +    stream.PutCString("qPlatform_shell:");      stream.PutBytesAsRawHex8(command, strlen(command));      stream.PutChar(',');      stream.PutHex32(timeout_sec); @@ -2534,24 +2596,44 @@ GDBRemoteCommunicationClient::RunShellCommand (const char *command,           //      return Error("unable to send packet");  } -uint32_t -GDBRemoteCommunicationClient::MakeDirectory (const std::string &path, -                                             mode_t mode) +Error +GDBRemoteCommunicationClient::MakeDirectory (const char *path, +                                             uint32_t file_permissions)  {      lldb_private::StreamString stream; -    stream.PutCString("qPlatform_IO_MkDir:"); -    stream.PutHex32(mode); +    stream.PutCString("qPlatform_mkdir:"); +    stream.PutHex32(file_permissions);      stream.PutChar(','); -    stream.PutBytesAsRawHex8(path.c_str(), path.size()); +    stream.PutBytesAsRawHex8(path, strlen(path));      const char *packet = stream.GetData();      int packet_len = stream.GetSize();      StringExtractorGDBRemote response;      if (SendPacketAndWaitForResponse(packet, packet_len, response, false))      { -        return response.GetHexMaxU32(false, UINT32_MAX); +        return Error(response.GetHexMaxU32(false, UINT32_MAX), eErrorTypePOSIX);      } -    return UINT32_MAX; +    return Error(); + +} +Error +GDBRemoteCommunicationClient::SetFilePermissions (const char *path, +                                                  uint32_t file_permissions) +{ +    lldb_private::StreamString stream; +    stream.PutCString("qPlatform_chmod:"); +    stream.PutHex32(file_permissions); +    stream.PutChar(','); +    stream.PutBytesAsRawHex8(path, strlen(path)); +    const char *packet = stream.GetData(); +    int packet_len = stream.GetSize(); +    StringExtractorGDBRemote response; +    if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) +    { +        return Error(response.GetHexMaxU32(false, UINT32_MAX), eErrorTypePOSIX); +    } +    return Error(); +      }  static uint64_t @@ -2641,13 +2723,13 @@ GDBRemoteCommunicationClient::GetFileSize (const lldb_private::FileSpec& file_sp      return UINT64_MAX;  } -uint32_t -GDBRemoteCommunicationClient::GetFilePermissions(const lldb_private::FileSpec& file_spec, Error &error) +Error +GDBRemoteCommunicationClient::GetFilePermissions(const char *path, uint32_t &file_permissions)  { +    Error error;      lldb_private::StreamString stream;      stream.PutCString("vFile:mode:"); -    std::string path (file_spec.GetPath()); -    stream.PutCStringAsRawHex8(path.c_str()); +    stream.PutCStringAsRawHex8(path);      const char* packet = stream.GetData();      int packet_len = stream.GetSize();      StringExtractorGDBRemote response; @@ -2656,29 +2738,34 @@ GDBRemoteCommunicationClient::GetFilePermissions(const lldb_private::FileSpec& f          if (response.GetChar() != 'F')          {              error.SetErrorStringWithFormat ("invalid response to '%s' packet", packet); -            return 0;          } -        const uint32_t mode = response.GetS32(-1); -        if (mode == -1) +        else          { -            if (response.GetChar() == ',') +            const uint32_t mode = response.GetS32(-1); +            if (mode == -1)              { -                int response_errno = response.GetS32(-1); -                if (response_errno > 0) -                    error.SetError(response_errno, lldb::eErrorTypePOSIX); +                if (response.GetChar() == ',') +                { +                    int response_errno = response.GetS32(-1); +                    if (response_errno > 0) +                        error.SetError(response_errno, lldb::eErrorTypePOSIX); +                    else +                        error.SetErrorToGenericError(); +                }                  else                      error.SetErrorToGenericError();              } +            else +            { +                file_permissions = mode & (S_IRWXU|S_IRWXG|S_IRWXO); +            }          } -        else -            error.Clear(); -        return mode & (S_IRWXU|S_IRWXG|S_IRWXO);      }      else      {          error.SetErrorStringWithFormat ("failed to send '%s' packet", packet);      } -    return 0; +    return error;  }  uint64_t @@ -2760,6 +2847,90 @@ GDBRemoteCommunicationClient::WriteFile (lldb::user_id_t fd,      return 0;  } +Error +GDBRemoteCommunicationClient::CreateSymlink (const char *src, const char *dst) +{ +    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.PutChar(','); +    stream.PutCStringAsRawHex8(src); +    const char* packet = stream.GetData(); +    int packet_len = stream.GetSize(); +    StringExtractorGDBRemote response; +    if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) +    { +        if (response.GetChar() == 'F') +        { +            uint32_t result = response.GetU32(UINT32_MAX); +            if (result != 0) +            { +                error.SetErrorToGenericError(); +                if (response.GetChar() == ',') +                { +                    int response_errno = response.GetS32(-1); +                    if (response_errno > 0) +                        error.SetError(response_errno, lldb::eErrorTypePOSIX); +                } +            } +        } +        else +        { +            // Should have returned with 'F<result>[,<errno>]' +            error.SetErrorStringWithFormat("symlink failed"); +        } +    } +    else +    { +        error.SetErrorString ("failed to send vFile:symlink packet"); +    } +    return error; +} + +Error +GDBRemoteCommunicationClient::Unlink (const char *path) +{ +    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); +    const char* packet = stream.GetData(); +    int packet_len = stream.GetSize(); +    StringExtractorGDBRemote response; +    if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) +    { +        if (response.GetChar() == 'F') +        { +            uint32_t result = response.GetU32(UINT32_MAX); +            if (result != 0) +            { +                error.SetErrorToGenericError(); +                if (response.GetChar() == ',') +                { +                    int response_errno = response.GetS32(-1); +                    if (response_errno > 0) +                        error.SetError(response_errno, lldb::eErrorTypePOSIX); +                } +            } +        } +        else +        { +            // Should have returned with 'F<result>[,<errno>]' +            error.SetErrorStringWithFormat("unlink failed"); +        } +    } +    else +    { +        error.SetErrorString ("failed to send vFile:unlink packet"); +    } +    return error; +} +  // Extension of host I/O packets to get whether a file exists.  bool  GDBRemoteCommunicationClient::GetFileExists (const lldb_private::FileSpec& file_spec) @@ -2809,3 +2980,134 @@ GDBRemoteCommunicationClient::CalculateMD5 (const lldb_private::FileSpec& file_s      }      return false;  } + +bool +GDBRemoteCommunicationClient::ReadRegister(lldb::tid_t tid, uint32_t reg, StringExtractorGDBRemote &response) +{ +    Mutex::Locker locker; +    if (GetSequenceMutex (locker, "Didn't get sequence mutex for p packet.")) +    { +        const bool thread_suffix_supported = GetThreadSuffixSupported(); +         +        if (thread_suffix_supported || SetCurrentThread(tid)) +        { +            char packet[64]; +            int packet_len = 0; +            if (thread_suffix_supported) +                packet_len = ::snprintf (packet, sizeof(packet), "p%x;thread:%4.4" PRIx64 ";", reg, tid); +            else +                packet_len = ::snprintf (packet, sizeof(packet), "p%x", reg); +            assert (packet_len < ((int)sizeof(packet) - 1)); +            return SendPacketAndWaitForResponse(packet, response, false); +        } +    } +    return false; + +} + + +bool +GDBRemoteCommunicationClient::ReadAllRegisters (lldb::tid_t tid, StringExtractorGDBRemote &response) +{ +    Mutex::Locker locker; +    if (GetSequenceMutex (locker, "Didn't get sequence mutex for g packet.")) +    { +        const bool thread_suffix_supported = GetThreadSuffixSupported(); + +        if (thread_suffix_supported || SetCurrentThread(tid)) +        { +            char packet[64]; +            int packet_len = 0; +            // Get all registers in one packet +            if (thread_suffix_supported) +                packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4" PRIx64 ";", tid); +            else +                packet_len = ::snprintf (packet, sizeof(packet), "g"); +            assert (packet_len < ((int)sizeof(packet) - 1)); +            return SendPacketAndWaitForResponse(packet, response, false); +        } +    } +    return false; +} +bool +GDBRemoteCommunicationClient::SaveRegisterState (lldb::tid_t tid, uint32_t &save_id) +{ +    save_id = 0; // Set to invalid save ID +    if (m_supports_QSaveRegisterState == eLazyBoolNo) +        return false; +     +    m_supports_QSaveRegisterState = eLazyBoolYes; +    Mutex::Locker locker; +    if (GetSequenceMutex (locker, "Didn't get sequence mutex for QSaveRegisterState.")) +    { +        const bool thread_suffix_supported = GetThreadSuffixSupported(); +        if (thread_suffix_supported || SetCurrentThread(tid)) +        { +            char packet[256]; +            if (thread_suffix_supported) +                ::snprintf (packet, sizeof(packet), "QSaveRegisterState;thread:%4.4" PRIx64 ";", tid); +            else +                ::strncpy (packet, "QSaveRegisterState", sizeof(packet)); +             +            StringExtractorGDBRemote response; + +            if (SendPacketAndWaitForResponse(packet, response, false)) +            { +                if (response.IsUnsupportedResponse()) +                { +                    // This packet isn't supported, don't try calling it again +                    m_supports_QSaveRegisterState = eLazyBoolNo; +                } +                     +                const uint32_t response_save_id = response.GetU32(0); +                if (response_save_id != 0) +                { +                    save_id = response_save_id; +                    return true; +                } +            } +        } +    } +    return false; +} + +bool +GDBRemoteCommunicationClient::RestoreRegisterState (lldb::tid_t tid, uint32_t save_id) +{ +    // We use the "m_supports_QSaveRegisterState" variable here becuase the +    // QSaveRegisterState and QRestoreRegisterState packets must both be supported in +    // order to be useful +    if (m_supports_QSaveRegisterState == eLazyBoolNo) +        return false; +     +    Mutex::Locker locker; +    if (GetSequenceMutex (locker, "Didn't get sequence mutex for QRestoreRegisterState.")) +    { +        const bool thread_suffix_supported = GetThreadSuffixSupported(); +        if (thread_suffix_supported || SetCurrentThread(tid)) +        { +            char packet[256]; +            if (thread_suffix_supported) +                ::snprintf (packet, sizeof(packet), "QRestoreRegisterState:%u;thread:%4.4" PRIx64 ";", save_id, tid); +            else +                ::snprintf (packet, sizeof(packet), "QRestoreRegisterState:%u" PRIx64 ";", save_id); +             +            StringExtractorGDBRemote response; +             +            if (SendPacketAndWaitForResponse(packet, response, false)) +            { +                if (response.IsOKResponse()) +                { +                    return true; +                } +                else if (response.IsUnsupportedResponse()) +                { +                    // This packet isn't supported, don't try calling this packet or +                    // QSaveRegisterState again... +                    m_supports_QSaveRegisterState = eLazyBoolNo; +                } +            } +        } +    } +    return false; +} | 
