X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fgdbserver%2Fhostio.c;h=8af4fbf4087aa8866c21990529492ea3bbac002a;hb=e8319fde715960466aca2461c74cec8907abd391;hp=757a229e8469600964a7f84d18b2aa6edd8126d8;hpb=4e799345942e3d777a2639a00892b67d084204c5;p=deliverable%2Fbinutils-gdb.git
diff --git a/gdb/gdbserver/hostio.c b/gdb/gdbserver/hostio.c
index 757a229e84..8af4fbf408 100644
--- a/gdb/gdbserver/hostio.c
+++ b/gdb/gdbserver/hostio.c
@@ -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,
@@ -17,19 +16,18 @@
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 . */
#include "server.h"
#include "gdb/fileio.h"
+#include "hostio.h"
-#include
#include
#include
#include
-
-extern int remote_debug;
+#include
+#include
+#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;