This is the mail archive of the binutils@sources.redhat.com 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]

Re: [wip] BFD from an arbitrary object; Was: provide pass-throughvalue in bfd_elf_bfd_from_remote_memory


Here's a revised work-in-progress. It is greatly simplified from the previous patch vis:

- it drops the published bfd_file interface

- it makes the iovec (struct bfd_io_vec) private to bfd

- it doesn't try to fix the bfd-in-memory code (later pass)

- it leaves all the cache.c structures in the bfd (later pass?)

- it publishes an interface for creating a read-only iovec backed bfd

+/*
+FUNCTION
+ bfd_openr_iovec
+
+SYNOPSIS
+ bfd *bfd_openr_iovec (const char *filename, const char *target,
+ void *(*open) (struct bfd *nbfd,
+ void *open_closure),
+ void *open_closure,
+ file_ptr (*pread) (struct bfd *nbfd,
+ void *stream,
+ void *buf,
+ file_ptr nbytes,
+ file_ptr offset),
+ int (*close) (struct bfd *nbfd,
+ void *stream));
+
+DESCRIPTION
+
+ Create and return a BFD backed by the read-only <<stream>>
+ returned by <<open>>.
+
+ Calls <<bfd_find_target>>, so @var{target} is interpreted as by
+ that function.
+
+ Calls <<open>> (which can call <<bfd_zalloc>> and
+ <<bfd_get_filename>>) to obtain to obtain the read-only stream
+ backing the BFD.
+
+ Any request for data from <<stream>> (e.g., by <<bfd_read>>)
+ is passed through to <<pread>>.
+
+ When the BFD is later <<bfd_close>>d, <<close>> is called.
+
+ If <<NULL>> is returned then an error has occurred. Possible errors
+ are <<bfd_error_no_memory>>, <<bfd_error_invalid_target>> or
+ <<system_call>> error.


This time everything still works. I also tested the interface by hacking objdump to use it.

Looking better?

Andrew
Index: bfd.c
===================================================================
RCS file: /cvs/src/src/bfd/bfd.c,v
retrieving revision 1.55
diff -u -r1.55 bfd.c
--- bfd.c	24 Nov 2003 18:06:39 -0000	1.55
+++ bfd.c	15 Feb 2004 17:33:49 -0000
@@ -45,14 +45,10 @@
 .  {* A pointer to the target jump table.  *}
 .  const struct bfd_target *xvec;
 .
-.  {* To avoid dragging too many header files into every file that
-.     includes `<<bfd.h>>', IOSTREAM has been declared as a "char *",
-.     and MTIME as a "long".  Their correct types, to which they
-.     are cast when used, are "FILE *" and "time_t".    The iostream
-.     is the result of an fopen on the filename.  However, if the
-.     BFD_IN_MEMORY flag is set, then iostream is actually a pointer
-.     to a bfd_in_memory struct.  *}
+.  {* The IOSTREAM, and corresponding IO vector that provide access
+.     to the file backing the BFD.  *}
 .  void *iostream;
+.  const struct bfd_io_vec *iovec;
 .
 .  {* Is the file descriptor being cached?  That is, can it be closed as
 .     needed, and re-opened when accessed later?  *}
Index: bfdio.c
===================================================================
RCS file: /cvs/src/src/bfd/bfdio.c,v
retrieving revision 1.5
diff -u -r1.5 bfdio.c
--- bfdio.c	11 Feb 2004 23:23:20 -0000	1.5
+++ bfdio.c	15 Feb 2004 17:33:51 -0000
@@ -62,38 +62,33 @@
 #endif
 }
 
-/* Note that archive entries don't have streams; they share their parent's.
-   This allows someone to play with the iostream behind BFD's back.
+/*
+INTERNAL_DEFINITION
+	struct bfd_io_vec
 
-   Also, note that the origin pointer points to the beginning of a file's
-   contents (0 for non-archive elements).  For archive entries this is the
-   first octet in the file, NOT the beginning of the archive header.  */
+DESCRIPTION
+	The <<struct bfd_io_vec>> contains the internal file I/O class.  Each
+	<<BFD>> has an instance of this class and all file I/O is
+	routed through it.
+
+.struct bfd_io_vec
+.{
+.  {* To avoid problems with macros, use a "b" rather than "f"
+.     prefix to each method name.  *}
+.  file_ptr (*bread) (struct bfd *abfd, void *ptr, file_ptr nbytes);
+.  file_ptr (*bwrite) (struct bfd *abfd, const void *ptr,
+.                      file_ptr nbytes);
+.  file_ptr (*btell) (struct bfd *abfd);
+.  int (*bseek) (struct bfd *abfd, file_ptr offset, int whence);
+.  int (*bclose) (struct bfd *abfd);
+.  int (*berror) (struct bfd *abfd);
+.  int (*bflush) (struct bfd *abfd);
+.  int (*bstat) (struct bfd *abfd, struct stat *sb);
+.};
 
