Make gdb_bfd_open able to open BFDs using target fileio

This commit updates gdb_bfd_open to access files using target
fileio functions if the supplied path starts with "target:"
and if the local and target filesystems are not the same.
This allows users to specify "set sysroot target:" and have
GDB access files locally or from the remote as appropriate.

The new functions in gdb_bfd.c are copies of functions from
remote.c. This duplication is intentional and will be removed
by the next commit in this series.

gdb/ChangeLog:

	* 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.
This commit is contained in:
Gary Benson
2015-04-02 13:38:29 +01:00
parent 4bd7dc4255
commit f08e97fed1
3 changed files with 246 additions and 4 deletions

View File

@@ -1,3 +1,21 @@
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> 2015-04-02 Gary Benson <gbenson@redhat.com>
* target.h (struct target_ops) <to_filesystem_is_local>: * target.h (struct target_ops) <to_filesystem_is_local>:

View File

@@ -30,6 +30,8 @@
#define MAP_FAILED ((void *) -1) #define MAP_FAILED ((void *) -1)
#endif #endif
#endif #endif
#include "target.h"
#include "gdb/fileio.h"
typedef bfd *bfdp; typedef bfd *bfdp;
DEF_VEC_P (bfdp); DEF_VEC_P (bfdp);
@@ -138,6 +140,177 @@ eq_bfd (const void *a, const void *b)
/* See gdb_bfd.h. */ /* 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 * struct bfd *
gdb_bfd_open (const char *name, const char *target, int fd) 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 gdb_bfd_cache_search search;
struct stat st; 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) if (gdb_bfd_cache == NULL)
gdb_bfd_cache = htab_create_alloc (1, hash_bfd, eq_bfd, NULL, gdb_bfd_cache = htab_create_alloc (1, hash_bfd, eq_bfd, NULL,
xcalloc, xfree); xcalloc, xfree);

View File

@@ -24,11 +24,32 @@
DECLARE_REGISTRY (bfd); 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. /* Open a read-only (FOPEN_RB) BFD given arguments like bfd_fopen.
Returns NULL on error. On success, returns a new reference to the If NAME starts with TARGET_SYSROOT_PREFIX then the BFD will be
BFD, which must be freed with gdb_bfd_unref. BFDs returned by this opened using target fileio operations if necessary. Returns NULL
call are shared among all callers opening the same file. If FD is on error. On success, returns a new reference to the BFD, which
not -1, then after this call it is owned by BFD. */ 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); struct bfd *gdb_bfd_open (const char *name, const char *target, int fd);