This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[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;


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]