-static size_t
-real_read (void *where, size_t a, size_t b, FILE *file)
-{
-  /* FIXME - this looks like an optimization, but it's really to cover
-     up for a feature of some OSs (not solaris - sigh) that
-     ld/pe-dll.c takes advantage of (apparently) when it creates BFDs
-     internally and tries to link against them.  BFD seems to be smart
-     enough to realize there are no symbol records in the "file" that
-     doesn't exist but attempts to read them anyway.  On Solaris,
-     attempting to read zero bytes from a NULL file results in a core
-     dump, but on other platforms it just returns zero bytes read.
-     This makes it to something reasonable. - DJ */
-  if (a == 0 || b == 0)
-    return 0;
+*/
 
 
-#if defined (__VAX) && defined (VMS)
-  /* Apparently fread on Vax VMS does not keep the record length
-     information.  */
-  return read (fileno (file), where, a * b);
-#else
-  return fread (where, a, b, file);
-#endif
-}
-
 /* Return value is amount read.  */
 
 bfd_size_type
@@ -121,7 +116,7 @@
       return get;
     }
 
-  nread = real_read (ptr, 1, (size_t) size, bfd_cache_lookup (abfd));
+  nread = abfd->iovec->bread (abfd, ptr, size);
   if (nread != (size_t) -1)
     abfd->where += nread;
 
@@ -134,7 +129,7 @@
      provide something more useful (eg. no_symbols or wrong_format).  */
   if (nread != size)
     {
-      if (ferror (bfd_cache_lookup (abfd)))
+      if (abfd->iovec->berror (abfd))
 	bfd_set_error (bfd_error_system_call);
       else
 	bfd_set_error (bfd_error_file_truncated);
@@ -175,7 +170,7 @@
       return size;
     }
 
-  nwrote = fwrite (ptr, 1, (size_t) size, bfd_cache_lookup (abfd));
+  nwrote = abfd->iovec->bwrite (abfd, ptr, size);
   if (nwrote != (size_t) -1)
     abfd->where += nwrote;
   if (nwrote != size)
@@ -196,7 +191,7 @@
   if ((abfd->flags & BFD_IN_MEMORY) != 0)
     return abfd->where;
 
-  ptr = real_ftell (bfd_cache_lookup (abfd));
+  ptr = abfd->iovec->btell (abfd);
 
   if (abfd->my_archive)
     ptr -= abfd->origin;
@@ -209,7 +204,7 @@
 {
   if ((abfd->flags & BFD_IN_MEMORY) != 0)
     return 0;
-  return fflush (bfd_cache_lookup(abfd));
+  return abfd->iovec->bflush (abfd);
 }
 
 /* Returns 0 for success, negative value for failure (in which case
@@ -217,19 +212,12 @@
 int
 bfd_stat (bfd *abfd, struct stat *statbuf)
 {
-  FILE *f;
   int result;
 
   if ((abfd->flags & BFD_IN_MEMORY) != 0)
     abort ();
 
-  f = bfd_cache_lookup (abfd);
-  if (f == NULL)
-    {
-      bfd_set_error (bfd_error_system_call);
-      return -1;
-    }
-  result = fstat (fileno (f), statbuf);
+  result = abfd->iovec->bstat (abfd, statbuf);
   if (result < 0)
     bfd_set_error (bfd_error_system_call);
   return result;
@@ -242,7 +230,6 @@
 bfd_seek (bfd *abfd, file_ptr position, int direction)
 {
   int result;
-  FILE *f;
   file_ptr file_position;
   /* For the time being, a BFD may not seek to it's end.  The problem
      is that we don't easily have a way to recognize the end of an
@@ -266,8 +253,8 @@
 
       if (abfd->where > bim->size)
 	{
-	  if ((abfd->direction == write_direction) ||
-	      (abfd->direction == both_direction))
+         if ((abfd->direction == write_direction) ||
+             (abfd->direction == both_direction))
 	    {
 	      bfd_size_type newsize, oldsize;
 	      oldsize = (bim->size + 127) & ~(bfd_size_type) 127;
@@ -328,12 +315,11 @@
 	 In the meantime, no optimization for archives.  */
     }
 
