diff options
-rw-r--r-- | bfd/ChangeLog | 21 | ||||
-rw-r--r-- | bfd/bfd-in2.h | 22 | ||||
-rw-r--r-- | bfd/bfd.c | 10 | ||||
-rw-r--r-- | bfd/bfdio.c | 102 | ||||
-rw-r--r-- | bfd/cache.c | 107 | ||||
-rw-r--r-- | bfd/libbfd.h | 21 | ||||
-rw-r--r-- | bfd/opncls.c | 185 |
7 files changed, 388 insertions, 80 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 279a97c..23cc010 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,5 +1,26 @@ 2004-04-21 Andrew Cagney <cagney@redhat.com> + * opncls.c (_bfd_new_bfd_contained_in): Copy "iovec". + (struct opncls, opncls_btell, opncls_bseek, opncls_bread) + (opncls_bwrite, opncls_bclose, opncls_bflush) + (opncls_bstat, opncls_iovec, bfd_openr_iovec): Implement a + bfd iovec that uses function callbacks. + (bfd_close): Use the iovec's bclose. + * cache.c (cache_btell, cache_bseek, cache_bread, cache_bwrite) + (cache_bclose, cache_bflush, cache_bstat) + (cache_iovec): New functions and global variable, implement a + cache "iovec", where applicable set bfd_error. + (bfd_cache_init, bfd_cache_close): Set/test the bfd's iovec. + * bfdio.c (struct bfd_iovec): Define. + (real_read): Delete function. + (bfd_bread, bfd_bread, bfd_bwrite, bfd_tell, bfd_flush, bfd_stat) + (bfd_seek, bfd_get_mtime, bfd_get_size): Use the bfd's "iovec", + assume that bread and bwrite set bfd_error. + * bfd.c (struct bfd): Add "iovec", update comments. + * bfd-in2.h, libbfd.h: Re-generate. + +2004-04-21 Andrew Cagney <cagney@redhat.com> + * libaout.h (enum machine_type): Add M_POWERPC_NETBSD. 2004-04-21 Eric Botcazou <ebotcazou@act-europe.fr> diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 07af231..49e22b4 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -839,6 +839,18 @@ bfd *bfd_fdopenr (const char *filename, const char *target, int fd); bfd *bfd_openstreamr (const char *, const char *, void *); +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)); + bfd *bfd_openw (const char *filename, const char *target); bfd_boolean bfd_close (bfd *abfd); @@ -3708,14 +3720,10 @@ struct bfd /* 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_iovec *iovec; /* Is the file descriptor being cached? That is, can it be closed as needed, and re-opened when accessed later? */ @@ -45,14 +45,10 @@ CODE_FRAGMENT . {* 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_iovec *iovec; . . {* Is the file descriptor being cached? That is, can it be closed as . needed, and re-opened when accessed later? *} diff --git a/bfd/bfdio.c b/bfd/bfdio.c index a90cb33..53534f4 100644 --- a/bfd/bfdio.c +++ b/bfd/bfdio.c @@ -62,37 +62,41 @@ real_fseek (FILE *file, file_ptr offset, int whence) #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_iovec - 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 -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; + The <<struct bfd_iovec>> contains the internal file I/O class. + Each <<BFD>> has an instance of this class and all file I/O is + routed through it (it is assumed that the instance implements + all methods listed below). + +.struct bfd_iovec +.{ +. {* To avoid problems with macros, a "b" rather than "f" +. prefix is prepended to each method name. *} +. {* Attempt to read/write NBYTES on ABFD's IOSTREAM storing/fetching +. bytes starting at PTR. Return the number of bytes actually +. transfered (a read past end-of-file returns less than NBYTES), +. or -1 (setting <<bfd_error>>) if an error occurs. *} +. file_ptr (*bread) (struct bfd *abfd, void *ptr, file_ptr nbytes); +. file_ptr (*bwrite) (struct bfd *abfd, const void *ptr, +. file_ptr nbytes); +. {* Return the current IOSTREAM file offset, or -1 (setting <<bfd_error>> +. if an error occurs. *} +. file_ptr (*btell) (struct bfd *abfd); +. {* For the following, on successful completion a value of 0 is returned. +. Otherwise, a value of -1 is returned (and <<bfd_error>> is set). *} +. int (*bseek) (struct bfd *abfd, file_ptr offset, int whence); +. int (*bclose) (struct bfd *abfd); +. int (*bflush) (struct bfd *abfd); +. int (*bstat) (struct bfd *abfd, struct stat *sb); +.}; +*/ -#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. */ @@ -121,25 +125,10 @@ bfd_bread (void *ptr, bfd_size_type size, bfd *abfd) 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; - /* Set bfd_error if we did not read as much data as we expected. - - If the read failed due to an error set the bfd_error_system_call, - else set bfd_error_file_truncated. - - A BFD backend may wish to override bfd_error_file_truncated to - provide something more useful (eg. no_symbols or wrong_format). */ - if (nread != size) - { - if (ferror (bfd_cache_lookup (abfd))) - bfd_set_error (bfd_error_system_call); - else - bfd_set_error (bfd_error_file_truncated); - } - return nread; } @@ -175,7 +164,7 @@ bfd_bwrite (const void *ptr, bfd_size_type size, bfd *abfd) 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 +185,7 @@ bfd_tell (bfd *abfd) 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 +198,7 @@ bfd_flush (bfd *abfd) { 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 +206,12 @@ bfd_flush (bfd *abfd) 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 +224,6 @@ int 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 @@ -328,12 +309,11 @@ bfd_seek (bfd *abfd, file_ptr position, int direction) 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 +358,12 @@ DESCRIPTION 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 +406,12 @@ DESCRIPTION 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; diff --git a/bfd/cache.c b/bfd/cache.c index 7d056ea..9146c05 100644 --- a/bfd/cache.c +++ b/bfd/cache.c @@ -44,6 +44,109 @@ SECTION 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) +{ + file_ptr nread; + /* 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. */ + nread = read (fileno (bfd_cache_lookup (abfd)), buf, nbytes); + /* Set bfd_error if we did not read as much data as we expected. If + the read failed due to an error set the bfd_error_system_call, + else set bfd_error_file_truncated. */ + if (nread == (file_ptr)-1) + { + bfd_set_error (bfd_error_system_call); + return -1; + } +#else + nread = fread (buf, 1, nbytes, bfd_cache_lookup (abfd)); + /* Set bfd_error if we did not read as much data as we expected. If + the read failed due to an error set the bfd_error_system_call, + else set bfd_error_file_truncated. */ + if (nread < nbytes && ferror (bfd_cache_lookup (abfd))) + { + bfd_set_error (bfd_error_system_call); + return -1; + } +#endif + return nread; +} + +static file_ptr +cache_bwrite (struct bfd *abfd, const void *where, file_ptr nbytes) +{ + file_ptr nwrite = fwrite (where, 1, nbytes, bfd_cache_lookup (abfd)); + if (nwrite < nbytes && ferror (bfd_cache_lookup (abfd))) + { + bfd_set_error (bfd_error_system_call); + return -1; + } + return nwrite; +} + +static int +cache_bclose (struct bfd *abfd) +{ + return bfd_cache_close (abfd); +} + +static int +cache_bflush (struct bfd *abfd) +{ + int sts = fflush (bfd_cache_lookup (abfd)); + if (sts < 0) + bfd_set_error (bfd_error_system_call); + return sts; +} + +static int +cache_bstat (struct bfd *abfd, struct stat *sb) +{ + int sts = fstat (fileno (bfd_cache_lookup (abfd)), sb); + if (sts < 0) + bfd_set_error (bfd_error_system_call); + return sts; +} + +static const struct bfd_iovec cache_iovec = { + &cache_bread, &cache_bwrite, &cache_btell, &cache_bseek, + &cache_bclose, &cache_bflush, &cache_bstat +}; + /* INTERNAL_FUNCTION BFD_CACHE_MAX_OPEN macro @@ -205,6 +308,7 @@ bfd_cache_init (bfd *abfd) if (! close_one ()) return FALSE; } + abfd->iovec = &cache_iovec; insert (abfd); ++open_files; return TRUE; @@ -229,8 +333,7 @@ RETURNS bfd_boolean bfd_cache_close (bfd *abfd) { - if (abfd->iostream == NULL - || (abfd->flags & BFD_IN_MEMORY) != 0) + if (abfd->iovec != &cache_iovec) return TRUE; return bfd_cache_delete (abfd); diff --git a/bfd/libbfd.h b/bfd/libbfd.h index 6afe58d..b4bc9f8 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -657,6 +657,27 @@ bfd_boolean bfd_write_bigendian_4byte_int (bfd *, unsigned int); unsigned int bfd_log2 (bfd_vma x); /* Extracted from bfdio.c. */ +struct bfd_iovec +{ + /* To avoid problems with macros, a "b" rather than "f" + prefix is prepended to each method name. */ + /* Attempt to read/write NBYTES on ABFD's IOSTREAM storing/fetching + bytes starting at PTR. Return the number of bytes actually + transfered (a read past end-of-file returns less than NBYTES), + or -1 (setting <<bfd_error>>) if an error occurs. */ + file_ptr (*bread) (struct bfd *abfd, void *ptr, file_ptr nbytes); + file_ptr (*bwrite) (struct bfd *abfd, const void *ptr, + file_ptr nbytes); + /* Return the current IOSTREAM file offset, or -1 (setting <<bfd_error>> + if an error occurs. */ + file_ptr (*btell) (struct bfd *abfd); + /* For the following, on successful completion a value of 0 is returned. + Otherwise, a value of -1 is returned (and <<bfd_error>> is set). */ + int (*bseek) (struct bfd *abfd, file_ptr offset, int whence); + int (*bclose) (struct bfd *abfd); + int (*bflush) (struct bfd *abfd); + int (*bstat) (struct bfd *abfd, struct stat *sb); +}; /* Extracted from bfdwin.c. */ struct _bfd_window_internal { struct _bfd_window_internal *next; diff --git a/bfd/opncls.c b/bfd/opncls.c index 6abd405..3291cba 100644 --- a/bfd/opncls.c +++ b/bfd/opncls.c @@ -103,6 +103,7 @@ _bfd_new_bfd_contained_in (bfd *obfd) 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,183 @@ bfd_openstreamr (const char *filename, const char *target, void *streamarg) 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 a read-only @var{stream}. + The @var{stream} is created using @var{open}, accessed using + @var{pread} and destroyed using @var{close}. + + Calls <<bfd_find_target>>, so @var{target} is interpreted as by + that function. + + Calls @var{open} (which can call <<bfd_zalloc>> and + <<bfd_get_filename>>) to obtain the read-only stream backing + the BFD. @var{open} either succeeds returning the + non-<<NULL>> @var{stream}, or fails returning <<NULL>> + (setting <<bfd_error>>). + + Calls @var{pread} to request @var{nbytes} of data from + @var{stream} starting at @var{offset} (e.g., via a call to + <<bfd_read>>). @var{pread} either succeeds returning the + number of bytes read (which can be less than @var{nbytes} when + end-of-file), or fails returning -1 (setting <<bfd_error>>). + + Calls @var{close} when the BFD is later closed using + <<bfd_close>>. @var{close} either succeeds returning 0, or + fails returning -1 (setting <<bfd_error>>). + + If <<bfd_openr_iovec>> returns <<NULL>> then an error has + occurred. Possible errors are <<bfd_error_no_memory>>, + <<bfd_error_invalid_target>> and <<bfd_error_system_call>>. + +*/ + +struct opncls +{ + 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 +opncls_btell (struct bfd *abfd) +{ + struct opncls *vec = abfd->iostream; + return vec->where; +} + +static int +opncls_bseek (struct bfd *abfd, file_ptr offset, int whence) +{ + struct opncls *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 +opncls_bread (struct bfd *abfd, void *buf, file_ptr nbytes) +{ + struct opncls *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 +opncls_bwrite (struct bfd *abfd ATTRIBUTE_UNUSED, + const void *where ATTRIBUTE_UNUSED, + file_ptr nbytes ATTRIBUTE_UNUSED) +{ + return -1; +} + +static int +opncls_bclose (struct bfd *abfd) +{ + struct opncls *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 +opncls_bflush (struct bfd *abfd ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +opncls_bstat (struct bfd *abfd ATTRIBUTE_UNUSED, struct stat *sb) +{ + memset (sb, 0, sizeof (*sb)); + return 0; +} + +static const struct bfd_iovec opncls_iovec = { + &opncls_bread, &opncls_bwrite, &opncls_btell, &opncls_bseek, + &opncls_bclose, &opncls_bflush, &opncls_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 opncls *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 opncls)); + vec->stream = stream; + vec->pread = pread; + vec->close = close; + + nbfd->iovec = &opncls_iovec; + nbfd->iostream = vec; + + return nbfd; +} /* bfd_openw -- open for writing. Returns a pointer to a freshly-allocated BFD on success, or NULL. @@ -415,7 +593,12 @@ bfd_close (bfd *abfd) 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. */ |