Update release making notes.
[deliverable/binutils-gdb.git] / gdb / gdbserver / hostio.c
index 757a229e8469600964a7f84d18b2aa6edd8126d8..8af4fbf4087aa8866c21990529492ea3bbac002a 100644 (file)
@@ -1,6 +1,5 @@
 /* Host file transfer support for gdbserver.
-   Copyright (C) 2007
-   Free Software Foundation, Inc.
+   Copyright (C) 2007-2020 Free Software Foundation, Inc.
 
    Contributed by CodeSourcery.
 
@@ -8,7 +7,7 @@
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "server.h"
 #include "gdb/fileio.h"
+#include "hostio.h"
 
-#include <errno.h>
 #include <fcntl.h>
 #include <limits.h>
 #include <unistd.h>
-
-extern int remote_debug;
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "gdbsupport/fileio.h"
 
 struct fd_list
 {
@@ -54,6 +52,14 @@ safe_fromhex (char a, int *nibble)
   return 0;
 }
 
+/* Filenames are hex encoded, so the maximum we can handle is half the
+   packet buffer size.  Cap to PATH_MAX, if it is shorter.  */
+#if !defined (PATH_MAX) || (PATH_MAX > (PBUFSIZ / 2 + 1))
+#  define HOSTIO_PATH_MAX (PBUFSIZ / 2 + 1)
+#else
+#  define HOSTIO_PATH_MAX PATH_MAX
+#endif
+
 static int
 require_filename (char **pp, char *filename)
 {
@@ -68,7 +74,7 @@ require_filename (char **pp, char *filename)
       int nib1, nib2;
 
       /* Don't allow overflow.  */
-      if (count >= PATH_MAX - 1)
+      if (count >= HOSTIO_PATH_MAX - 1)
        return -1;
 
       if (safe_fromhex (p[0], &nib1)
@@ -88,22 +94,27 @@ static int
 require_int (char **pp, int *value)
 {
   char *p;
-  int count;
+  int count, firstdigit;
 
   p = *pp;
   *value = 0;
   count = 0;
+  firstdigit = -1;
 
   while (*p && *p != ',')
     {
       int nib;
 
-      /* Don't allow overflow.  */
-      if (count >= 7)
+      if (safe_fromhex (p[0], &nib))
        return -1;
 
-      if (safe_fromhex (p[0], &nib))
+      if (firstdigit == -1)
+       firstdigit = nib;
+
+      /* Don't allow overflow.  */
+      if (count >= 8 || (count == 7 && firstdigit >= 0x8))
        return -1;
+
       *value = *value * 16 + nib;
       p++;
       count++;
@@ -118,7 +129,7 @@ require_data (char *p, int p_len, char **data, int *data_len)
 {
   int input_index, output_index, escaped;
 
-  *data = malloc (p_len);
+  *data = (char *) xmalloc (p_len);
 
   output_index = 0;
   escaped = 0;
@@ -138,7 +149,10 @@ require_data (char *p, int p_len, char **data, int *data_len)
     }
 
   if (escaped)
-    return -1;
+    {
+      free (*data);
+      return -1;
+    }
 
   *data_len = output_index;
   return 0;
@@ -177,69 +191,18 @@ require_valid_fd (int fd)
   return -1;
 }
 
-static int
-errno_to_fileio_errno (int error)
-{
-  switch (error)
-    {
-    case EPERM:
-      return FILEIO_EPERM;
-    case ENOENT:
-      return FILEIO_ENOENT;
-    case EINTR:
-      return FILEIO_EINTR;
-    case EIO:
-      return FILEIO_EIO;
-    case EBADF:
-      return FILEIO_EBADF;
-    case EACCES:
-      return FILEIO_EACCES;
-    case EFAULT:
-      return FILEIO_EFAULT;
-    case EBUSY:
-      return FILEIO_EBUSY;
-    case EEXIST:
-      return FILEIO_EEXIST;
-    case ENODEV:
-      return FILEIO_ENODEV;
-    case ENOTDIR:
-      return FILEIO_ENOTDIR;
-    case EISDIR:
-      return FILEIO_EISDIR;
-    case EINVAL:
-      return FILEIO_EINVAL;
-    case ENFILE:
-      return FILEIO_ENFILE;
-    case EMFILE:
-      return FILEIO_EMFILE;
-    case EFBIG:
-      return FILEIO_EFBIG;
-    case ENOSPC:
-      return FILEIO_ENOSPC;
-    case ESPIPE:
-      return FILEIO_ESPIPE;
-    case EROFS:
-      return FILEIO_EROFS;
-    case ENOSYS:
-      return FILEIO_ENOSYS;
-    case ENAMETOOLONG:
-      return FILEIO_ENAMETOOLONG;
-    }
-  return FILEIO_EUNKNOWN;
-}
-
+/* Fill in own_buf with the last hostio error packet, however it
+   suitable for the target.  */
 static void
-hostio_error (char *own_buf, int error)
+hostio_error (char *own_buf)
 {
-  int fileio_error = errno_to_fileio_errno (error);
-
-  sprintf (own_buf, "F-1,%x", fileio_error);
+  the_target->hostio_last_error (own_buf);
 }
 
 static void
 hostio_packet_error (char *own_buf)
 {
-  hostio_error (own_buf, EINVAL);
+  sprintf (own_buf, "F-1,%x", FILEIO_EINVAL);
 }
 
 static void
@@ -283,44 +246,62 @@ hostio_reply_with_data (char *own_buf, char *buffer, int len,
   return input_index;
 }
 
-static int
-fileio_open_flags_to_host (int fileio_open_flags, int *open_flags_p)
+/* Process ID of inferior whose filesystem hostio functions
+   that take FILENAME arguments will use.  Zero means to use
+   our own filesystem.  */
+
+static int hostio_fs_pid;
+
+/* See hostio.h.  */
+
+void
+hostio_handle_new_gdb_connection (void)
 {
-  int open_flags = 0;
+  hostio_fs_pid = 0;
+}
 
-  if (fileio_open_flags & ~FILEIO_O_SUPPORTED)
-    return -1;
+/* Handle a "vFile:setfs:" packet.  */
 
-  if (fileio_open_flags & FILEIO_O_CREAT)
-    open_flags |= O_CREAT;
-  if (fileio_open_flags & FILEIO_O_EXCL)
-    open_flags |= O_EXCL;
-  if (fileio_open_flags & FILEIO_O_TRUNC)
-    open_flags |= O_TRUNC;
-  if (fileio_open_flags & FILEIO_O_APPEND)
-    open_flags |= O_APPEND;
-  if (fileio_open_flags & FILEIO_O_RDONLY)
-    open_flags |= O_RDONLY;
-  if (fileio_open_flags & FILEIO_O_WRONLY)
-    open_flags |= O_WRONLY;
-  if (fileio_open_flags & FILEIO_O_RDWR)
-    open_flags |= O_RDWR;
-/* On systems supporting binary and text mode, always open files in
-   binary mode. */
-#ifdef O_BINARY
-  open_flags |= O_BINARY;
-#endif
+static void
+handle_setfs (char *own_buf)
+{
+  char *p;
+  int pid;
+
+  /* If the target doesn't have any of the in-filesystem-of methods
+     then there's no point in GDB sending "vFile:setfs:" packets.  We
+     reply with an empty packet (i.e. we pretend we don't understand
+     "vFile:setfs:") and that should stop GDB sending any more.  */
+  if (the_target->multifs_open == NULL
+      && the_target->multifs_unlink == NULL
+      && the_target->multifs_readlink == NULL)
+    {
+      own_buf[0] = '\0';
+      return;
+    }
 
-  *open_flags_p = open_flags;
-  return 0;
+  p = own_buf + strlen ("vFile:setfs:");
+
+  if (require_int (&p, &pid)
+      || pid < 0
+      || require_end (p))
+    {
+      hostio_packet_error (own_buf);
+      return;
+    }
+
+  hostio_fs_pid = pid;
+
+  hostio_reply (own_buf, 0);
 }
 
 static void
 handle_open (char *own_buf)
 {
-  char filename[PATH_MAX];
+  char filename[HOSTIO_PATH_MAX];
   char *p;
-  int fileio_flags, mode, flags, fd;
+  int fileio_flags, fileio_mode, flags, fd;
+  mode_t mode;
   struct fd_list *new_fd;
 
   p = own_buf + strlen ("vFile:open:");
@@ -329,9 +310,10 @@ handle_open (char *own_buf)
       || require_comma (&p)
       || require_int (&p, &fileio_flags)
       || require_comma (&p)
-      || require_int (&p, &mode)
+      || require_int (&p, &fileio_mode)
       || require_end (p)
-      || fileio_open_flags_to_host (fileio_flags, &flags))
+      || fileio_to_host_openflags (fileio_flags, &flags)
+      || fileio_to_host_mode (fileio_mode, &mode))
     {
       hostio_packet_error (own_buf);
       return;
@@ -339,16 +321,20 @@ handle_open (char *own_buf)
 
   /* We do not need to convert MODE, since the fileio protocol
      uses the standard values.  */
-  fd = open (filename, flags, mode);
+  if (hostio_fs_pid != 0 && the_target->multifs_open != NULL)
+    fd = the_target->multifs_open (hostio_fs_pid, filename,
+                                  flags, mode);
+  else
+    fd = open (filename, flags, mode);
 
   if (fd == -1)
     {
-      hostio_error (own_buf, errno);
+      hostio_error (own_buf);
       return;
     }
 
   /* Record the new file descriptor.  */
-  new_fd = malloc (sizeof (struct fd_list));
+  new_fd = XNEW (struct fd_list);
   new_fd->fd = fd;
   new_fd->next = open_fds;
   open_fds = new_fd;
@@ -361,6 +347,7 @@ handle_pread (char *own_buf, int *new_packet_len)
 {
   int fd, ret, len, offset, bytes_sent;
   char *p, *data;
+  static int max_reply_size = -1;
 
   p = own_buf + strlen ("vFile:pread:");
 
@@ -376,18 +363,34 @@ handle_pread (char *own_buf, int *new_packet_len)
       return;
     }
 
-  data = malloc (len);
+  /* Do not attempt to read more than the maximum number of bytes
+     hostio_reply_with_data can fit in a packet.  We may still read
+     too much because of escaping, but this is handled below.  */
+  if (max_reply_size == -1)
+    {
+      sprintf (own_buf, "F%x;", PBUFSIZ);
+      max_reply_size = PBUFSIZ - strlen (own_buf);
+    }
+  if (len > max_reply_size)
+    len = max_reply_size;
+
+  data = (char *) xmalloc (len);
 #ifdef HAVE_PREAD
   ret = pread (fd, data, len, offset);
 #else
-  ret = lseek (fd, offset, SEEK_SET);
-  if (ret != -1)
-    ret = read (fd, data, len);
+  ret = -1;
 #endif
+  /* If we have no pread or it failed for this file, use lseek/read.  */
+  if (ret == -1)
+    {
+      ret = lseek (fd, offset, SEEK_SET);
+      if (ret != -1)
+       ret = read (fd, data, len);
+    }
 
   if (ret == -1)
     {
-      hostio_error (own_buf, errno);
+      hostio_error (own_buf);
       free (data);
       return;
     }
@@ -428,14 +431,19 @@ handle_pwrite (char *own_buf, int packet_len)
 #ifdef HAVE_PWRITE
   ret = pwrite (fd, data, len, offset);
 #else
-  ret = lseek (fd, offset, SEEK_SET);
-  if (ret != -1)
-    ret = write (fd, data, len);
+  ret = -1;
 #endif
+  /* If we have no pwrite or it failed for this file, use lseek/write.  */
+  if (ret == -1)
+    {
+      ret = lseek (fd, offset, SEEK_SET);
+      if (ret != -1)
+       ret = write (fd, data, len);
+    }
 
   if (ret == -1)
     {
-      hostio_error (own_buf, errno);
+      hostio_error (own_buf);
       free (data);
       return;
     }
@@ -444,6 +452,42 @@ handle_pwrite (char *own_buf, int packet_len)
   free (data);
 }
 
+static void
+handle_fstat (char *own_buf, int *new_packet_len)
+{
+  int fd, bytes_sent;
+  char *p;
+  struct stat st;
+  struct fio_stat fst;
+
+  p = own_buf + strlen ("vFile:fstat:");
+
+  if (require_int (&p, &fd)
+      || require_valid_fd (fd)
+      || require_end (p))
+    {
+      hostio_packet_error (own_buf);
+      return;
+    }
+
+  if (fstat (fd, &st) == -1)
+    {
+      hostio_error (own_buf);
+      return;
+    }
+
+  host_to_fileio_stat (&st, &fst);
+
+  bytes_sent = hostio_reply_with_data (own_buf,
+                                      (char *) &fst, sizeof (fst),
+                                      new_packet_len);
+
+  /* If the response does not fit into a single packet, do not attempt
+     to return a partial response, but simply fail.  */
+  if (bytes_sent < sizeof (fst))
+    write_enn (own_buf);
+}
+
 static void
 handle_close (char *own_buf)
 {
@@ -465,12 +509,13 @@ handle_close (char *own_buf)
 
   if (ret == -1)
     {
-      hostio_error (own_buf, errno);
+      hostio_error (own_buf);
       return;
     }
 
   open_fd_p = &open_fds;
-  while (*open_fd_p && (*open_fd_p)->fd != fd)
+  /* We know that fd is in the list, thanks to require_valid_fd.  */
+  while ((*open_fd_p)->fd != fd)
     open_fd_p = &(*open_fd_p)->next;
 
   old_fd = *open_fd_p;
@@ -483,7 +528,7 @@ handle_close (char *own_buf)
 static void
 handle_unlink (char *own_buf)
 {
-  char filename[PATH_MAX];
+  char filename[HOSTIO_PATH_MAX];
   char *p;
   int ret;
 
@@ -496,32 +541,78 @@ handle_unlink (char *own_buf)
       return;
     }
 
-  ret = unlink (filename);
+  if (hostio_fs_pid != 0 && the_target->multifs_unlink != NULL)
+    ret = the_target->multifs_unlink (hostio_fs_pid, filename);
+  else
+    ret = unlink (filename);
 
   if (ret == -1)
     {
-      hostio_error (own_buf, errno);
+      hostio_error (own_buf);
       return;
     }
 
   hostio_reply (own_buf, ret);
 }
 
+static void
+handle_readlink (char *own_buf, int *new_packet_len)
+{
+  char filename[HOSTIO_PATH_MAX], linkname[HOSTIO_PATH_MAX];
+  char *p;
+  int ret, bytes_sent;
+
+  p = own_buf + strlen ("vFile:readlink:");
+
+  if (require_filename (&p, filename)
+      || require_end (p))
+    {
+      hostio_packet_error (own_buf);
+      return;
+    }
+
+  if (hostio_fs_pid != 0 && the_target->multifs_readlink != NULL)
+    ret = the_target->multifs_readlink (hostio_fs_pid, filename,
+                                       linkname,
+                                       sizeof (linkname) - 1);
+  else
+    ret = readlink (filename, linkname, sizeof (linkname) - 1);
+
+  if (ret == -1)
+    {
+      hostio_error (own_buf);
+      return;
+    }
+
+  bytes_sent = hostio_reply_with_data (own_buf, linkname, ret, new_packet_len);
+
+  /* If the response does not fit into a single packet, do not attempt
+     to return a partial response, but simply fail.  */
+  if (bytes_sent < ret)
+    sprintf (own_buf, "F-1,%x", FILEIO_ENAMETOOLONG);
+}
+
 /* Handle all the 'F' file transfer packets.  */
 
 int
 handle_vFile (char *own_buf, int packet_len, int *new_packet_len)
 {
-  if (strncmp (own_buf, "vFile:open:", 11) == 0)
+  if (startswith (own_buf, "vFile:open:"))
     handle_open (own_buf);
-  else if (strncmp (own_buf, "vFile:pread:", 11) == 0)
+  else if (startswith (own_buf, "vFile:pread:"))
     handle_pread (own_buf, new_packet_len);
-  else if (strncmp (own_buf, "vFile:pwrite:", 12) == 0)
+  else if (startswith (own_buf, "vFile:pwrite:"))
     handle_pwrite (own_buf, packet_len);
-  else if (strncmp (own_buf, "vFile:close:", 12) == 0)
+  else if (startswith (own_buf, "vFile:fstat:"))
+    handle_fstat (own_buf, new_packet_len);
+  else if (startswith (own_buf, "vFile:close:"))
     handle_close (own_buf);
-  else if (strncmp (own_buf, "vFile:unlink:", 13) == 0)
+  else if (startswith (own_buf, "vFile:unlink:"))
     handle_unlink (own_buf);
+  else if (startswith (own_buf, "vFile:readlink:"))
+    handle_readlink (own_buf, new_packet_len);
+  else if (startswith (own_buf, "vFile:setfs:"))
+    handle_setfs (own_buf);
   else
     return 0;
 
This page took 0.032778 seconds and 4 git commands to generate.