From 4fe6d901bd49996a77c84ab710918c94e84e9a23 Mon Sep 17 00:00:00 2001 From: Ken Raeburn Date: Mon, 6 Nov 1995 10:08:03 +0000 Subject: [PATCH] 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/ChangeLog | 34 +++++ bfd/aoutx.h | 70 ++++------ bfd/bfd-in.h | 22 +++ bfd/bfd-in2.h | 29 +++- bfd/config.in | 55 ++++++++ bfd/configure | 152 ++++++++++++++++++++ bfd/configure.in | 4 + bfd/libbfd.c | 351 ++++++++++++++++++++++++++++++++++++++--------- bfd/libcoff-in.h | 3 + bfd/libcoff.h | 3 + bfd/oasys.c | 5 +- bfd/targets.c | 9 +- 12 files changed, 625 insertions(+), 112 deletions(-) create mode 100644 bfd/config.in diff --git a/bfd/ChangeLog b/bfd/ChangeLog index c0a9a34138..b8fc05081f 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -8,6 +8,40 @@ Sun Nov 5 21:44:13 1995 Ken Raeburn * ecoff.c (_bfd_ecoff_slurp_armap): Cast _bfd_read_ar_hdr return value. + Permit use of mmap when available: + + * configure.in: Check for mmap, madvise, mprotect. + * config.in, configure: Regenerated. + + * libbfd.c (struct _bfd_window_internal): Define type. + (bfd_init_window, bfd_free_window, bfd_get_file_window): New + functions. + (ok_to_map): New static variable for debugging. + (_bfd_generic_get_section_contents_in_window): New function. + * bfd-in.h (bfd_window_internal): Declare type. + (bfd_window): Define type. + (bfd_init_window, bfd_free_window, bfd_get_file_window): Declare. + * libbfd-in.h (_bfd_generic_get_section_contents_in_window): + Declare. + + * libaout.h (struct aoutdata): Add two window fields. + (obj_aout_sym_window, obj_aout_string_window): New macros. + * aoutx.h (some_aout_object_p): Initialize windows. + (aout_get_external_symbols): Get symbol data and strings in + windows instead of explicitly allocated buffers. + (slurp_symbol_table): Free window instead of memory. + (bfd_free_cached_info): Release windows instead of freeing storage + directly. + (aout_link_free_symbols): Ditto. + + * targets.c (bfd_target): Add new field for + get_section_contents_in_window. + (BFD_JUMP_TABLE_GENERIC): Updated. + * aout-adobe.c, aout-target.h, binary.c, bout.c, coff-alpha.c, + coff-mips.c, elfxx-target.h, i386msdos.c, i386os9k.c, ieee.c, + libcoff-in.h, oasys.c, srec.c, tekhex.c, versados.c: Added new + macros for get_section_contents_in_window field. + Sat Nov 4 12:23:26 1995 Fred Fish * core.c: Renamed to corefile.c diff --git a/bfd/aoutx.h b/bfd/aoutx.h index 657130212e..8d7ea3ab94 100644 --- a/bfd/aoutx.h +++ b/bfd/aoutx.h @@ -497,7 +497,9 @@ NAME(aout,some_aout_object_p) (abfd, execp, callback_to_real_object_p) obj_symbol_entry_size (abfd) = EXTERNAL_NLIST_SIZE; obj_aout_external_syms (abfd) = NULL; + bfd_init_window (&obj_aout_sym_window (abfd)); obj_aout_external_strings (abfd) = NULL; + bfd_init_window (&obj_aout_string_window (abfd)); obj_aout_sym_hashes (abfd) = NULL; if (! NAME(aout,make_sections) (abfd)) @@ -1226,24 +1228,11 @@ aout_get_external_symbols (abfd) count = exec_hdr (abfd)->a_syms / EXTERNAL_NLIST_SIZE; - /* We allocate using malloc to make the values easy to free - later on. If we put them on the obstack it might not be - possible to free them. */ - syms = ((struct external_nlist *) - malloc ((size_t) count * EXTERNAL_NLIST_SIZE)); - if (syms == (struct external_nlist *) NULL && count != 0) - { - bfd_set_error (bfd_error_no_memory); - return false; - } - - if (bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET) != 0 - || (bfd_read (syms, 1, exec_hdr (abfd)->a_syms, abfd) - != exec_hdr (abfd)->a_syms)) - { - free (syms); - return false; - } + if (bfd_get_file_window (abfd, + obj_sym_filepos (abfd), exec_hdr (abfd)->a_syms, + &obj_aout_sym_window (abfd), 1) == false) + return false; + syms = (struct external_nlist *) obj_aout_sym_window (abfd).data; obj_aout_external_syms (abfd) = syms; obj_aout_external_sym_count (abfd) = count; @@ -1263,28 +1252,25 @@ aout_get_external_symbols (abfd) return false; stringsize = GET_WORD (abfd, string_chars); - strings = (char *) malloc ((size_t) stringsize + 1); - if (strings == NULL) - { - bfd_set_error (bfd_error_no_memory); - return false; - } - - /* Skip space for the string count in the buffer for convenience - when using indexes. */ - if (bfd_read (strings + BYTES_IN_WORD, 1, stringsize - BYTES_IN_WORD, - abfd) - != stringsize - BYTES_IN_WORD) - { - free (strings); - return false; - } + if (bfd_get_file_window (abfd, obj_str_filepos (abfd), stringsize, + &obj_aout_string_window (abfd), 1) == false) + return false; + strings = (char *) obj_aout_string_window (abfd).data; /* Ensure that a zero index yields an empty string. */ strings[0] = '\0'; - /* Sanity preservation. */ - strings[stringsize] = '\0'; + /* Using the "window" interface, we don't know that there's + writeable storage after the last byte of the string table. + Besides, every string in the string table should be null + terminated. Check it here so the application doesn't crash, + but don't expend huge effort trying to correct a broken + object file. */ + if (stringsize > BYTES_IN_WORD && strings[stringsize - 1] != 0) + { + fprintf (stderr, "string table missing ending null\n"); + strings[stringsize - 1] = 0; + } obj_aout_external_strings (abfd) = strings; obj_aout_external_string_size (abfd) = stringsize; @@ -1755,7 +1741,7 @@ NAME(aout,slurp_symbol_table) (abfd) if (old_external_syms == (struct external_nlist *) NULL && obj_aout_external_syms (abfd) != (struct external_nlist *) NULL) { - free (obj_aout_external_syms (abfd)); + bfd_free_window (&obj_aout_sym_window (abfd)); obj_aout_external_syms (abfd) = NULL; } @@ -2784,8 +2770,10 @@ NAME(aout,bfd_free_cached_info) (abfd) #define BFCI_FREE(x) if (x != NULL) { free (x); x = NULL; } BFCI_FREE (obj_aout_symbols (abfd)); - BFCI_FREE (obj_aout_external_syms (abfd)); - BFCI_FREE (obj_aout_external_strings (abfd)); + obj_aout_external_syms (abfd) = 0; + bfd_free_window (&obj_aout_sym_window (abfd)); + bfd_free_window (&obj_aout_string_window (abfd)); + obj_aout_external_strings (abfd) = 0; for (o = abfd->sections; o != (asection *) NULL; o = o->next) BFCI_FREE (o->relocation); #undef BFCI_FREE @@ -2957,12 +2945,12 @@ aout_link_free_symbols (abfd) { if (obj_aout_external_syms (abfd) != (struct external_nlist *) NULL) { - free ((PTR) obj_aout_external_syms (abfd)); + bfd_free_window (&obj_aout_sym_window (abfd)); obj_aout_external_syms (abfd) = (struct external_nlist *) NULL; } if (obj_aout_external_strings (abfd) != (char *) NULL) { - free ((PTR) obj_aout_external_strings (abfd)); + bfd_free_window (&obj_aout_string_window (abfd)); obj_aout_external_strings (abfd) = (char *) NULL; } return true; diff --git a/bfd/bfd-in.h b/bfd/bfd-in.h index d027196c90..d69f7636fb 100644 --- a/bfd/bfd-in.h +++ b/bfd/bfd-in.h @@ -600,6 +600,28 @@ extern boolean bfd_sunos_size_dynamic_sections extern boolean bfd_linux_size_dynamic_sections PARAMS ((bfd *, struct bfd_link_info *)); +/* mmap hacks */ + +struct _bfd_window_internal; +typedef struct _bfd_window_internal bfd_window_internal; + +typedef struct _bfd_window { + /* What the user asked for. */ + PTR data; + bfd_size_type size; + /* The actual window used by BFD. Small user-requested read-only + regions sharing a page may share a single window into the object + file. Read-write versions shouldn't until I've fixed things to + keep track of which portions have been claimed by the + application; don't want to give the same region back when the + application wants two writable copies! */ + struct _bfd_window_internal *i; +} bfd_window; + +void bfd_init_window PARAMS ((bfd_window *)); +void bfd_free_window PARAMS ((bfd_window *)); +int bfd_get_file_window PARAMS ((bfd *, file_ptr, bfd_size_type, bfd_window *, int)); + /* XCOFF support routines for the linker. */ extern boolean bfd_xcoff_link_record_set diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 109c1fc3db..394979d164 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -600,6 +600,28 @@ extern boolean bfd_sunos_size_dynamic_sections extern boolean bfd_linux_size_dynamic_sections PARAMS ((bfd *, struct bfd_link_info *)); +/* mmap hacks */ + +struct _bfd_window_internal; +typedef struct _bfd_window_internal bfd_window_internal; + +typedef struct _bfd_window { + /* What the user asked for. */ + PTR data; + bfd_size_type size; + /* The actual window used by BFD. Small user-requested read-only + regions sharing a page may share a single window into the object + file. Read-write versions shouldn't until I've fixed things to + keep track of which portions have been claimed by the + application; don't want to give the same region back when the + application wants two writable copies! */ + struct _bfd_window_internal *i; +} bfd_window; + +void bfd_init_window PARAMS ((bfd_window *)); +void bfd_free_window PARAMS ((bfd_window *)); +int bfd_get_file_window PARAMS ((bfd *, file_ptr, bfd_size_type, bfd_window *, int)); + /* XCOFF support routines for the linker. */ extern boolean bfd_xcoff_link_record_set @@ -2184,7 +2206,9 @@ typedef struct bfd_target CAT(NAME,_close_and_cleanup),\ CAT(NAME,_bfd_free_cached_info),\ CAT(NAME,_new_section_hook),\ -CAT(NAME,_get_section_contents) +CAT(NAME,_get_section_contents),\ +CAT(NAME,_get_section_contents_in_window) + /* Called when the BFD is being closed to do any necessary cleanup. */ boolean (*_close_and_cleanup) PARAMS ((bfd *)); /* Ask the BFD to free all cached information. */ @@ -2194,6 +2218,9 @@ CAT(NAME,_get_section_contents) /* Read the contents of a section. */ boolean (*_bfd_get_section_contents) PARAMS ((bfd *, sec_ptr, PTR, file_ptr, bfd_size_type)); + boolean (*_bfd_get_section_contents_in_window) + PARAMS ((bfd *, sec_ptr, bfd_window *, + file_ptr, bfd_size_type)); /* Entry points to copy private data. */ #define BFD_JUMP_TABLE_COPY(NAME)\ diff --git a/bfd/config.in b/bfd/config.in new file mode 100644 index 0000000000..49dbce18a0 --- /dev/null +++ b/bfd/config.in @@ -0,0 +1,55 @@ +/* config.in. Generated automatically from configure.in by autoheader. */ + +/* Define if you have a working `mmap' system call. */ +#undef HAVE_MMAP + +/* Do we need to use the b modifier when opening binary files? */ +#undef USE_BINARY_FOPEN + +/* Whether malloc must be declared even if is included. */ +#undef NEED_DECLARATION_MALLOC + +/* Whether free must be declared even if is included. */ +#undef NEED_DECLARATION_FREE + +/* Name of host specific header file to include in trad-core.c. */ +#undef TRAD_HEADER + +/* Define only if is available *and* it defines prstatus_t. */ +#undef HAVE_SYS_PROCFS_H + +/* Define if you have the fcntl function. */ +#undef HAVE_FCNTL + +/* Define if you have the getpagesize function. */ +#undef HAVE_GETPAGESIZE + +/* Define if you have the madvise function. */ +#undef HAVE_MADVISE + +/* Define if you have the mprotect function. */ +#undef HAVE_MPROTECT + +/* Define if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define if you have the header file. */ +#undef HAVE_STDDEF_H + +/* Define if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define if you have the header file. */ +#undef HAVE_STRING_H + +/* Define if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_FILE_H + +/* Define if you have the header file. */ +#undef HAVE_TIME_H + +/* Define if you have the header file. */ +#undef HAVE_UNISTD_H diff --git a/bfd/configure b/bfd/configure index 724ab8a1db..f07af90b1e 100755 --- a/bfd/configure +++ b/bfd/configure @@ -1502,6 +1502,158 @@ test -n "${selvecs}" && tdefaults="${tdefaults} -DSELECT_VECS='${selvecs}'" test -n "${selarchs}" && tdefaults="${tdefaults} -DSELECT_ARCHITECTURES='${selarchs}'" +echo $ac_n "checking for working mmap""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_func_mmap'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + ac_cv_func_mmap=no +else +cat > conftest.$ac_ext < +#include +#include + +#ifdef BSD +# ifndef BSD4_1 +# define HAVE_GETPAGESIZE +# endif +#endif + +#ifndef HAVE_GETPAGESIZE +# include +# ifdef EXEC_PAGESIZE +# define getpagesize() EXEC_PAGESIZE +# else +# ifdef NBPG +# define getpagesize() NBPG * CLSIZE +# ifndef CLSIZE +# define CLSIZE 1 +# endif +# else +# ifdef NBPC +# define getpagesize() NBPC +# else +# define getpagesize() PAGESIZE /* SVR4 */ +# endif +# endif +# endif +#endif + +#ifdef __osf__ +# define valloc malloc +#endif + +#ifdef __cplusplus +extern "C" { void *valloc(unsigned), *malloc(unsigned); } +#else +char *valloc(), *malloc(); +#endif + +int +main() +{ + char *buf1, *buf2, *buf3; + int i = getpagesize(), j; + int i2 = getpagesize()*2; + int fd; + + buf1 = (char *)valloc(i2); + buf2 = (char *)valloc(i); + buf3 = (char *)malloc(i2); + for (j = 0; j < i2; ++j) + *(buf1 + j) = rand(); + fd = open("conftestmmap", O_CREAT | O_RDWR, 0666); + write(fd, buf1, i2); + mmap(buf2, i, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE, fd, 0); + for (j = 0; j < i; ++j) + if (*(buf1 + j) != *(buf2 + j)) + exit(1); + lseek(fd, (long)i, 0); + read(fd, buf2, i); /* read into mapped memory -- file should not change */ + /* (it does in i386 SVR4.0 - Jim Avera, jima@netcom.com) */ + lseek(fd, (long)0, 0); + read(fd, buf3, i2); + for (j = 0; j < i2; ++j) + if (*(buf1 + j) != *(buf3 + j)) + exit(1); + exit(0); +} + +EOF +eval $ac_link +if test -s conftest && (./conftest; exit) 2>/dev/null; then + ac_cv_func_mmap=yes +else + ac_cv_func_mmap=no +fi +fi +rm -fr conftest* +fi +echo "$ac_t""$ac_cv_func_mmap" 1>&6 +if test $ac_cv_func_mmap = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_MMAP 1 +EOF + +fi + +for ac_func in madvise mprotect +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +char $ac_func(); + +int main() { return 0; } +int t() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if eval $ac_link; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* + +fi +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr '[a-z]' '[A-Z]'` + cat >> confdefs.h <&6 +fi +done + + rm -f doc/config.status trap '' 1 2 15 cat > confcache <<\EOF diff --git a/bfd/configure.in b/bfd/configure.in index 61e04712b3..8ef6b013fd 100644 --- a/bfd/configure.in +++ b/bfd/configure.in @@ -528,6 +528,10 @@ test -n "${selvecs}" && tdefaults="${tdefaults} -DSELECT_VECS='${selvecs}'" test -n "${selarchs}" && tdefaults="${tdefaults} -DSELECT_ARCHITECTURES='${selarchs}'" AC_SUBST(tdefaults) +dnl AC_CHECK_HEADERS(sys/mman.h) +AC_FUNC_MMAP +AC_CHECK_FUNCS(madvise mprotect) + rm -f doc/config.status AC_OUTPUT(Makefile doc/Makefile, [case x$CONFIG_HEADERS in xconfig.h:config.in) echo > stamp-h ;; esac]) diff --git a/bfd/libbfd.c b/bfd/libbfd.c index 2925754cbd..5f682ecebe 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 diff --git a/bfd/libcoff-in.h b/bfd/libcoff-in.h index 7b818aa413..1c90879a56 100644 --- a/bfd/libcoff-in.h +++ b/bfd/libcoff-in.h @@ -314,6 +314,9 @@ extern boolean _bfd_coff_generic_relocate_section PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, struct internal_reloc *, struct internal_syment *, asection **)); +#define coff_get_section_contents_in_window \ + _bfd_generic_get_section_contents_in_window + /* Functions in xcofflink.c. */ extern struct bfd_link_hash_table *_bfd_xcoff_bfd_link_hash_table_create diff --git a/bfd/libcoff.h b/bfd/libcoff.h index f75c42b92a..69f2377092 100644 --- a/bfd/libcoff.h +++ b/bfd/libcoff.h @@ -314,6 +314,9 @@ extern boolean _bfd_coff_generic_relocate_section PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, struct internal_reloc *, struct internal_syment *, asection **)); +#define coff_get_section_contents_in_window \ + _bfd_generic_get_section_contents_in_window + /* Functions in xcofflink.c. */ extern struct bfd_link_hash_table *_bfd_xcoff_bfd_link_hash_table_create diff --git a/bfd/oasys.c b/bfd/oasys.c index 4e543af181..76370645c6 100644 --- a/bfd/oasys.c +++ b/bfd/oasys.c @@ -1484,6 +1484,7 @@ oasys_sizeof_headers (abfd, exec) ((boolean (*) \ PARAMS ((bfd *, unsigned int, struct orl *, unsigned int, int))) \ bfd_true) +#define oasys_read_ar_hdr bfd_nullvoidptr #define oasys_update_armap_timestamp bfd_true #define oasys_bfd_is_local_label bfd_generic_is_local_label @@ -1496,6 +1497,9 @@ oasys_sizeof_headers (abfd, exec) #define oasys_set_arch_mach bfd_default_set_arch_mach +#define oasys_get_section_contents_in_window \ + _bfd_generic_get_section_contents_in_window + #define oasys_bfd_get_relocated_section_contents \ bfd_generic_get_relocated_section_contents #define oasys_bfd_relax_section bfd_generic_relax_section @@ -1519,7 +1523,6 @@ const bfd_target oasys_vec = 0, /* leading underscore */ ' ', /* ar_pad_char */ 16, /* ar_max_namelen */ - 1, /* minimum alignment */ bfd_getb64, bfd_getb_signed_64, bfd_putb64, bfd_getb32, bfd_getb_signed_32, bfd_putb32, bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ diff --git a/bfd/targets.c b/bfd/targets.c index 78a57a5ec6..911f2a783a 100644 --- a/bfd/targets.c +++ b/bfd/targets.c @@ -246,7 +246,9 @@ The general target vector. .CAT(NAME,_close_and_cleanup),\ .CAT(NAME,_bfd_free_cached_info),\ .CAT(NAME,_new_section_hook),\ -.CAT(NAME,_get_section_contents) +.CAT(NAME,_get_section_contents),\ +.CAT(NAME,_get_section_contents_in_window) +. . {* Called when the BFD is being closed to do any necessary cleanup. *} . boolean (*_close_and_cleanup) PARAMS ((bfd *)); . {* Ask the BFD to free all cached information. *} @@ -256,6 +258,9 @@ The general target vector. . {* Read the contents of a section. *} . boolean (*_bfd_get_section_contents) PARAMS ((bfd *, sec_ptr, PTR, . file_ptr, bfd_size_type)); +. boolean (*_bfd_get_section_contents_in_window) +. PARAMS ((bfd *, sec_ptr, bfd_window *, +. file_ptr, bfd_size_type)); . . {* Entry points to copy private data. *} .#define BFD_JUMP_TABLE_COPY(NAME)\ @@ -315,7 +320,7 @@ The general target vector. . struct orl *map, . unsigned int orl_count, . int stridx)); -. PTR (*_bfd_read_ar_hdr) PARAMS ((bfd *)); +. PTR (*_bfd_read_ar_hdr_fn) PARAMS ((bfd *)); . bfd * (*openr_next_archived_file) PARAMS ((bfd *arch, bfd *prev)); . int (*_bfd_stat_arch_elt) PARAMS ((bfd *, struct stat *)); . boolean (*_bfd_update_armap_timestamp) PARAMS ((bfd *));