diff options
-rw-r--r-- | gdb/ChangeLog | 18 | ||||
-rw-r--r-- | gdb/gdb_bfd.c | 203 | ||||
-rw-r--r-- | gdb/gdb_bfd.h | 29 |
3 files changed, 246 insertions, 4 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 697aeb1..35acfed 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,23 @@ 2015-04-02 Gary Benson <gbenson@redhat.com> + * gdb/gdb_bfd.h (TARGET_SYSROOT_PREFIX): New definition. + (is_target_filename): New declaration. + (gdb_bfd_has_target_filename): Likewise. + (gdb_bfd_open): Update documentation comment. + * gdb_bfd.c (target.h): New include. + (gdb/fileio.h): Likewise. + (is_target_filename): New function. + (gdb_bfd_has_target_filename): Likewise. + (fileio_errno_to_host): Likewise. + (gdb_bfd_iovec_fileio_open): Likewise. + (gdb_bfd_iovec_fileio_pread): Likewise. + (gdb_bfd_iovec_fileio_close): Likewise. + (gdb_bfd_iovec_fileio_fstat): Likewise. + (gdb_bfd_open): Use target fileio to access paths prefixed + with "target:" where necessary. + +2015-04-02 Gary Benson <gbenson@redhat.com> + * target.h (struct target_ops) <to_filesystem_is_local>: New field. (target_filesystem_is_local): New macro. diff --git a/gdb/gdb_bfd.c b/gdb/gdb_bfd.c index 40874a8..3d5d23f 100644 --- a/gdb/gdb_bfd.c +++ b/gdb/gdb_bfd.c @@ -30,6 +30,8 @@ #define MAP_FAILED ((void *) -1) #endif #endif +#include "target.h" +#include "gdb/fileio.h" typedef bfd *bfdp; DEF_VEC_P (bfdp); @@ -138,6 +140,177 @@ eq_bfd (const void *a, const void *b) /* See gdb_bfd.h. */ +int +is_target_filename (const char *name) +{ + return startswith (name, TARGET_SYSROOT_PREFIX); +} + +/* See gdb_bfd.h. */ + +int +gdb_bfd_has_target_filename (struct bfd *abfd) +{ + return is_target_filename (bfd_get_filename (abfd)); +} + + +/* Return the system error number corresponding to ERRNUM. */ + +static int +fileio_errno_to_host (int errnum) +{ + switch (errnum) + { + case FILEIO_EPERM: + return EPERM; + case FILEIO_ENOENT: + return ENOENT; + case FILEIO_EINTR: + return EINTR; + case FILEIO_EIO: + return EIO; + case FILEIO_EBADF: + return EBADF; + case FILEIO_EACCES: + return EACCES; + case FILEIO_EFAULT: + return EFAULT; + case FILEIO_EBUSY: + return EBUSY; + case FILEIO_EEXIST: + return EEXIST; + case FILEIO_ENODEV: + return ENODEV; + case FILEIO_ENOTDIR: + return ENOTDIR; + case FILEIO_EISDIR: + return EISDIR; + case FILEIO_EINVAL: + return EINVAL; + case FILEIO_ENFILE: + return ENFILE; + case FILEIO_EMFILE: + return EMFILE; + case FILEIO_EFBIG: + return EFBIG; + case FILEIO_ENOSPC: + return ENOSPC; + case FILEIO_ESPIPE: + return ESPIPE; + case FILEIO_EROFS: + return EROFS; + case FILEIO_ENOSYS: + return ENOSYS; + case FILEIO_ENAMETOOLONG: + return ENAMETOOLONG; + } + return -1; +} + +/* Wrapper for target_fileio_open suitable for passing as the + OPEN_FUNC argument to gdb_bfd_openr_iovec. The supplied + OPEN_CLOSURE is unused. */ + +static void * +gdb_bfd_iovec_fileio_open (struct bfd *abfd, void *open_closure) +{ + const char *filename = bfd_get_filename (abfd); + int fd, target_errno; + int *stream; + + gdb_assert (is_target_filename (filename)); + + fd = target_fileio_open (filename + strlen (TARGET_SYSROOT_PREFIX), + FILEIO_O_RDONLY, 0, + &target_errno); + if (fd == -1) + { + errno = fileio_errno_to_host (target_errno); + bfd_set_error (bfd_error_system_call); + return NULL; + } + + stream = XCNEW (int); + *stream = fd; + return stream; +} + +/* Wrapper for target_fileio_pread suitable for passing as the + PREAD_FUNC argument to gdb_bfd_openr_iovec. */ + +static file_ptr +gdb_bfd_iovec_fileio_pread (struct bfd *abfd, void *stream, void *buf, + file_ptr nbytes, file_ptr offset) +{ + int fd = *(int *) stream; + int target_errno; + file_ptr pos, bytes; + + pos = 0; + while (nbytes > pos) + { + bytes = target_fileio_pread (fd, (gdb_byte *) buf + pos, + nbytes - pos, offset + pos, + &target_errno); + if (bytes == 0) + /* Success, but no bytes, means end-of-file. */ + break; + if (bytes == -1) + { + errno = fileio_errno_to_host (target_errno); + bfd_set_error (bfd_error_system_call); + return -1; + } + + pos += bytes; + } + + return pos; +} + +/* Wrapper for target_fileio_close suitable for passing as the + CLOSE_FUNC argument to gdb_bfd_openr_iovec. */ + +static int +gdb_bfd_iovec_fileio_close (struct bfd *abfd, void *stream) +{ + int fd = *(int *) stream; + int target_errno; + + xfree (stream); + + /* Ignore errors on close. These may happen with remote + targets if the connection has already been torn down. */ + target_fileio_close (fd, &target_errno); + + /* Zero means success. */ + return 0; +} + +/* Wrapper for target_fileio_fstat suitable for passing as the + STAT_FUNC argument to gdb_bfd_openr_iovec. */ + +static int +gdb_bfd_iovec_fileio_fstat (struct bfd *abfd, void *stream, + struct stat *sb) +{ + int fd = *(int *) stream; + int target_errno; + int result; + + result = target_fileio_fstat (fd, sb, &target_errno); + if (result == -1) + { + errno = fileio_errno_to_host (target_errno); + bfd_set_error (bfd_error_system_call); + } + + return result; +} + +/* See gdb_bfd.h. */ + struct bfd * gdb_bfd_open (const char *name, const char *target, int fd) { @@ -147,6 +320,36 @@ gdb_bfd_open (const char *name, const char *target, int fd) struct gdb_bfd_cache_search search; struct stat st; + if (is_target_filename (name)) + { + if (!target_filesystem_is_local ()) + { + gdb_assert (fd == -1); + + abfd = gdb_bfd_openr_iovec (name, target, + gdb_bfd_iovec_fileio_open, NULL, + gdb_bfd_iovec_fileio_pread, + gdb_bfd_iovec_fileio_close, + gdb_bfd_iovec_fileio_fstat); + + if (abfd != NULL || errno != ENOSYS) + return abfd; + + /* gdb_bfd_iovec_fileio_open failed with ENOSYS. This can + happen, for example, with vgdb (Valgrind GDB), which + presents itself as a remote target but works on the local + filesystem: it does not implement remote get and users + are not expected to set gdb_sysroot. To handle this case + we fall back to trying the local filesystem iff + gdb_sysroot is exactly TARGET_SYSROOT_PREFIX. */ + if (gdb_sysroot == NULL + || strcmp (gdb_sysroot, TARGET_SYSROOT_PREFIX) != 0) + return NULL; + } + + name += strlen (TARGET_SYSROOT_PREFIX); + } + if (gdb_bfd_cache == NULL) gdb_bfd_cache = htab_create_alloc (1, hash_bfd, eq_bfd, NULL, xcalloc, xfree); diff --git a/gdb/gdb_bfd.h b/gdb/gdb_bfd.h index 05b6870..8fbdf36 100644 --- a/gdb/gdb_bfd.h +++ b/gdb/gdb_bfd.h @@ -24,11 +24,32 @@ DECLARE_REGISTRY (bfd); +/* If supplied a path starting with this sequence, gdb_bfd_open will + open BFDs using target fileio operations. */ + +#define TARGET_SYSROOT_PREFIX "target:" + +/* Returns nonzero if NAME starts with TARGET_SYSROOT_PREFIX, zero + otherwise. */ + +int is_target_filename (const char *name); + +/* Returns nonzero if the filename associated with ABFD starts with + TARGET_SYSROOT_PREFIX, zero otherwise. */ + +int gdb_bfd_has_target_filename (struct bfd *abfd); + /* Open a read-only (FOPEN_RB) BFD given arguments like bfd_fopen. - Returns NULL on error. On success, returns a new reference to the - BFD, which must be freed with gdb_bfd_unref. BFDs returned by this - call are shared among all callers opening the same file. If FD is - not -1, then after this call it is owned by BFD. */ + If NAME starts with TARGET_SYSROOT_PREFIX then the BFD will be + opened using target fileio operations if necessary. Returns NULL + on error. On success, returns a new reference to the BFD, which + must be freed with gdb_bfd_unref. BFDs returned by this call are + shared among all callers opening the same file. If FD is not -1, + then after this call it is owned by BFD. If the BFD was not + accessed using target fileio operations then the filename + associated with the BFD and accessible with bfd_get_filename will + not be exactly NAME but rather NAME with TARGET_SYSROOT_PREFIX + stripped. */ struct bfd *gdb_bfd_open (const char *name, const char *target, int fd); |