X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Fbfdio.c;h=5f144bc7f3fee833ff97924ec8f2e3eec37364b9;hb=ebe84f23d2f3c0cb145cc7b3acfb011a4c7df1c9;hp=f99fddd482981208350226df59056caf818c17ca;hpb=eac93a98e53859497dd70949b93dce6eb85fbace;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/bfdio.c b/bfd/bfdio.c index f99fddd482..5f144bc7f3 100644 --- a/bfd/bfdio.c +++ b/bfd/bfdio.c @@ -1,30 +1,34 @@ /* Low-level I/O routines for BFDs. - Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + + Copyright (C) 1990-2020 Free Software Foundation, Inc. + Written by Cygnus Support. -This file is part of BFD, the Binary File Descriptor library. + This file is part of BFD, the Binary File Descriptor library. -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ #include "sysdep.h" - +#include #include "bfd.h" #include "libbfd.h" - -#include +#include "aout/ar.h" +#if defined (_WIN32) +#include +#endif #ifndef S_IXUSR #define S_IXUSR 0100 /* Execute by owner. */ @@ -36,123 +40,225 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #define S_IXOTH 0001 /* Execute by others. */ #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. +#ifndef FD_CLOEXEC +#define FD_CLOEXEC 1 +#endif - 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. */ +file_ptr +_bfd_real_ftell (FILE *file) +{ +#if defined (HAVE_FTELLO64) + return ftello64 (file); +#elif defined (HAVE_FTELLO) + return ftello (file); +#else + return ftell (file); +#endif +} -static size_t -real_read (void *where, size_t a, size_t b, FILE *file) +int +_bfd_real_fseek (FILE *file, file_ptr offset, int whence) { - /* 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 (HAVE_FSEEKO64) + return fseeko64 (file, offset, whence); +#elif defined (HAVE_FSEEKO) + return fseeko (file, offset, whence); +#else + return fseek (file, offset, whence); +#endif +} + +/* Mark FILE as close-on-exec. Return FILE. FILE may be NULL, in + which case nothing is done. */ +static FILE * +close_on_exec (FILE *file) +{ +#if defined (HAVE_FILENO) && defined (F_GETFD) + if (file) + { + int fd = fileno (file); + int old = fcntl (fd, F_GETFD, 0); + if (old >= 0) + fcntl (fd, F_SETFD, old | FD_CLOEXEC); + } +#endif + return file; +} +FILE * +_bfd_real_fopen (const char *filename, const char *modes) +{ +#ifdef VMS + char *vms_attr; + + /* On VMS, fopen allows file attributes as optional arguments. + We need to use them but we'd better to use the common prototype. + In fopen-vms.h, they are separated from the mode with a comma. + Split here. */ + vms_attr = strchr (modes, ','); + if (vms_attr != NULL) + { + /* Attributes found. Split. */ + size_t modes_len = strlen (modes) + 1; + char attrs[modes_len + 1]; + char *at[3]; + int i; + + memcpy (attrs, modes, modes_len); + at[0] = attrs; + for (i = 0; i < 2; i++) + { + at[i + 1] = strchr (at[i], ','); + BFD_ASSERT (at[i + 1] != NULL); + *(at[i + 1]++) = 0; /* Replace ',' with a nul, and skip it. */ + } + return close_on_exec (fopen (filename, at[0], at[1], at[2])); + } -#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); +#elif defined (_WIN32) + size_t filelen = strlen (filename) + 1; + + if (filelen > MAX_PATH - 1) + { + FILE * file; + char * fullpath = (char *) malloc (filelen + 8); + int i; + + /* Add a Microsoft recommended prefix that + will allow the extra-long path to work. */ + strcpy (fullpath, "\\\\?\\"); + strcat (fullpath, filename); + + /* Convert any UNIX style path separators into the DOS form. */ + for (i = 0; fullpath[i]; i++) + { + if (IS_UNIX_DIR_SEPARATOR (fullpath[i])) + fullpath[i] = '\\'; + } + + file = close_on_exec (fopen (fullpath, modes)); + free (fullpath); + return file; + } + +#elif defined (HAVE_FOPEN64) + return close_on_exec (fopen64 (filename, modes)); #endif + + return close_on_exec (fopen (filename, modes)); } +/* +INTERNAL_DEFINITION + struct bfd_iovec + +DESCRIPTION + + The <> contains the internal file I/O class. + Each <> 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 <>) 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 <> +. 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 <> 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); +. {* Mmap a part of the files. ADDR, LEN, PROT, FLAGS and OFFSET are the usual +. mmap parameter, except that LEN and OFFSET do not need to be page +. aligned. Returns (void *)-1 on failure, mmapped address on success. +. Also write in MAP_ADDR the address of the page aligned buffer and in +. MAP_LEN the size mapped (a page multiple). Use unmap with MAP_ADDR and +. MAP_LEN to unmap. *} +. void *(*bmmap) (struct bfd *abfd, void *addr, bfd_size_type len, +. int prot, int flags, file_ptr offset, +. void **map_addr, bfd_size_type *map_len); +.}; + +.extern const struct bfd_iovec _bfd_memory_iovec; + +*/ + + /* Return value is amount read. */ bfd_size_type bfd_bread (void *ptr, bfd_size_type size, bfd *abfd) { - size_t nread; + file_ptr nread; + bfd *element_bfd = abfd; + ufile_ptr offset = 0; - if ((abfd->flags & BFD_IN_MEMORY) != 0) + while (abfd->my_archive != NULL + && !bfd_is_thin_archive (abfd->my_archive)) { - struct bfd_in_memory *bim; - bfd_size_type get; + offset += abfd->origin; + abfd = abfd->my_archive; + } + offset += abfd->origin; - bim = abfd->iostream; - get = size; - if (abfd->where + get > bim->size) + /* If this is an archive element, don't read past the end of + this element. */ + if (element_bfd->arelt_data != NULL) + { + bfd_size_type maxbytes = arelt_size (element_bfd); + + if (abfd->where < offset || abfd->where - offset >= maxbytes) { - if (bim->size < (bfd_size_type) abfd->where) - get = 0; - else - get = bim->size - abfd->where; - bfd_set_error (bfd_error_file_truncated); + bfd_set_error (bfd_error_invalid_operation); + return -1; } - memcpy (ptr, bim->buffer + abfd->where, (size_t) get); - abfd->where += get; - return get; + if (abfd->where - offset + size > maxbytes) + size = maxbytes - (abfd->where - offset); } - nread = real_read (ptr, 1, (size_t) size, bfd_cache_lookup (abfd)); - 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 (abfd->iovec == NULL) { - if (ferror (bfd_cache_lookup (abfd))) - bfd_set_error (bfd_error_system_call); - else - bfd_set_error (bfd_error_file_truncated); + bfd_set_error (bfd_error_invalid_operation); + return -1; } + nread = abfd->iovec->bread (abfd, ptr, size); + if (nread != -1) + abfd->where += nread; + return nread; } bfd_size_type bfd_bwrite (const void *ptr, bfd_size_type size, bfd *abfd) { - size_t nwrote; + file_ptr 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; + while (abfd->my_archive != NULL + && !bfd_is_thin_archive (abfd->my_archive)) + abfd = abfd->my_archive; - 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 (bim->buffer, newsize); - if (bim->buffer == 0) - { - bim->size = 0; - return 0; - } - } - } - memcpy (bim->buffer + abfd->where, ptr, (size_t) size); - abfd->where += size; - return size; + if (abfd->iovec == NULL) + { + bfd_set_error (bfd_error_invalid_operation); + return -1; } - nwrote = fwrite (ptr, 1, (size_t) size, bfd_cache_lookup (abfd)); - if (nwrote != (size_t) -1) + nwrote = abfd->iovec->bwrite (abfd, ptr, size); + if (nwrote != -1) abfd->where += nwrote; - if (nwrote != size) + if ((bfd_size_type) nwrote != size) { #ifdef ENOSPC errno = ENOSPC; @@ -162,28 +268,39 @@ bfd_bwrite (const void *ptr, bfd_size_type size, bfd *abfd) return nwrote; } -bfd_vma +file_ptr bfd_tell (bfd *abfd) { + ufile_ptr offset = 0; file_ptr ptr; - if ((abfd->flags & BFD_IN_MEMORY) != 0) - return abfd->where; + while (abfd->my_archive != NULL + && !bfd_is_thin_archive (abfd->my_archive)) + { + offset += abfd->origin; + abfd = abfd->my_archive; + } + offset += abfd->origin; - ptr = ftell (bfd_cache_lookup (abfd)); + if (abfd->iovec == NULL) + return 0; - if (abfd->my_archive) - ptr -= abfd->origin; + ptr = abfd->iovec->btell (abfd); abfd->where = ptr; - return ptr; + return ptr - offset; } int bfd_flush (bfd *abfd) { - if ((abfd->flags & BFD_IN_MEMORY) != 0) + while (abfd->my_archive != NULL + && !bfd_is_thin_archive (abfd->my_archive)) + abfd = abfd->my_archive; + + if (abfd->iovec == NULL) return 0; - return fflush (bfd_cache_lookup(abfd)); + + return abfd->iovec->bflush (abfd); } /* Returns 0 for success, negative value for failure (in which case @@ -191,19 +308,19 @@ bfd_flush (bfd *abfd) int bfd_stat (bfd *abfd, struct stat *statbuf) { - FILE *f; int result; - if ((abfd->flags & BFD_IN_MEMORY) != 0) - abort (); + while (abfd->my_archive != NULL + && !bfd_is_thin_archive (abfd->my_archive)) + abfd = abfd->my_archive; - f = bfd_cache_lookup (abfd); - if (f == NULL) + if (abfd->iovec == NULL) { - bfd_set_error (bfd_error_system_call); + bfd_set_error (bfd_error_invalid_operation); 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; @@ -216,123 +333,53 @@ int bfd_seek (bfd *abfd, file_ptr position, int direction) { int result; - FILE *f; - long 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 - element in an archive. */ - - BFD_ASSERT (direction == SEEK_SET || direction == SEEK_CUR); + ufile_ptr offset = 0; - if (direction == SEEK_CUR && position == 0) - return 0; - - if ((abfd->flags & BFD_IN_MEMORY) != 0) + while (abfd->my_archive != NULL + && !bfd_is_thin_archive (abfd->my_archive)) { - 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 (bim->buffer, newsize); - if (bim->buffer == 0) - { - bim->size = 0; - return -1; - } - } - } - else - { - abfd->where = bim->size; - bfd_set_error (bfd_error_file_truncated); - return -1; - } - } - return 0; + offset += abfd->origin; + abfd = abfd->my_archive; } + offset += abfd->origin; - if (abfd->format != bfd_archive && abfd->my_archive == 0) + if (abfd->iovec == NULL) { -#if 0 - /* Explanation for this code: I'm only about 95+% sure that the above - conditions are sufficient and that all i/o calls are properly - adjusting the `where' field. So this is sort of an `assert' - that the `where' field is correct. If we can go a while without - tripping the abort, we can probably safely disable this code, - so that the real optimizations happen. */ - file_ptr where_am_i_now; - where_am_i_now = ftell (bfd_cache_lookup (abfd)); - if (abfd->my_archive) - where_am_i_now -= abfd->origin; - if (where_am_i_now != abfd->where) - abort (); -#endif - if (direction == SEEK_SET && (bfd_vma) position == abfd->where) - return 0; + bfd_set_error (bfd_error_invalid_operation); + return -1; } - else - { - /* We need something smarter to optimize access to archives. - Currently, anything inside an archive is read via the file - handle for the archive. Which means that a bfd_seek on one - component affects the `current position' in the archive, as - well as in any other component. - It might be sufficient to put a spike through the cache - abstraction, and look to the archive for the file position, - but I think we should try for something cleaner. + /* 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 + element in an archive. */ + BFD_ASSERT (direction == SEEK_SET || direction == SEEK_CUR); - In the meantime, no optimization for archives. */ - } + if (direction != SEEK_CUR) + position += offset; - f = bfd_cache_lookup (abfd); - file_position = position; - if (direction == SEEK_SET && abfd->my_archive != NULL) - file_position += abfd->origin; + if ((direction == SEEK_CUR && position == 0) + || (direction == SEEK_SET && (ufile_ptr) position == abfd->where)) + return 0; - result = fseek (f, file_position, direction); + result = abfd->iovec->bseek (abfd, position, direction); if (result != 0) { - int hold_errno = errno; - - /* Force redetermination of `where' field. */ - bfd_tell (abfd); - /* An EINVAL error probably means that the file offset was - absurd. */ - if (hold_errno == EINVAL) + absurd. */ + if (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); } else { /* Adjust `where' field. */ - if (direction == SEEK_SET) - abfd->where = position; - else + if (direction == SEEK_CUR) abfd->where += position; + else + abfd->where = position; } + return result; } @@ -352,14 +399,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 (bfd_stat (abfd, &buf) != 0) return 0; abfd->mtime = buf.st_mtime; /* Save value in case anyone wants it */ @@ -371,7 +416,7 @@ FUNCTION bfd_get_size SYNOPSIS - long bfd_get_size (bfd *abfd); + ufile_ptr bfd_get_size (bfd *abfd); DESCRIPTION Return the file size (as read from file system) for the file @@ -395,22 +440,265 @@ DESCRIPTION error when it tries to read the table, or a "virtual memory exhausted" error when it tries to allocate 15 bazillon bytes of space for the 15 bazillon byte table it is about to read. - This function at least allows us to answer the quesion, "is the + This function at least allows us to answer the question, "is the size reasonable?". + + A return value of zero indicates the file size is unknown. */ -long +ufile_ptr bfd_get_size (bfd *abfd) { - FILE *fp; - struct stat buf; + /* A size of 0 means we haven't yet called bfd_stat. A size of 1 + means we have a cached value of 0, ie. unknown. */ + if (abfd->size <= 1 || bfd_write_p (abfd)) + { + struct stat buf; - if ((abfd->flags & BFD_IN_MEMORY) != 0) - return ((struct bfd_in_memory *) abfd->iostream)->size; + if (abfd->size == 1 && !bfd_write_p (abfd)) + return 0; - fp = bfd_cache_lookup (abfd); - if (0 != fstat (fileno (fp), & buf)) - return 0; + if (bfd_stat (abfd, &buf) != 0 + || buf.st_size == 0 + || buf.st_size - (ufile_ptr) buf.st_size != 0) + { + abfd->size = 1; + return 0; + } + abfd->size = buf.st_size; + } + return abfd->size; +} + +/* +FUNCTION + bfd_get_file_size + +SYNOPSIS + ufile_ptr bfd_get_file_size (bfd *abfd); + +DESCRIPTION + Return the file size (as read from file system) for the file + associated with BFD @var{abfd}. It supports both normal files + and archive elements. + +*/ + +ufile_ptr +bfd_get_file_size (bfd *abfd) +{ + ufile_ptr file_size, archive_size = (ufile_ptr) -1; + + if (abfd->my_archive != NULL + && !bfd_is_thin_archive (abfd->my_archive)) + { + struct areltdata *adata = (struct areltdata *) abfd->arelt_data; + archive_size = adata->parsed_size; + /* If the archive is compressed we can't compare against file size. */ + if (adata->arch_header != NULL + && memcmp (((struct ar_hdr *) adata->arch_header)->ar_fmag, + "Z\012", 2) == 0) + return archive_size; + abfd = abfd->my_archive; + } + + file_size = bfd_get_size (abfd); + if (archive_size < file_size) + return archive_size; + return file_size; +} - return buf.st_size; +/* +FUNCTION + bfd_mmap + +SYNOPSIS + void *bfd_mmap (bfd *abfd, void *addr, bfd_size_type len, + int prot, int flags, file_ptr offset, + void **map_addr, bfd_size_type *map_len); + +DESCRIPTION + Return mmap()ed region of the file, if possible and implemented. + LEN and OFFSET do not need to be page aligned. The page aligned + address and length are written to MAP_ADDR and MAP_LEN. + +*/ + +void * +bfd_mmap (bfd *abfd, void *addr, bfd_size_type len, + int prot, int flags, file_ptr offset, + void **map_addr, bfd_size_type *map_len) +{ + while (abfd->my_archive != NULL + && !bfd_is_thin_archive (abfd->my_archive)) + { + offset += abfd->origin; + abfd = abfd->my_archive; + } + offset += abfd->origin; + + if (abfd->iovec == NULL) + { + bfd_set_error (bfd_error_invalid_operation); + return (void *) -1; + } + + return abfd->iovec->bmmap (abfd, addr, len, prot, flags, offset, + map_addr, map_len); +} + +/* Memory file I/O operations. */ + +static file_ptr +memory_bread (bfd *abfd, void *ptr, file_ptr size) +{ + struct bfd_in_memory *bim; + bfd_size_type get; + + bim = (struct bfd_in_memory *) 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); + return get; } + +static file_ptr +memory_bwrite (bfd *abfd, const void *ptr, file_ptr size) +{ + struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream; + + 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_byte *) 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 +memory_btell (bfd *abfd) +{ + return abfd->where; +} + +static int +memory_bseek (bfd *abfd, file_ptr position, int direction) +{ + file_ptr nwhere; + struct bfd_in_memory *bim; + + bim = (struct bfd_in_memory *) abfd->iostream; + + if (direction == SEEK_SET) + nwhere = position; + else + nwhere = abfd->where + position; + + if (nwhere < 0) + { + abfd->where = 0; + errno = EINVAL; + return -1; + } + + if ((bfd_size_type)nwhere > 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 = nwhere; + /* Round up to cut down on memory fragmentation */ + newsize = (bim->size + 127) & ~(bfd_size_type) 127; + if (newsize > oldsize) + { + bim->buffer = (bfd_byte *) bfd_realloc_or_free (bim->buffer, newsize); + if (bim->buffer == NULL) + { + errno = EINVAL; + bim->size = 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 +memory_bclose (struct bfd *abfd) +{ + struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream; + + free (bim->buffer); + free (bim); + abfd->iostream = NULL; + + return 0; +} + +static int +memory_bflush (bfd *abfd ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +memory_bstat (bfd *abfd, struct stat *statbuf) +{ + struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream; + + memset (statbuf, 0, sizeof (*statbuf)); + statbuf->st_size = bim->size; + + return 0; +} + +static void * +memory_bmmap (bfd *abfd ATTRIBUTE_UNUSED, void *addr ATTRIBUTE_UNUSED, + bfd_size_type len ATTRIBUTE_UNUSED, int prot ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, file_ptr offset ATTRIBUTE_UNUSED, + void **map_addr ATTRIBUTE_UNUSED, + bfd_size_type *map_len ATTRIBUTE_UNUSED) +{ + return (void *)-1; +} + +const struct bfd_iovec _bfd_memory_iovec = +{ + &memory_bread, &memory_bwrite, &memory_btell, &memory_bseek, + &memory_bclose, &memory_bflush, &memory_bstat, &memory_bmmap +};