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.
This commit is contained in:
Andrew Cagney 2004-04-21 17:05:12 +00:00
parent 7f919c8471
commit 40838a725a
7 changed files with 388 additions and 80 deletions

View file

@ -1,3 +1,24 @@
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.

View file

@ -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? */

View file

@ -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? *}

View file

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

View file

@ -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);

View file

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

View file

@ -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. */