diff options
Diffstat (limited to 'source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp')
| -rw-r--r-- | source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp | 232 | 
1 files changed, 136 insertions, 96 deletions
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index 9c263c8c4087..2ea1f206008a 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -30,6 +30,7 @@  #include "lldb/Host/StringConvert.h"  #include "lldb/Host/ThreadLauncher.h"  #include "lldb/Host/TimeValue.h" +#include "lldb/Target/Platform.h"  #include "lldb/Target/Process.h"  #include "llvm/ADT/SmallString.h" @@ -574,15 +575,24 @@ GDBRemoteCommunication::DecompressPacket ()          return true;      if (m_bytes[1] != 'C' && m_bytes[1] != 'N')          return true; -    if (m_bytes[pkt_size - 3] != '#') + +    size_t hash_mark_idx = m_bytes.find ('#'); +    if (hash_mark_idx == std::string::npos) +        return true; +    if (hash_mark_idx + 2 >= m_bytes.size())          return true; -    if (!::isxdigit (m_bytes[pkt_size - 2]) || !::isxdigit (m_bytes[pkt_size - 1])) + +    if (!::isxdigit (m_bytes[hash_mark_idx + 1]) || !::isxdigit (m_bytes[hash_mark_idx + 2]))          return true; -    size_t content_length = pkt_size - 5;   // not counting '$', 'C' | 'N', '#', & the two hex checksum chars -    size_t content_start = 2;               // The first character of the compressed/not-compressed text of the packet -    size_t hash_mark_idx = pkt_size - 3;    // The '#' character marking the end of the packet -    size_t checksum_idx = pkt_size - 2;     // The first character of the two hex checksum characters +    size_t content_length = pkt_size - 5;    // not counting '$', 'C' | 'N', '#', & the two hex checksum chars +    size_t content_start = 2;                // The first character of the compressed/not-compressed text of the packet +    size_t checksum_idx = hash_mark_idx + 1; // The first character of the two hex checksum characters + +    // Normally size_of_first_packet == m_bytes.size() but m_bytes may contain multiple packets. +    // size_of_first_packet is the size of the initial packet which we'll replace with the decompressed +    // version of, leaving the rest of m_bytes unmodified. +    size_t size_of_first_packet = hash_mark_idx + 3;       // Compressed packets ("$C") start with a base10 number which is the size of the uncompressed payload,      // then a : and then the compressed data.  e.g. $C1024:<binary>#00 @@ -604,7 +614,7 @@ GDBRemoteCommunication::DecompressPacket ()              decompressed_bufsize = ::strtoul (bufsize_str.c_str(), NULL, 10);              if (errno != 0 || decompressed_bufsize == ULONG_MAX)              { -                m_bytes.erase (0, pkt_size); +                m_bytes.erase (0, size_of_first_packet);                  return false;              }          } @@ -633,7 +643,7 @@ GDBRemoteCommunication::DecompressPacket ()          if (!success)          {              SendNack(); -            m_bytes.erase (0, pkt_size); +            m_bytes.erase (0, size_of_first_packet);              return false;          }          else @@ -677,7 +687,7 @@ GDBRemoteCommunication::DecompressPacket ()          decompressed_buffer = (uint8_t *) malloc (decompressed_bufsize + 1);          if (decompressed_buffer == nullptr)          { -            m_bytes.erase (0, pkt_size); +            m_bytes.erase (0, size_of_first_packet);              return false;          } @@ -751,7 +761,7 @@ GDBRemoteCommunication::DecompressPacket ()      {          if (decompressed_buffer)              free (decompressed_buffer); -        m_bytes.erase (0, pkt_size); +        m_bytes.erase (0, size_of_first_packet);          return false;      } @@ -773,7 +783,7 @@ GDBRemoteCommunication::DecompressPacket ()          new_packet.push_back ('0');      } -    m_bytes = new_packet; +    m_bytes.replace (0, size_of_first_packet, new_packet.data(), new_packet.size());      free (decompressed_buffer);      return true; @@ -927,8 +937,10 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri                  {                      for (size_t i=0; !binary && i<total_length; ++i)                      { -                        if (isprint(m_bytes[i]) == 0) +                        if (isprint (m_bytes[i]) == 0 && isspace (m_bytes[i]) == 0) +                        {                              binary = true; +                        }                      }                  }                  if (binary) @@ -1100,16 +1112,16 @@ GDBRemoteCommunication::ListenThread (lldb::thread_arg_t arg)  }  Error -GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, -                                                 uint16_t in_port, +GDBRemoteCommunication::StartDebugserverProcess (const char *url, +                                                 Platform *platform,                                                   ProcessLaunchInfo &launch_info, -                                                 uint16_t &out_port) +                                                 uint16_t *port, +                                                 const Args& inferior_args)  {      Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));      if (log) -        log->Printf ("GDBRemoteCommunication::%s(hostname=%s, in_port=%" PRIu16 ", out_port=%" PRIu16, __FUNCTION__, hostname ? hostname : "<empty>", in_port, out_port); +        log->Printf ("GDBRemoteCommunication::%s(url=%s, port=%" PRIu16, __FUNCTION__, url ? url : "<empty>", port ? *port : uint16_t(0)); -    out_port = in_port;      Error error;      // If we locate debugserver, keep that located version around      static FileSpec g_debugserver_file_spec; @@ -1146,11 +1158,20 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname,              }              else              { -                if (log) -                    log->Printf ("GDBRemoteCommunication::%s() could not find gdb-remote stub exe '%s'", __FUNCTION__, debugserver_file_spec.GetPath ().c_str ()); - +                debugserver_file_spec = platform->LocateExecutable(DEBUGSERVER_BASENAME); +                if (debugserver_file_spec) +                { +                    // Platform::LocateExecutable() wouldn't return a path if it doesn't exist +                    debugserver_exists = true; +                } +                else +                { +                    if (log) +                        log->Printf ("GDBRemoteCommunication::%s() could not find gdb-remote stub exe '%s'", __FUNCTION__, debugserver_file_spec.GetPath ().c_str ()); +                } +                // Don't cache the platform specific GDB server binary as it could change +                // from platform to platform                  g_debugserver_file_spec.Clear(); -                debugserver_file_spec.Clear();              }          }      } @@ -1171,17 +1192,9 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname,          debugserver_args.AppendArgument("gdbserver");  #endif -        // If a host and port is supplied then use it -        char host_and_port[128]; -        if (hostname) -        { -            snprintf (host_and_port, sizeof(host_and_port), "%s:%u", hostname, in_port); -            debugserver_args.AppendArgument(host_and_port); -        } -        else -        { -            host_and_port[0] = '\0'; -        } +        // If a url is supplied then use it +        if (url) +            debugserver_args.AppendArgument(url);          // use native registers, not the GDB registers          debugserver_args.AppendArgument("--native-regs"); @@ -1192,30 +1205,41 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname,          }          llvm::SmallString<PATH_MAX> named_pipe_path; -        Pipe port_pipe; - -        if (host_and_port[0] && in_port == 0) +        // socket_pipe is used by debug server to communicate back either +        // TCP port or domain socket name which it listens on. +        // The second purpose of the pipe to serve as a synchronization point - +        // once data is written to the pipe, debug server is up and running. +        Pipe socket_pipe; + +        // port is null when debug server should listen on domain socket - +        // we're not interested in port value but rather waiting for debug server +        // to become available. +        if ((port != nullptr && *port == 0) || port == nullptr)          { -            // Create a temporary file to get the stdout/stderr and redirect the -            // output of the command into this file. We will later read this file -            // if all goes well and fill the data into "command_output_ptr" - -            // Binding to port zero, we need to figure out what port it ends up -            // using using a named pipe... -            error = port_pipe.CreateWithUniqueName("debugserver-named-pipe", false, named_pipe_path); -            if (error.Success()) +            if (url)              { +                // Create a temporary file to get the stdout/stderr and redirect the +                // output of the command into this file. We will later read this file +                // if all goes well and fill the data into "command_output_ptr" +     +#if defined(__APPLE__) +                // Binding to port zero, we need to figure out what port it ends up +                // using using a named pipe... +                error = socket_pipe.CreateWithUniqueName("debugserver-named-pipe", false, named_pipe_path); +                if (error.Fail()) +                { +                    if (log) +                        log->Printf("GDBRemoteCommunication::%s() " +                                "named pipe creation failed: %s", +                                __FUNCTION__, error.AsCString()); +                    return error; +                }                  debugserver_args.AppendArgument("--named-pipe");                  debugserver_args.AppendArgument(named_pipe_path.c_str()); -            } -            else -            { -                if (log) -                    log->Printf("GDBRemoteCommunication::%s() " -                            "named pipe creation failed: %s", -                            __FUNCTION__, error.AsCString()); -                // let's try an unnamed pipe -                error = port_pipe.CreateNew(true); +#else +                // Binding to port zero, we need to figure out what port it ends up +                // using using an unnamed pipe... +                error = socket_pipe.CreateNew(true);                  if (error.Fail())                  {                      if (log) @@ -1224,42 +1248,43 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname,                                  __FUNCTION__, error.AsCString());                      return error;                  } -                int write_fd = port_pipe.GetWriteFileDescriptor(); +                int write_fd = socket_pipe.GetWriteFileDescriptor();                  debugserver_args.AppendArgument("--pipe");                  debugserver_args.AppendArgument(std::to_string(write_fd).c_str()); -                launch_info.AppendCloseFileAction(port_pipe.GetReadFileDescriptor()); -            } -        } -        else -        { -            // No host and port given, so lets listen on our end and make the debugserver -            // connect to us.. -            error = StartListenThread ("127.0.0.1", 0); -            if (error.Fail()) -            { -                if (log) -                    log->Printf ("GDBRemoteCommunication::%s() unable to start listen thread: %s", __FUNCTION__, error.AsCString()); -                return error; -            } - -            ConnectionFileDescriptor *connection = (ConnectionFileDescriptor *)GetConnection (); -            // Wait for 10 seconds to resolve the bound port -            out_port = connection->GetListeningPort(10); -            if (out_port > 0) -            { -                char port_cstr[32]; -                snprintf(port_cstr, sizeof(port_cstr), "127.0.0.1:%i", out_port); -                // Send the host and port down that debugserver and specify an option -                // so that it connects back to the port we are listening to in this process -                debugserver_args.AppendArgument("--reverse-connect"); -                debugserver_args.AppendArgument(port_cstr); +                launch_info.AppendCloseFileAction(socket_pipe.GetReadFileDescriptor()); +#endif              }              else              { -                error.SetErrorString ("failed to bind to port 0 on 127.0.0.1"); -                if (log) -                    log->Printf ("GDBRemoteCommunication::%s() failed: %s", __FUNCTION__, error.AsCString()); -                return error; +                // No host and port given, so lets listen on our end and make the debugserver +                // connect to us.. +                error = StartListenThread ("127.0.0.1", 0); +                if (error.Fail()) +                { +                    if (log) +                        log->Printf ("GDBRemoteCommunication::%s() unable to start listen thread: %s", __FUNCTION__, error.AsCString()); +                    return error; +                } +     +                ConnectionFileDescriptor *connection = (ConnectionFileDescriptor *)GetConnection (); +                // Wait for 10 seconds to resolve the bound port +                *port = connection->GetListeningPort(10); +                if (*port > 0) +                { +                    char port_cstr[32]; +                    snprintf(port_cstr, sizeof(port_cstr), "127.0.0.1:%i", *port); +                    // Send the host and port down that debugserver and specify an option +                    // so that it connects back to the port we are listening to in this process +                    debugserver_args.AppendArgument("--reverse-connect"); +                    debugserver_args.AppendArgument(port_cstr); +                } +                else +                { +                    error.SetErrorString ("failed to bind to port 0 on 127.0.0.1"); +                    if (log) +                        log->Printf ("GDBRemoteCommunication::%s() failed: %s", __FUNCTION__, error.AsCString()); +                    return error; +                }              }          } @@ -1304,6 +1329,20 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname,              }          } while (has_env_var); +        if (inferior_args.GetArgumentCount() > 0) +        { +            debugserver_args.AppendArgument ("--"); +            debugserver_args.AppendArguments (inferior_args); +        } + +        // Copy the current environment to the gdbserver/debugserver instance +        StringList env; +        if (Host::GetEnvironment(env)) +        { +            for (size_t i = 0; i < env.GetSize(); ++i) +                launch_info.GetEnvironmentEntries().AppendArgument(env[i].c_str()); +        } +          // Close STDIN, STDOUT and STDERR.          launch_info.AppendCloseFileAction (STDIN_FILENO);          launch_info.AppendCloseFileAction (STDOUT_FILENO); @@ -1316,11 +1355,12 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname,          error = Host::LaunchProcess(launch_info); -        if (error.Success() && launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) +        if (error.Success() && +            launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID)          {              if (named_pipe_path.size() > 0)              { -                error = port_pipe.OpenAsReader(named_pipe_path, false); +                error = socket_pipe.OpenAsReader(named_pipe_path, false);                  if (error.Fail())                      if (log)                          log->Printf("GDBRemoteCommunication::%s() " @@ -1328,24 +1368,24 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname,                                  __FUNCTION__, named_pipe_path.c_str(), error.AsCString());              } -            if (port_pipe.CanWrite()) -                port_pipe.CloseWriteFileDescriptor(); -            if (port_pipe.CanRead()) +            if (socket_pipe.CanWrite()) +                socket_pipe.CloseWriteFileDescriptor(); +            if (socket_pipe.CanRead())              { -                char port_cstr[256]; +                char port_cstr[PATH_MAX] = {0};                  port_cstr[0] = '\0';                  size_t num_bytes = sizeof(port_cstr);                  // Read port from pipe with 10 second timeout. -                error = port_pipe.ReadWithTimeout(port_cstr, num_bytes, +                error = socket_pipe.ReadWithTimeout(port_cstr, num_bytes,                          std::chrono::seconds{10}, num_bytes); -                if (error.Success()) +                if (error.Success() && (port != nullptr))                  {                      assert(num_bytes > 0 && port_cstr[num_bytes-1] == '\0'); -                    out_port = StringConvert::ToUInt32(port_cstr, 0); +                    *port = StringConvert::ToUInt32(port_cstr, 0);                      if (log)                          log->Printf("GDBRemoteCommunication::%s() " -                                "debugserver listens %u port", -                                __FUNCTION__, out_port); +                                    "debugserver listens %u port", +                                    __FUNCTION__, *port);                  }                  else                  { @@ -1355,12 +1395,12 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname,                                  __FUNCTION__, named_pipe_path.c_str(), error.AsCString());                  } -                port_pipe.Close(); +                socket_pipe.Close();              }              if (named_pipe_path.size() > 0)              { -                const auto err = port_pipe.Delete(named_pipe_path); +                const auto err = socket_pipe.Delete(named_pipe_path);                  if (err.Fail())                  {                      if (log)  | 
