This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[RFC] Implement bfd_iovec for BFD_IN_MEMORY
- From: dje at google dot com (Doug Evans)
- To: binutils at sourceware dot org
- Date: Thu, 23 Jul 2009 23:55:57 -0700 (PDT)
- Subject: [RFC] Implement bfd_iovec for BFD_IN_MEMORY
Hi.
Here is a first pass at a bfd_iovec for BFD_IN_MEMORY objects.
This patch seems reasonable.
But I haven't tested anything other than ELF.
And I don't discount the possibility that I'm missing something. :-)
2009-07-23 Doug Evans <dje@google.com>
Implement an iovec for BFD_IN_MEMORY.
* bfdio.c (bfd_bread): Move BFD_IN_MEMORY support to bim_bread.
(bfd_bwrite): Similarly move to bim_bwrite.
(bfd_tell): Similarly move to bim_btell.
(bfd_seek): Similarly move to bim_bseek.
(bfd_stat): Don't abort for BFD_IN_MEMORY.
(bfd_get_size): Remove BFD_IN_MEMORY special case.
(bfd_mmap): Ditto.
(bim_bread, bim_bwrite, bim_btell, bim_bseek): New functions.
(bim_close, bim_bflush, bim_bstat, bim_bmmap): New functions.
(bfd_in_memory_iovec): New global.
* libbfd.h: Regenerate.
* opncls.c (bfd_close): Remove BFD_IN_MEMORY special case.
* coff-alpha.c (alpha_ecoff_get_elt_at_filepos): Set iovec.
* elfcode.h (_bfd_elf,bfd_from_remote_memory): Ditto.
* peicode.h (pe_ILF_build_a_bfd): Ditto.
* xcofflink.c (bfd_xcoff_link_generate_rtinit): Ditto.
Index: bfdio.c
===================================================================
RCS file: /cvs/src/src/bfd/bfdio.c,v
retrieving revision 1.23
diff -u -p -r1.23 bfdio.c
--- bfdio.c 10 Jul 2009 18:38:27 -0000 1.23
+++ bfdio.c 24 Jul 2009 06:25:55 -0000
@@ -182,26 +182,6 @@ bfd_bread (void *ptr, bfd_size_type size
size = maxbytes;
}
- if ((abfd->flags & BFD_IN_MEMORY) != 0)
- {
- struct bfd_in_memory *bim;
- bfd_size_type get;
-
- bim = abfd->iostream;
- get = size;
- if (abfd->where + get > bim->size)
- {
- if (bim->size < (bfd_size_type) abfd->where)
- get = 0;
- else
- get = bim->size - abfd->where;
- bfd_set_error (bfd_error_file_truncated);
- }
- memcpy (ptr, bim->buffer + abfd->where, (size_t) get);
- abfd->where += get;
- return get;
- }
-
if (abfd->iovec)
nread = abfd->iovec->bread (abfd, ptr, size);
else
@@ -217,35 +197,9 @@ bfd_bwrite (const void *ptr, bfd_size_ty
{
size_t nwrote;
- if ((abfd->flags & BFD_IN_MEMORY) != 0)
- {
- struct bfd_in_memory *bim = abfd->iostream;
-
- size = (size_t) size;
- if (abfd->where + size > bim->size)
- {
- bfd_size_type newsize, oldsize;
-
- oldsize = (bim->size + 127) & ~(bfd_size_type) 127;
- bim->size = abfd->where + size;
- /* Round up to cut down on memory fragmentation */
- newsize = (bim->size + 127) & ~(bfd_size_type) 127;
- if (newsize > oldsize)
- {
- bim->buffer = bfd_realloc_or_free (bim->buffer, newsize);
- if (bim->buffer == NULL)
- {
- bim->size = 0;
- return 0;
- }
- if (newsize > bim->size)
- memset (bim->buffer + bim->size, 0, newsize - bim->size);
- }
- }
- memcpy (bim->buffer + abfd->where, ptr, (size_t) size);
- abfd->where += size;
- return size;
- }
+ /* Some iovecs, e.g. bfd_in_memory_iovec, call bfd_set_error.
+ Preserve any error that they flag. */
+ bfd_set_error (bfd_error_no_error);
if (abfd->iovec)
nwrote = abfd->iovec->bwrite (abfd, ptr, size);
@@ -256,11 +210,15 @@ bfd_bwrite (const void *ptr, bfd_size_ty
abfd->where += nwrote;
if (nwrote != size)
{
+ if (bfd_get_error () == bfd_error_no_error)
+ {
#ifdef ENOSPC
- errno = ENOSPC;
+ errno = ENOSPC;
#endif
- bfd_set_error (bfd_error_system_call);
+ bfd_set_error (bfd_error_system_call);
+ }
}
+
return nwrote;
}
@@ -269,9 +227,6 @@ bfd_tell (bfd *abfd)
{
file_ptr ptr;
- if ((abfd->flags & BFD_IN_MEMORY) != 0)
- return abfd->where;
-
if (abfd->iovec)
{
ptr = abfd->iovec->btell (abfd);
@@ -289,9 +244,6 @@ bfd_tell (bfd *abfd)
int
bfd_flush (bfd *abfd)
{
- if ((abfd->flags & BFD_IN_MEMORY) != 0)
- return 0;
-
if (abfd->iovec)
return abfd->iovec->bflush (abfd);
return 0;
@@ -304,9 +256,6 @@ bfd_stat (bfd *abfd, struct stat *statbu
{
int result;
- if ((abfd->flags & BFD_IN_MEMORY) != 0)
- abort ();
-
if (abfd->iovec)
result = abfd->iovec->bstat (abfd, statbuf);
else
@@ -334,49 +283,6 @@ bfd_seek (bfd *abfd, file_ptr position,
if (direction == SEEK_CUR && position == 0)
return 0;
- if ((abfd->flags & BFD_IN_MEMORY) != 0)
- {
- struct bfd_in_memory *bim;
-
- bim = abfd->iostream;
-
- if (direction == SEEK_SET)
- abfd->where = position;
- else
- abfd->where += position;
-
- if (abfd->where > bim->size)
- {
- if (abfd->direction == write_direction
- || abfd->direction == both_direction)
- {
- bfd_size_type newsize, oldsize;
-
- oldsize = (bim->size + 127) & ~(bfd_size_type) 127;
- bim->size = abfd->where;
- /* Round up to cut down on memory fragmentation */
- newsize = (bim->size + 127) & ~(bfd_size_type) 127;
- if (newsize > oldsize)
- {
- bim->buffer = bfd_realloc_or_free (bim->buffer, newsize);
- if (bim->buffer == NULL)
- {
- bim->size = 0;
- return -1;
- }
- memset (bim->buffer + oldsize, 0, newsize - oldsize);
- }
- }
- else
- {
- abfd->where = bim->size;
- bfd_set_error (bfd_error_file_truncated);
- return -1;
- }
- }
- return 0;
- }
-
if (abfd->format != bfd_archive && abfd->my_archive == 0)
{
if (direction == SEEK_SET && (bfd_vma) position == abfd->where)
@@ -401,6 +307,10 @@ bfd_seek (bfd *abfd, file_ptr position,
if (direction == SEEK_SET && abfd->my_archive != NULL)
file_position += abfd->origin;
+ /* Some iovecs, e.g. bfd_in_memory_iovec, call bfd_set_error.
+ Preserve any error that they flag. */
+ bfd_set_error (bfd_error_no_error);
+
if (abfd->iovec)
result = abfd->iovec->bseek (abfd, file_position, direction);
else
@@ -408,20 +318,22 @@ bfd_seek (bfd *abfd, file_ptr position,
if (result != 0)
{
+ bfd_error_type hold_error = bfd_get_error ();
int hold_errno = errno;
/* Force redetermination of `where' field. */
bfd_tell (abfd);
+ /* First, preserve the error that the iovec flagged, if any. */
+ if (hold_error != bfd_error_no_error)
+ bfd_set_error (hold_error);
/* An EINVAL error probably means that the file offset was
absurd. */
- if (hold_errno == EINVAL)
+ else if (hold_errno == EINVAL)
bfd_set_error (bfd_error_file_truncated);
else
- {
- bfd_set_error (bfd_error_system_call);
- errno = hold_errno;
- }
+ bfd_set_error (bfd_error_system_call);
+ errno = hold_errno;
}
else
{
@@ -503,9 +415,6 @@ bfd_get_size (bfd *abfd)
{
struct stat buf;
- if ((abfd->flags & BFD_IN_MEMORY) != 0)
- return ((struct bfd_in_memory *) abfd->iostream)->size;
-
if (abfd->iovec == NULL)
return 0;
@@ -534,11 +443,223 @@ bfd_mmap (bfd *abfd, void *addr, bfd_siz
int prot, int flags, file_ptr offset)
{
void *ret = (void *)-1;
- if ((abfd->flags & BFD_IN_MEMORY) != 0)
- return ret;
if (abfd->iovec == NULL)
return ret;
return abfd->iovec->bmmap (abfd, addr, len, prot, flags, offset);
}
+
+/* bfd_iovec for BFD_IN_MEMORY */
+
+static file_ptr
+bim_bread (struct bfd *abfd, void *ptr, file_ptr nbytes)
+{
+ struct bfd_in_memory *bim;
+ bfd_size_type get;
+
+ BFD_ASSERT ((abfd->flags & BFD_IN_MEMORY) != 0);
+
+ bim = abfd->iostream;
+ get = nbytes;
+ if (abfd->where + get > bim->size)
+ {
+ if (bim->size < (bfd_size_type) abfd->where)
+ get = 0;
+ else
+ get = bim->size - abfd->where;
+ bfd_set_error (bfd_error_file_truncated);
+ }
+ memcpy (ptr, bim->buffer + abfd->where, (size_t) get);
+
+ return get;
+}
+
+static file_ptr
+bim_bwrite (struct bfd *abfd, const void *ptr, file_ptr nbytes)
+{
+ struct bfd_in_memory *bim = abfd->iostream;
+ bfd_size_type size;
+
+ BFD_ASSERT ((abfd->flags & BFD_IN_MEMORY) != 0);
+
+ size = (size_t) nbytes;
+ if (abfd->where + size > bim->size)
+ {
+ bfd_size_type newsize, oldsize;
+
+ oldsize = (bim->size + 127) & ~(bfd_size_type) 127;
+ bim->size = abfd->where + size;
+ /* Round up to cut down on memory fragmentation. */
+ newsize = (bim->size + 127) & ~(bfd_size_type) 127;
+ if (newsize > oldsize)
+ {
+ bim->buffer = bfd_realloc_or_free (bim->buffer, newsize);
+ if (bim->buffer == NULL)
+ {
+ bim->size = 0;
+ return 0;
+ }
+ if (newsize > bim->size)
+ memset (bim->buffer + bim->size, 0, newsize - bim->size);
+ }
+ }
+ memcpy (bim->buffer + abfd->where, ptr, (size_t) size);
+
+ return size;
+}
+
+static file_ptr
+bim_btell (struct bfd *abfd)
+{
+ BFD_ASSERT ((abfd->flags & BFD_IN_MEMORY) != 0);
+
+ return abfd->where;
+}
+
+static int
+bim_bseek (struct bfd *abfd, file_ptr offset, int whence)
+{
+ struct bfd_in_memory *bim = abfd->iostream;
+ ufile_ptr position;
+
+ BFD_ASSERT ((abfd->flags & BFD_IN_MEMORY) != 0);
+
+ /* Don't update abfd->where yet, leave that to the caller. */
+ if (whence == SEEK_SET)
+ {
+ if (offset < 0)
+ {
+ errno = EINVAL;
+ bfd_set_error (bfd_error_system_call);
+ return -1;
+ }
+ position = offset;
+ }
+ else
+ {
+ position = abfd->where + offset;
+ if ((offset > 0
+ && position < abfd->where)
+ || (offset < 0
+ && position > abfd->where))
+ {
+ errno = EINVAL;
+ bfd_set_error (bfd_error_system_call);
+ return -1;
+ }
+ }
+
+ if (position > bim->size)
+ {
+ if (abfd->direction == write_direction
+ || abfd->direction == both_direction)
+ {
+ bfd_size_type newsize, oldsize;
+
+ oldsize = (bim->size + 127) & ~(bfd_size_type) 127;
+ bim->size = position;
+ /* Round up to cut down on memory fragmentation */
+ newsize = (bim->size + 127) & ~(bfd_size_type) 127;
+ if (newsize > oldsize)
+ {
+ bim->buffer = bfd_realloc_or_free (bim->buffer, newsize);
+ if (bim->buffer == NULL)
+ {
+ bim->size = 0;
+ abfd->where = 0;
+ return -1;
+ }
+ memset (bim->buffer + oldsize, 0, newsize - oldsize);
+ }
+ }
+ else
+ {
+ abfd->where = bim->size;
+ errno = EINVAL;
+ bfd_set_error (bfd_error_file_truncated);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int
+bim_bclose (struct bfd *abfd)
+{
+ struct bfd_in_memory *bim = abfd->iostream;
+
+ BFD_ASSERT ((abfd->flags & BFD_IN_MEMORY) != 0);
+
+ free (bim->buffer);
+ free (bim);
+
+ /* ??? Documentation says to return 0 for success, but all existing
+ uses return TRUE. */
+ return TRUE;
+}
+
+static int
+bim_bflush (struct bfd *abfd)
+{
+ BFD_ASSERT ((abfd->flags & BFD_IN_MEMORY) != 0);
+
+ return 0;
+}
+
+/* ??? This is needed for bfd_get_size.
+ Previous versions aborted if bfd_stat was called on a BFD_IN_MEMORY object.
+ Maybe the thing to do is add a get_size routine to bfd_iovec, but that
+ seems excessive. */
+
+static int
+bim_bstat (struct bfd *abfd, struct stat *sb)
+{
+ struct bfd_in_memory *bim = abfd->iostream;
+
+ BFD_ASSERT ((abfd->flags & BFD_IN_MEMORY) != 0);
+
+ memset (sb, 0, sizeof (*sb));
+ sb->st_size = bim->size;
+
+ /* ??? bfd_get_mtime also uses iovec->bstat.
+ BFD_IN_MEMORY objects set abfd->mtime_set, so we shouldn't get here
+ for bfd_get_mtime. OTOH, we could add mtime to struct bfd_in_memory.
+ For now just propagate abfd->mtime if it's set. */
+ if (abfd->mtime_set)
+ sb->st_mtime = abfd->mtime;
+
+ return 0;
+}
+
+static void *
+bim_bmmap (struct bfd *abfd,
+ void *addr ATTRIBUTE_UNUSED,
+ bfd_size_type len ATTRIBUTE_UNUSED,
+ int prot ATTRIBUTE_UNUSED,
+ int flags ATTRIBUTE_UNUSED,
+ file_ptr offset ATTRIBUTE_UNUSED)
+{
+ BFD_ASSERT ((abfd->flags & BFD_IN_MEMORY) != 0);
+
+ return (void *) -1;
+}
+
+/*
+INTERNAL_DEFINITION
+ bfd_in_memory_iovec
+
+DESCRIPTION
+ The <<bfd_in_memory_iovec>> is an item of
+ <<bfd_iovec>> which is used to perform i/o operations on
+ BFD_IN_MEMORY bfds.
+
+.extern const struct bfd_iovec bfd_in_memory_iovec;
+*/
+
+const struct bfd_iovec bfd_in_memory_iovec =
+{
+ &bim_bread, &bim_bwrite, &bim_btell, &bim_bseek,
+ &bim_bclose, &bim_bflush, &bim_bstat, &bim_bmmap
+};
Index: coff-alpha.c
===================================================================
RCS file: /cvs/src/src/bfd/coff-alpha.c,v
retrieving revision 1.40
diff -u -p -r1.40 coff-alpha.c
--- coff-alpha.c 16 Apr 2009 23:06:58 -0000 1.40
+++ coff-alpha.c 24 Jul 2009 06:25:55 -0000
@@ -2225,6 +2225,7 @@ alpha_ecoff_get_elt_at_filepos (archive,
nbfd->flags |= BFD_IN_MEMORY;
nbfd->iostream = (PTR) bim;
+ nbfd->iovec = &bfd_in_memory_iovec;
BFD_ASSERT (! nbfd->cacheable);
return nbfd;
Index: elfcode.h
===================================================================
RCS file: /cvs/src/src/bfd/elfcode.h,v
retrieving revision 1.94
diff -u -p -r1.94 elfcode.h
--- elfcode.h 30 Apr 2009 15:47:10 -0000 1.94
+++ elfcode.h 24 Jul 2009 06:25:55 -0000
@@ -1801,6 +1801,7 @@ NAME(_bfd_elf,bfd_from_remote_memory)
}
nbfd->filename = "<in-memory>";
nbfd->xvec = templ->xvec;
+ nbfd->iovec = &bfd_in_memory_iovec;
bim->size = contents_size;
bim->buffer = contents;
nbfd->iostream = bim;
Index: libbfd.h
===================================================================
RCS file: /cvs/src/src/bfd/libbfd.h,v
retrieving revision 1.219
diff -u -p -r1.219 libbfd.h
--- libbfd.h 12 Jun 2009 09:15:45 -0000 1.219
+++ libbfd.h 24 Jul 2009 06:25:55 -0000
@@ -777,6 +777,7 @@ struct bfd_iovec
void *(*bmmap) (struct bfd *abfd, void *addr, bfd_size_type len,
int prot, int flags, file_ptr offset);
};
+extern const struct bfd_iovec bfd_in_memory_iovec;
/* Extracted from bfdwin.c. */
struct _bfd_window_internal {
struct _bfd_window_internal *next;
Index: opncls.c
===================================================================
RCS file: /cvs/src/src/bfd/opncls.c,v
retrieving revision 1.55
diff -u -p -r1.55 opncls.c
--- opncls.c 12 Jun 2009 12:04:19 -0000 1.55
+++ opncls.c 24 Jul 2009 06:25:55 -0000
@@ -703,12 +703,7 @@ bfd_close (bfd *abfd)
if (! BFD_SEND (abfd, _close_and_cleanup, (abfd)))
return FALSE;
- /* FIXME: cagney/2004-02-15: Need to implement a BFD_IN_MEMORY io
- vector. */
- if (!(abfd->flags & BFD_IN_MEMORY))
- ret = abfd->iovec->bclose (abfd);
- else
- ret = TRUE;
+ ret = abfd->iovec->bclose (abfd);
if (ret)
_maybe_make_executable (abfd);
Index: peicode.h
===================================================================
RCS file: /cvs/src/src/bfd/peicode.h,v
retrieving revision 1.58
diff -u -p -r1.58 peicode.h
--- peicode.h 21 Apr 2009 17:08:20 -0000 1.58
+++ peicode.h 24 Jul 2009 06:25:55 -0000
@@ -1001,6 +1001,7 @@ pe_ILF_build_a_bfd (bfd * abfd
bfd_cache_close (abfd);
abfd->iostream = (void *) vars.bim;
+ abfd->iovec = &bfd_in_memory_iovec;
abfd->flags |= BFD_IN_MEMORY /* | HAS_LOCALS */;
abfd->where = 0;
obj_sym_filepos (abfd) = 0;
Index: xcofflink.c
===================================================================
RCS file: /cvs/src/src/bfd/xcofflink.c,v
retrieving revision 1.69
diff -u -p -r1.69 xcofflink.c
--- xcofflink.c 2 Jun 2009 18:51:33 -0000 1.69
+++ xcofflink.c 24 Jul 2009 06:25:56 -0000
@@ -3975,6 +3975,7 @@ bfd_xcoff_link_generate_rtinit (bfd *abf
abfd->link_next = 0;
abfd->format = bfd_object;
abfd->iostream = (void *) bim;
+ abfd->iovec = &bfd_in_memory_iovec;
abfd->flags = BFD_IN_MEMORY;
abfd->direction = write_direction;
abfd->where = 0;