From 4fe6d901bd49996a77c84ab710918c94e84e9a23 Mon Sep 17 00:00:00 2001 From: Ken Raeburn Date: Mon, 6 Nov 1995 10:08:03 +0000 Subject: Changes for mmap; details in change log. Added some new interfaces, and a new entry in the target vector. Under the new interfaces, mmap will be used if available, otherwise malloc/seek/read, as before. Old interfaces all still intact. Most configurations (including all used by "--enable-targets=all") simply changed to call the default routine for that entry in the target vector. I might've missed some targets only included in special configurations. Support for a.out symbol and string table reading now goes through new interfaces, and will use mmap when available. Linker hooks (e.g., avoiding reallocation under malloc) not ready yet. --- bfd/libbfd.c | 351 +++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 284 insertions(+), 67 deletions(-) (limited to 'bfd/libbfd.c') diff --git a/bfd/libbfd.c b/bfd/libbfd.c index 2925754..5f682ec 100644 --- a/bfd/libbfd.c +++ b/bfd/libbfd.c @@ -16,12 +16,14 @@ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "bfd.h" #include "sysdep.h" #include "libbfd.h" +static int real_read PARAMS ((PTR, size_t, size_t, FILE *)); + /* SECTION Internal functions @@ -145,10 +147,11 @@ _bfd_nocore_core_file_failing_signal (ignore_abfd) } /*ARGSUSED*/ -bfd_target * +const bfd_target * _bfd_dummy_target (ignore_abfd) bfd *ignore_abfd; { + bfd_set_error (bfd_error_wrong_format); return 0; } @@ -179,15 +182,14 @@ bfd_zmalloc (size) 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 -int +static int real_read (where, a,b, file) PTR where; - int a; - int b; + size_t a; + size_t b; FILE *file; { - return fread(where, a,b,file); + return fread (where, a, b, file); } /* Return value is amount read (FIXME: how are errors and end of file dealt @@ -201,7 +203,7 @@ bfd_read (ptr, size, nitems, abfd) bfd *abfd; { int nread; - nread = real_read (ptr, 1, (int)(size*nitems), bfd_cache_lookup(abfd)); + nread = real_read (ptr, 1, (size_t)(size*nitems), bfd_cache_lookup(abfd)); #ifdef FILE_OFFSET_IS_CHAR_INDEX if (nread > 0) abfd->where += nread; @@ -225,6 +227,219 @@ bfd_read (ptr, size, nitems, abfd) 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; +} + +#undef HAVE_MPROTECT /* code's not tested yet */ + +#if HAVE_MMAP || HAVE_MPROTECT +#include +#include +#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; + +int +bfd_get_file_window (abfd, offset, size, windowp, writable) + bfd *abfd; + file_ptr offset; + bfd_size_type size; + bfd_window *windowp; + int writable; +{ + static size_t pagesize; + bfd_window_internal *i = windowp->i; + size_t 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, 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) + { + windowp->i = i = (bfd_window_internal *) bfd_zmalloc (sizeof (bfd_window_internal)); + if (i == 0) + return false; + i->data = 0; + } +#ifdef HAVE_MMAP + if (ok_to_map && (i->data == 0 || i->mapped == 1)) + { + 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, + 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 = i->data + offset2; + windowp->size = size; + i->mapped = 1; + return true; + } + else if (debug_windows) + { + if (ok_to_map) + fprintf (stderr, "not mapping: data=%x mapped=%d\n", + i->data, 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); + if (i->data) + i->data = realloc (i->data, size_to_alloc); + else + i->data = malloc (size_to_alloc); + if (debug_windows) + fprintf (stderr, "\t-> %p\n", i->data); + i->refcount = 1; + if (i->data == 0) + return size_to_alloc == 0; + if (bfd_seek (abfd, offset, SEEK_SET) != 0) + return false; + i->size = bfd_read (i->data, size, 1, 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; +} + bfd_size_type bfd_write (ptr, size, nitems, abfd) CONST PTR ptr; @@ -232,12 +447,13 @@ bfd_write (ptr, size, nitems, abfd) bfd_size_type nitems; bfd *abfd; { - int nwrote = fwrite (ptr, 1, (int) (size * nitems), bfd_cache_lookup (abfd)); + long nwrote = fwrite (ptr, 1, (size_t) (size * nitems), + bfd_cache_lookup (abfd)); #ifdef FILE_OFFSET_IS_CHAR_INDEX if (nwrote > 0) abfd->where += nwrote; #endif - if (nwrote != size * nitems) + if ((bfd_size_type) nwrote != size * nitems) { #ifdef ENOSPC if (nwrote >= 0) @@ -293,12 +509,25 @@ bfd_flush (abfd) 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; { - return fstat (fileno(bfd_cache_lookup(abfd)), statbuf); + FILE *f; + int result; + 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 @@ -306,9 +535,9 @@ bfd_stat (abfd, statbuf) int bfd_seek (abfd, position, direction) - bfd * CONST abfd; - CONST file_ptr position; - CONST int direction; + bfd *abfd; + file_ptr position; + int direction; { int result; FILE *f; @@ -383,59 +612,6 @@ bfd_seek (abfd, position, direction) return result; } -/** Make a string table */ - -/*>bfd.h< - Add string to table pointed to by table, at location starting with free_ptr. - resizes the table if necessary (if it's NULL, creates it, ignoring - table_length). Updates free_ptr, table, table_length */ - -boolean -bfd_add_to_string_table (table, new_string, table_length, free_ptr) - char **table; - char *new_string; - unsigned int *table_length; - char **free_ptr; -{ - size_t string_length = strlen (new_string) + 1; /* include null here */ - char *base = *table; - size_t space_length = *table_length; - unsigned int offset = (base ? *free_ptr - base : 0); - - if (base == NULL) { - /* Avoid a useless regrow if we can (but of course we still - take it next time). */ - space_length = (string_length < DEFAULT_STRING_SPACE_SIZE ? - DEFAULT_STRING_SPACE_SIZE : string_length+1); - base = bfd_zmalloc ((bfd_size_type) space_length); - - if (base == NULL) { - bfd_set_error (bfd_error_no_memory); - return false; - } - } - - if ((size_t)(offset + string_length) >= space_length) { - /* Make sure we will have enough space */ - while ((size_t)(offset + string_length) >= space_length) - space_length += space_length/2; /* grow by 50% */ - - base = (char *) realloc (base, space_length); - if (base == NULL) { - bfd_set_error (bfd_error_no_memory); - return false; - } - - } - - memcpy (base + offset, new_string, string_length); - *table = base; - *table_length = space_length; - *free_ptr = base + offset + string_length; - - return true; -} - /** The do-it-yourself (byte) sex-change kit */ /* The middle letter e.g. getshort indicates Big or Little endian @@ -823,6 +999,47 @@ _bfd_generic_get_section_contents (abfd, section, location, offset, count) return (true); } +boolean +_bfd_generic_get_section_contents_in_window (abfd, section, w, offset, count) + bfd *abfd; + sec_ptr section; + bfd_window *w; + file_ptr offset; + bfd_size_type count; +{ + if (count == 0) + return true; + if (abfd->xvec->_bfd_get_section_contents != _bfd_generic_get_section_contents) + { + /* We don't know what changes the bfd's get_section_contents + method may have to make. So punt trying to map the file + window, and let get_section_contents do its thing. */ + /* @@ FIXME : If the internal window has a refcount of 1 and was + allocated with malloc instead of mmap, just reuse it. */ + bfd_free_window (w); + w->i = (bfd_window_internal *) bfd_zmalloc (sizeof (bfd_window_internal)); + if (w->i == NULL) + return false; + w->i->data = (PTR) malloc ((size_t) count); + if (w->i->data == NULL) + { + free (w->i); + w->i = NULL; + return false; + } + w->i->mapped = 0; + w->i->refcount = 1; + w->size = w->i->size = count; + w->data = w->i->data; + return bfd_get_section_contents (abfd, section, w->data, offset, count); + } + if ((bfd_size_type) (offset+count) > section->_raw_size + || (bfd_get_file_window (abfd, section->filepos + offset, count, w, 1) + == false)) + return false; + return true; +} + /* This generic function can only be used in implementations where creating NEW sections is disallowed. It is useful in patching existing sections in read-write files, though. See other set_section_contents functions -- cgit v1.1