From 1c4b552ba553c4dbbb066c9ef8667209553444ca Mon Sep 17 00:00:00 2001 From: Gary Benson Date: Wed, 25 Mar 2015 11:26:43 +0000 Subject: [PATCH] Associate target_ops with target_fileio file descriptors Various target_fileio_* functions use integer file descriptors to refer to open files. File operation functions are looked up from the target stack as they are used, which causes problems if the target stack changes after the file is opened. For example, if a file is opened on a remote target and the remote target disconnects or closes the remote target will be popped off the stack. If target_fileio_close is then called on that file and "set auto-connect-native-target" is "on" (the default) then the native target's close method will be called. If the file opened on the remote happens to share the same number with a file open in GDB then that file will be closed by mistake. This commit changes target_fileio_open to store newly opened file descriptors in a table together with the target_ops used to open them. The index into the table is returned and used as the file descriptor argument to all target_fileio_* functions that accept file descriptor arguments. gdb/ChangeLog: * target.c (fileio_ft_t): New typedef, define object vector. (fileio_fhandles): New static variable. (is_closed_fileio_fh): New macro. (lowest_closed_fd): New static variable. (acquire_fileio_fd): New function. (release_fileio_fd): Likewise. (fileio_fd_to_fh): New macro. (target_fileio_open): Wrap the file descriptor on success. (target_fileio_pwrite): Updated to use wrapped file descriptor. (target_fileio_pread): Likewise. (target_fileio_close): Likewise. --- gdb/ChangeLog | 15 +++++ gdb/target.c | 169 ++++++++++++++++++++++++++++++++++---------------- 2 files changed, 132 insertions(+), 52 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index a5abe28e14d..591a1145406 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,18 @@ +2015-03-25 Gary Benson + Pedro Alves + + * target.c (fileio_ft_t): New typedef, define object vector. + (fileio_fhandles): New static variable. + (is_closed_fileio_fh): New macro. + (lowest_closed_fd): New static variable. + (acquire_fileio_fd): New function. + (release_fileio_fd): Likewise. + (fileio_fd_to_fh): New macro. + (target_fileio_open): Wrap the file descriptor on success. + (target_fileio_pwrite): Updated to use wrapped file descriptor. + (target_fileio_pread): Likewise. + (target_fileio_close): Likewise. + 2015-03-24 Pedro Alves * thread.c (thread_apply_all_command): Take exited threads into diff --git a/gdb/target.c b/gdb/target.c index af94f48279a..6f6029b238d 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -2684,6 +2684,78 @@ default_fileio_target (void) return find_default_run_target ("file I/O"); } +/* File handle for target file operations. */ + +typedef struct +{ + /* The target on which this file is open. */ + struct target_ops *t; + + /* The file descriptor on the target. */ + int fd; +} fileio_fh_t; + +DEF_VEC_O (fileio_fh_t); + +/* Vector of currently open file handles. The value returned by + target_fileio_open and passed as the FD argument to other + target_fileio_* functions is an index into this vector. This + vector's entries are never freed; instead, files are marked as + closed, and the handle becomes available for reuse. */ +static VEC (fileio_fh_t) *fileio_fhandles; + +/* Macro to check whether a fileio_fh_t represents a closed file. */ +#define is_closed_fileio_fh(fd) ((fd) < 0) + +/* Index into fileio_fhandles of the lowest handle that might be + closed. This permits handle reuse without searching the whole + list each time a new file is opened. */ +static int lowest_closed_fd; + +/* Acquire a target fileio file descriptor. */ + +static int +acquire_fileio_fd (struct target_ops *t, int fd) +{ + fileio_fh_t *fh, buf; + + gdb_assert (!is_closed_fileio_fh (fd)); + + /* Search for closed handles to reuse. */ + for (; + VEC_iterate (fileio_fh_t, fileio_fhandles, + lowest_closed_fd, fh); + lowest_closed_fd++) + if (is_closed_fileio_fh (fh->fd)) + break; + + /* Push a new handle if no closed handles were found. */ + if (lowest_closed_fd == VEC_length (fileio_fh_t, fileio_fhandles)) + fh = VEC_safe_push (fileio_fh_t, fileio_fhandles, NULL); + + /* Fill in the handle. */ + fh->t = t; + fh->fd = fd; + + /* Return its index, and start the next lookup at + the next index. */ + return lowest_closed_fd++; +} + +/* Release a target fileio file descriptor. */ + +static void +release_fileio_fd (int fd, fileio_fh_t *fh) +{ + fh->fd = -1; + lowest_closed_fd = min (lowest_closed_fd, fd); +} + +/* Return a pointer to the fileio_fhandle_t corresponding to FD. */ + +#define fileio_fd_to_fh(fd) \ + VEC_index (fileio_fh_t, fileio_fhandles, (fd)) + /* Open FILENAME on the target, using FLAGS and MODE. Return a target file descriptor, or -1 if an error occurs (and set *TARGET_ERRNO). */ @@ -2699,6 +2771,11 @@ target_fileio_open (const char *filename, int flags, int mode, { int fd = t->to_fileio_open (t, filename, flags, mode, target_errno); + if (fd < 0) + fd = -1; + else + fd = acquire_fileio_fd (t, fd); + if (targetdebug) fprintf_unfiltered (gdb_stdlog, "target_fileio_open (%s,0x%x,0%o) = %d (%d)\n", @@ -2719,27 +2796,22 @@ int target_fileio_pwrite (int fd, const gdb_byte *write_buf, int len, ULONGEST offset, int *target_errno) { - struct target_ops *t; + fileio_fh_t *fh = fileio_fd_to_fh (fd); + int ret = -1; - for (t = default_fileio_target (); t != NULL; t = t->beneath) - { - if (t->to_fileio_pwrite != NULL) - { - int ret = t->to_fileio_pwrite (t, fd, write_buf, len, offset, - target_errno); - - if (targetdebug) - fprintf_unfiltered (gdb_stdlog, - "target_fileio_pwrite (%d,...,%d,%s) " - "= %d (%d)\n", - fd, len, pulongest (offset), - ret, ret != -1 ? 0 : *target_errno); - return ret; - } - } + if (is_closed_fileio_fh (fh->fd)) + *target_errno = EBADF; + else + ret = fh->t->to_fileio_pwrite (fh->t, fh->fd, write_buf, + len, offset, target_errno); - *target_errno = FILEIO_ENOSYS; - return -1; + if (targetdebug) + fprintf_unfiltered (gdb_stdlog, + "target_fileio_pwrite (%d,...,%d,%s) " + "= %d (%d)\n", + fd, len, pulongest (offset), + ret, ret != -1 ? 0 : *target_errno); + return ret; } /* Read up to LEN bytes FD on the target into READ_BUF. @@ -2749,27 +2821,22 @@ int target_fileio_pread (int fd, gdb_byte *read_buf, int len, ULONGEST offset, int *target_errno) { - struct target_ops *t; + fileio_fh_t *fh = fileio_fd_to_fh (fd); + int ret = -1; - for (t = default_fileio_target (); t != NULL; t = t->beneath) - { - if (t->to_fileio_pread != NULL) - { - int ret = t->to_fileio_pread (t, fd, read_buf, len, offset, - target_errno); - - if (targetdebug) - fprintf_unfiltered (gdb_stdlog, - "target_fileio_pread (%d,...,%d,%s) " - "= %d (%d)\n", - fd, len, pulongest (offset), - ret, ret != -1 ? 0 : *target_errno); - return ret; - } - } + if (is_closed_fileio_fh (fh->fd)) + *target_errno = EBADF; + else + ret = fh->t->to_fileio_pread (fh->t, fh->fd, read_buf, + len, offset, target_errno); - *target_errno = FILEIO_ENOSYS; - return -1; + if (targetdebug) + fprintf_unfiltered (gdb_stdlog, + "target_fileio_pread (%d,...,%d,%s) " + "= %d (%d)\n", + fd, len, pulongest (offset), + ret, ret != -1 ? 0 : *target_errno); + return ret; } /* Close FD on the target. Return 0, or -1 if an error occurs @@ -2777,24 +2844,22 @@ target_fileio_pread (int fd, gdb_byte *read_buf, int len, int target_fileio_close (int fd, int *target_errno) { - struct target_ops *t; + fileio_fh_t *fh = fileio_fd_to_fh (fd); + int ret = -1; - for (t = default_fileio_target (); t != NULL; t = t->beneath) + if (is_closed_fileio_fh (fh->fd)) + *target_errno = EBADF; + else { - if (t->to_fileio_close != NULL) - { - int ret = t->to_fileio_close (t, fd, target_errno); - - if (targetdebug) - fprintf_unfiltered (gdb_stdlog, - "target_fileio_close (%d) = %d (%d)\n", - fd, ret, ret != -1 ? 0 : *target_errno); - return ret; - } + ret = fh->t->to_fileio_close (fh->t, fh->fd, target_errno); + release_fileio_fd (fd, fh); } - *target_errno = FILEIO_ENOSYS; - return -1; + if (targetdebug) + fprintf_unfiltered (gdb_stdlog, + "target_fileio_close (%d) = %d (%d)\n", + fd, ret, ret != -1 ? 0 : *target_errno); + return ret; } /* Unlink FILENAME on the target. Return 0, or -1 if an error -- 2.30.2