-  f = bfd_cache_lookup (abfd);
   file_position = position;
   if (direction == SEEK_SET && abfd->my_archive != NULL)
     file_position += abfd->origin;
 
-  result = real_fseek (f, file_position, direction);
+  result = abfd->iovec->bseek (abfd, file_position, direction);
   if (result != 0)
     {
       int hold_errno = errno;
@@ -378,14 +364,12 @@
 long
 bfd_get_mtime (bfd *abfd)
 {
-  FILE *fp;
   struct stat buf;
 
   if (abfd->mtime_set)
     return abfd->mtime;
 
-  fp = bfd_cache_lookup (abfd);
-  if (0 != fstat (fileno (fp), &buf))
+  if (abfd->iovec->bstat (abfd, &buf) != 0)
     return 0;
 
   abfd->mtime = buf.st_mtime;		/* Save value in case anyone wants it */
@@ -428,14 +412,12 @@
 long
 bfd_get_size (bfd *abfd)
 {
-  FILE *fp;
   struct stat buf;
 
   if ((abfd->flags & BFD_IN_MEMORY) != 0)
     return ((struct bfd_in_memory *) abfd->iostream)->size;
 
-  fp = bfd_cache_lookup (abfd);
-  if (0 != fstat (fileno (fp), & buf))
+  if (abfd->iovec->bstat (abfd, &buf) != 0)
     return 0;
 
   return buf.st_size;
Index: cache.c
===================================================================
RCS file: /cvs/src/src/bfd/cache.c,v
retrieving revision 1.11
diff -u -r1.11 cache.c
--- cache.c	11 Feb 2004 23:23:20 -0000	1.11
+++ cache.c	15 Feb 2004 17:33:52 -0000
@@ -44,6 +44,85 @@
 
 static bfd_boolean bfd_cache_delete (bfd *);
 
+
+static file_ptr
+cache_btell (struct bfd *abfd)
+{
+  return real_ftell (bfd_cache_lookup (abfd));
+}
+
+static int
+cache_bseek (struct bfd *abfd, file_ptr offset, int whence)
+{
+  return real_fseek (bfd_cache_lookup (abfd), offset, whence);
+}
+
+/* Note that archive entries don't have streams; they share their parent's.
+   This allows someone to play with the iostream behind BFD's back.
+
+   Also, note that the origin pointer points to the beginning of a file's
+   contents (0 for non-archive elements).  For archive entries this is the
+   first octet in the file, NOT the beginning of the archive header.  */
+
+static file_ptr
+cache_bread (struct bfd *abfd, void *buf, file_ptr nbytes)
+{
+  /* FIXME - this looks like an optimization, but it's really to cover
+     up for a feature of some OSs (not solaris - sigh) that
+     ld/pe-dll.c takes advantage of (apparently) when it creates BFDs
+     internally and tries to link against them.  BFD seems to be smart
+     enough to realize there are no symbol records in the "file" that
+     doesn't exist but attempts to read them anyway.  On Solaris,
+     attempting to read zero bytes from a NULL file results in a core
+     dump, but on other platforms it just returns zero bytes read.
+     This makes it to something reasonable. - DJ */
+  if (nbytes == 0)
+    return 0;
+
+#if defined (__VAX) && defined (VMS)
+  /* Apparently fread on Vax VMS does not keep the record length
+     information.  */
+  return read (fileno (bfd_cache_lookup (abfd)), buf, nbytes);
+#else
+  return fread (buf, 1, nbytes, bfd_cache_lookup (abfd));
+#endif
+}
+
+static file_ptr
+cache_bwrite (struct bfd *abfd, const void *where, file_ptr nbytes)
+{
+  return fwrite (where, 1, nbytes, bfd_cache_lookup (abfd));
+}
+
+static int
+cache_bclose (struct bfd *abfd)
+{
+  bfd_cache_close (abfd);
+}
+
+static int
+cache_berror (struct bfd *abfd)
+{
+  return ferror (bfd_cache_lookup (abfd));
+}
+
+static int
+cache_bflush (struct bfd *abfd)
+{
+  return fflush (bfd_cache_lookup (abfd));
+}
+
+static int
+cache_bstat (struct bfd *abfd, struct stat *sb)
+{
+  return fstat (fileno (bfd_cache_lookup (abfd)), sb);
+}
+
+static const struct bfd_io_vec cache_io_vec = {
+  &cache_bread, &cache_bwrite, &cache_btell, &cache_bseek,
+  &cache_bclose, &cache_berror, &cache_bflush, &cache_bstat
+};
+
 /*
 INTERNAL_FUNCTION
 	BFD_CACHE_MAX_OPEN macro
@@ -205,6 +284,7 @@
       if (! close_one ())
 	return FALSE;
     }
+  abfd->iovec = &cache_io_vec;
   insert (abfd);
   ++open_files;
   return TRUE;
@@ -229,8 +309,7 @@
 bfd_boolean
 bfd_cache_close (bfd *abfd)
 {
-  if (abfd->iostream == NULL
-      || (abfd->flags & BFD_IN_MEMORY) != 0)
+  if (abfd->iovec != &cache_io_vec)
     return TRUE;
 
   return bfd_cache_delete (abfd);
Index: opncls.c
===================================================================
RCS file: /cvs/src/src/bfd/opncls.c,v
retrieving revision 1.21
diff -u -r1.21 opncls.c
--- opncls.c	21 Jan 2004 11:17:53 -0000	1.21
+++ opncls.c	15 Feb 2004 17:33:53 -0000
@@ -103,6 +103,7 @@
   if (nbfd == NULL)
     return NULL;
   nbfd->xvec = obfd->xvec;
+  nbfd->iovec = obfd->iovec;
   nbfd->my_archive = obfd;
   nbfd->direction = read_direction;
   nbfd->target_defaulted = obfd->target_defaulted;
@@ -322,6 +323,181 @@
 
   return nbfd;
 }
+
+/*
+FUNCTION
+	bfd_openr_iovec
+
+SYNOPSIS
+        bfd *bfd_openr_iovec (const char *filename, const char *target,
+                              void *(*open) (struct bfd *nbfd,
+                                             void *open_closure),
+                              void *open_closure,
+                              file_ptr (*pread) (struct bfd *nbfd,
+                                                 void *stream,
+                                                 void *buf,
+                                                 file_ptr nbytes,
+                                                 file_ptr offset),
+                              int (*close) (struct bfd *nbfd,
+                                            void *stream));
+
+DESCRIPTION
+
+        Create and return a BFD backed by the read-only <<stream>>
+        returned by <<open>>.
+
+	Calls <<bfd_find_target>>, so @var{target} is interpreted as by
+	that function.
+
+	Calls <<open>> (which can call <<bfd_zalloc>> and
+	<<bfd_get_filename>>) to obtain to obtain the read-only stream
+	backing the BFD.
+
+	Any request for data from <<stream>> (e.g., by <<bfd_read>>)
+	is passed through to <<pread>>.
+
+	When the BFD is later <<bfd_close>>d, <<close>> is called.
+
+	If <<NULL>> is returned then an error has occurred.   Possible errors
+	are <<bfd_error_no_memory>>, <<bfd_error_invalid_target>> or
+	<<system_call>> error.
+
+*/
+
+struct iovec
+{
+  void *stream;
+  file_ptr (*pread) (struct bfd *abfd, void *stream, void *buf,
+		     file_ptr nbytes, file_ptr offset);
+  int (*close) (struct bfd *abfd, void *stream);
+  file_ptr where;
+};
+
+static file_ptr
+iovec_btell (struct bfd *abfd)
+{
+  struct iovec *vec = abfd->iostream;
+  return vec->where;
+}
+
+static int
+iovec_bseek (struct bfd *abfd, file_ptr offset, int whence)
+{
+  struct iovec *vec = abfd->iostream;
+  switch (whence)
+    {
+    case SEEK_SET: vec->where = offset; break;
+    case SEEK_CUR: vec->where += offset; break;
+    case SEEK_END: return -1;
+    }
+  return 0;
+}
+
+static file_ptr
+iovec_bread (struct bfd *abfd, void *buf, file_ptr nbytes)
+{
+  struct iovec *vec = abfd->iostream;
+  file_ptr nread = vec->pread (abfd, vec->stream, buf, nbytes, vec->where);
+  if (nread < 0)
+    return nread;
+  vec->where += nread;
+  return nread;
+}
+
+static file_ptr
+iovec_bwrite (struct bfd *abfd ATTRIBUTE_UNUSED,
+	      const void *where ATTRIBUTE_UNUSED,
+	      file_ptr nbytes ATTRIBUTE_UNUSED)
+{
+  return -1;
+}
+
+static int
+iovec_bclose (struct bfd *abfd)
+{
+  struct iovec *vec = abfd->iostream;
+  /* Since the VEC's memory is bound to the bfd deleting the bfd will
+     free it.  */
+  int status = 0;
+  if (vec->close != NULL)
+    status = vec->close (abfd, vec->stream);
+  abfd->iostream = NULL;
+  return status;
+}
+
+static int
+iovec_berror (struct bfd *abfd ATTRIBUTE_UNUSED)
+{
+  return 0;
+}
+
+static int
+iovec_bflush (struct bfd *abfd ATTRIBUTE_UNUSED)
+{
+  return 0;
+}
+
+static int
+iovec_bstat (struct bfd *abfd ATTRIBUTE_UNUSED, struct stat *sb)
+{
+  memset (sb, 0, sizeof (*sb));
+  return 0;
+}
+
+static const struct bfd_io_vec iovec_io_vec = {
+  &iovec_bread, &iovec_bwrite, &iovec_btell, &iovec_bseek,
+  &iovec_bclose, &iovec_berror, &iovec_bflush, &iovec_bstat
+};
+
+bfd *
+bfd_openr_iovec (const char *filename, const char *target,
+		 void *(*open) (struct bfd *nbfd,
+				void *open_closure),
+		 void *open_closure,
+		 file_ptr (*pread) (struct bfd *abfd,
+				    void *stream,
+				    void *buf,
+				    file_ptr nbytes,
+				    file_ptr offset),
+		 int (*close) (struct bfd *nbfd,
+			       void *stream))
+{
+  bfd *nbfd;
+  const bfd_target *target_vec;
+  struct iovec *vec;
+  void *stream;
+
+  nbfd = _bfd_new_bfd ();
+  if (nbfd == NULL)
+    return NULL;
+
+  target_vec = bfd_find_target (target, nbfd);
+  if (target_vec == NULL)
+    {
+      _bfd_delete_bfd (nbfd);
+      return NULL;
+    }
+
+  nbfd->filename = filename;
+  nbfd->direction = read_direction;
+
+  stream = open (nbfd, open_closure);
+  if (stream == NULL)
+    {
+      _bfd_delete_bfd (nbfd);
+      return NULL;
+    }
+
+  vec = bfd_zalloc (nbfd, sizeof (struct iovec));
+  vec->stream = stream;
+  vec->pread = pread;
+  vec->close = close;
+
+  nbfd->iovec = &iovec_io_vec;
+  nbfd->iostream = vec;
+
+  return nbfd;
+}
 
 /* bfd_openw -- open for writing.
    Returns a pointer to a freshly-allocated BFD on success, or NULL.
@@ -415,7 +591,12 @@
   if (! BFD_SEND (abfd, _close_and_cleanup, (abfd)))
     return FALSE;
 
-  ret = bfd_cache_close (abfd);
+  /* 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 = 0;
 
   /* If the file was open for writing and is now executable,
      make it so.  */

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