diff options
Diffstat (limited to 'bfd/libbfd.c')
-rw-r--r-- | bfd/libbfd.c | 548 |
1 files changed, 0 insertions, 548 deletions
diff --git a/bfd/libbfd.c b/bfd/libbfd.c index f21abbc..8783def 100644 --- a/bfd/libbfd.c +++ b/bfd/libbfd.c @@ -28,8 +28,6 @@ #define getpagesize() 2048 #endif -static size_t real_read PARAMS ((PTR, size_t, size_t, FILE *)); - /* SECTION Internal functions @@ -222,372 +220,6 @@ bfd_zmalloc (size) return ptr; } - -/* Some IO code */ - -/* 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 size_t -real_read (where, a, b, file) - PTR 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 -bfd_bread (ptr, size, abfd) - PTR ptr; - bfd_size_type size; - bfd *abfd; -{ - size_t nread; - - if ((abfd->flags & BFD_IN_MEMORY) != 0) - { - 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); - abfd->where += get; - return get; - } - - 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 (ferror (bfd_cache_lookup (abfd))) - bfd_set_error (bfd_error_system_call); - else - bfd_set_error (bfd_error_file_truncated); - } - - return nread; -} - -/* The window support stuff should probably be broken out into - another file.... */ -/* The idea behind the next and refcount fields is that one mapped - region can suffice for multiple read-only windows or multiple - non-overlapping read-write windows. It's not implemented yet - though. */ -struct _bfd_window_internal { - struct _bfd_window_internal *next; - PTR data; - bfd_size_type size; - int refcount : 31; /* should be enough... */ - unsigned mapped : 1; /* 1 = mmap, 0 = malloc */ -}; - -void -bfd_init_window (windowp) - bfd_window *windowp; -{ - windowp->data = 0; - windowp->i = 0; - windowp->size = 0; -} - -/* Currently, if USE_MMAP is undefined, none if the window stuff is - used. Okay, so it's mis-named. At least the command-line option - "--without-mmap" is more obvious than "--without-windows" or some - such. */ -#ifdef USE_MMAP - -#undef HAVE_MPROTECT /* code's not tested yet */ - -#if HAVE_MMAP || HAVE_MPROTECT || HAVE_MADVISE -#include <sys/mman.h> -#endif - -#ifndef MAP_FILE -#define MAP_FILE 0 -#endif - -static int debug_windows; - -void -bfd_free_window (windowp) - bfd_window *windowp; -{ - bfd_window_internal *i = windowp->i; - windowp->i = 0; - windowp->data = 0; - if (i == 0) - return; - i->refcount--; - if (debug_windows) - fprintf (stderr, "freeing window @%p<%p,%lx,%p>\n", - windowp, windowp->data, windowp->size, windowp->i); - if (i->refcount != 0) - return; - - if (i->mapped) - { -#ifdef HAVE_MMAP - munmap (i->data, i->size); - goto no_free; -#else - abort (); -#endif - } -#ifdef HAVE_MPROTECT - mprotect (i->data, i->size, PROT_READ | PROT_WRITE); -#endif - free (i->data); -#ifdef HAVE_MMAP - no_free: -#endif - i->data = 0; - /* There should be no more references to i at this point. */ - free (i); -} - -static int ok_to_map = 1; - -boolean -bfd_get_file_window (abfd, offset, size, windowp, writable) - bfd *abfd; - file_ptr offset; - bfd_size_type size; - bfd_window *windowp; - boolean writable; -{ - static size_t pagesize; - bfd_window_internal *i = windowp->i; - bfd_size_type size_to_alloc = size; - - if (debug_windows) - fprintf (stderr, "bfd_get_file_window (%p, %6ld, %6ld, %p<%p,%lx,%p>, %d)", - abfd, (long) offset, (long) size, - windowp, windowp->data, (unsigned long) windowp->size, - windowp->i, writable); - - /* Make sure we know the page size, so we can be friendly to mmap. */ - if (pagesize == 0) - pagesize = getpagesize (); - if (pagesize == 0) - abort (); - - if (i == 0) - { - i = ((bfd_window_internal *) - bfd_zmalloc ((bfd_size_type) sizeof (bfd_window_internal))); - windowp->i = i; - if (i == 0) - return false; - i->data = 0; - } -#ifdef HAVE_MMAP - if (ok_to_map - && (i->data == 0 || i->mapped == 1) - && (abfd->flags & BFD_IN_MEMORY) == 0) - { - file_ptr file_offset, offset2; - size_t real_size; - int fd; - FILE *f; - - /* Find the real file and the real offset into it. */ - while (abfd->my_archive != NULL) - { - offset += abfd->origin; - abfd = abfd->my_archive; - } - f = bfd_cache_lookup (abfd); - fd = fileno (f); - - /* Compute offsets and size for mmap and for the user's data. */ - offset2 = offset % pagesize; - if (offset2 < 0) - abort (); - file_offset = offset - offset2; - real_size = offset + size - file_offset; - real_size = real_size + pagesize - 1; - real_size -= real_size % pagesize; - - /* If we're re-using a memory region, make sure it's big enough. */ - if (i->data && i->size < size) - { - munmap (i->data, i->size); - i->data = 0; - } - i->data = mmap (i->data, real_size, - writable ? PROT_WRITE | PROT_READ : PROT_READ, - (writable - ? MAP_FILE | MAP_PRIVATE - : MAP_FILE | MAP_SHARED), - fd, file_offset); - if (i->data == (PTR) -1) - { - /* An error happened. Report it, or try using malloc, or - something. */ - bfd_set_error (bfd_error_system_call); - i->data = 0; - windowp->data = 0; - if (debug_windows) - fprintf (stderr, "\t\tmmap failed!\n"); - return false; - } - if (debug_windows) - fprintf (stderr, "\n\tmapped %ld at %p, offset is %ld\n", - (long) real_size, i->data, (long) offset2); - i->size = real_size; - windowp->data = (PTR) ((bfd_byte *) i->data + offset2); - windowp->size = size; - i->mapped = 1; - return true; - } - else if (debug_windows) - { - if (ok_to_map) - fprintf (stderr, _("not mapping: data=%lx mapped=%d\n"), - (unsigned long) i->data, (int) i->mapped); - else - fprintf (stderr, _("not mapping: env var not set\n")); - } -#else - ok_to_map = 0; -#endif - -#ifdef HAVE_MPROTECT - if (!writable) - { - size_to_alloc += pagesize - 1; - size_to_alloc -= size_to_alloc % pagesize; - } -#endif - if (debug_windows) - fprintf (stderr, "\n\t%s(%6ld)", - i->data ? "realloc" : " malloc", (long) size_to_alloc); - i->data = (PTR) bfd_realloc (i->data, size_to_alloc); - if (debug_windows) - fprintf (stderr, "\t-> %p\n", i->data); - i->refcount = 1; - if (i->data == NULL) - { - if (size_to_alloc == 0) - return true; - return false; - } - if (bfd_seek (abfd, offset, SEEK_SET) != 0) - return false; - i->size = bfd_bread (i->data, size, abfd); - if (i->size != size) - return false; - i->mapped = 0; -#ifdef HAVE_MPROTECT - if (!writable) - { - if (debug_windows) - fprintf (stderr, "\tmprotect (%p, %ld, PROT_READ)\n", i->data, - (long) i->size); - mprotect (i->data, i->size, PROT_READ); - } -#endif - windowp->data = i->data; - windowp->size = i->size; - return true; -} - -#endif /* USE_MMAP */ - -bfd_size_type -bfd_bwrite (ptr, size, abfd) - const PTR ptr; - bfd_size_type size; - bfd *abfd; -{ - size_t nwrote; - - if ((abfd->flags & BFD_IN_MEMORY) != 0) - { - struct bfd_in_memory *bim = (struct bfd_in_memory *) (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_byte *) 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; - } - - nwrote = fwrite (ptr, 1, (size_t) size, bfd_cache_lookup (abfd)); - if (nwrote != (size_t) -1) - abfd->where += nwrote; - if (nwrote != size) - { -#ifdef ENOSPC - errno = ENOSPC; -#endif - bfd_set_error (bfd_error_system_call); - } - return nwrote; -} - /* INTERNAL_FUNCTION bfd_write_bigendian_4byte_int @@ -611,186 +243,6 @@ bfd_write_bigendian_4byte_int (abfd, i) return (boolean) (bfd_bwrite ((PTR) buffer, (bfd_size_type) 4, abfd) == 4); } -bfd_vma -bfd_tell (abfd) - bfd *abfd; -{ - file_ptr ptr; - - if ((abfd->flags & BFD_IN_MEMORY) != 0) - return abfd->where; - - ptr = ftell (bfd_cache_lookup (abfd)); - - if (abfd->my_archive) - ptr -= abfd->origin; - abfd->where = ptr; - return ptr; -} - -int -bfd_flush (abfd) - bfd *abfd; -{ - if ((abfd->flags & BFD_IN_MEMORY) != 0) - return 0; - return fflush (bfd_cache_lookup(abfd)); -} - -/* Returns 0 for success, negative value for failure (in which case - bfd_get_error can retrieve the error code). */ -int -bfd_stat (abfd, statbuf) - 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); - if (result < 0) - bfd_set_error (bfd_error_system_call); - return result; -} - -/* Returns 0 for success, nonzero for failure (in which case bfd_get_error - can retrieve the error code). */ - -int -bfd_seek (abfd, position, direction) - 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); - - if (direction == SEEK_CUR && position == 0) - return 0; - - if ((abfd->flags & BFD_IN_MEMORY) != 0) - { - struct bfd_in_memory *bim; - - bim = (struct bfd_in_memory *) 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_byte *) 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; - } - - if (abfd->format != bfd_archive && abfd->my_archive == 0) - { -#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; - } - 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. - - 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 = fseek (f, file_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) - bfd_set_error (bfd_error_file_truncated); - else - { - bfd_set_error (bfd_error_system_call); - errno = hold_errno; - } - } - else - { - /* Adjust `where' field. */ - if (direction == SEEK_SET) - abfd->where = position; - else - abfd->where += position; - } - return result; -} /** The do-it-yourself (byte) sex-change kit */ |