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;