import gdb-2000-02-02 snapshot
[external/binutils.git] / bfd / libbfd.c
index 1c93970..fb833f6 100644 (file)
@@ -1,5 +1,6 @@
 /* Assorted BFD support routines, only used internally.
-   Copyright 1990, 1991, 1992 Free Software Foundation, Inc.
+   Copyright 1990, 91, 92, 93, 94, 95, 96, 97, 98, 1999
+   Free Software Foundation, Inc.
    Written by Cygnus Support.
 
 This file is part of BFD, the Binary File Descriptor library.
@@ -16,168 +17,202 @@ 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"
 
+#ifndef HAVE_GETPAGESIZE
+#define getpagesize() 2048
+#endif
+
+static int real_read PARAMS ((PTR, size_t, size_t, FILE *));
+
 /*
 SECTION
-       libbfd
+       Internal functions
 
 DESCRIPTION
-       This file contains various routines which are used within BFD.
+       These routines are used within BFD.
        They are not intended for export, but are documented here for
        completeness.
 */
 
-boolean
-DEFUN(_bfd_dummy_new_section_hook,(ignore, ignore_newsect),
-      bfd *ignore AND
-      asection *ignore_newsect)
-{
-  return true;
-}
+/* A routine which is used in target vectors for unsupported
+   operations.  */
 
+/*ARGSUSED*/
 boolean
-DEFUN(bfd_false ,(ignore),
-      bfd *ignore)
+bfd_false (ignore)
+     bfd *ignore ATTRIBUTE_UNUSED;
 {
+  bfd_set_error (bfd_error_invalid_operation);
   return false;
 }
 
+/* A routine which is used in target vectors for supported operations
+   which do not actually do anything.  */
+
+/*ARGSUSED*/
 boolean
-DEFUN(bfd_true,(ignore),
-      bfd *ignore)
+bfd_true (ignore)
+     bfd *ignore ATTRIBUTE_UNUSED;
 {
   return true;
 }
 
+/* A routine which is used in target vectors for unsupported
+   operations which return a pointer value.  */
+
+/*ARGSUSED*/
 PTR
-DEFUN(bfd_nullvoidptr,(ignore),
-      bfd *ignore)
+bfd_nullvoidptr (ignore)
+     bfd *ignore ATTRIBUTE_UNUSED;
 {
-  return (PTR)NULL;
+  bfd_set_error (bfd_error_invalid_operation);
+  return NULL;
 }
 
+/*ARGSUSED*/
 int 
-DEFUN(bfd_0,(ignore),
-      bfd *ignore)
+bfd_0 (ignore)
+     bfd *ignore ATTRIBUTE_UNUSED;
 {
   return 0;
 }
 
+/*ARGSUSED*/
 unsigned int 
-DEFUN(bfd_0u,(ignore),
-      bfd *ignore)
+bfd_0u (ignore)
+     bfd *ignore ATTRIBUTE_UNUSED;
 {
    return 0;
 }
 
+/*ARGUSED*/
+long
+bfd_0l (ignore)
+     bfd *ignore ATTRIBUTE_UNUSED;
+{
+  return 0;
+}
+
+/* A routine which is used in target vectors for unsupported
+   operations which return -1 on error.  */
+
+/*ARGSUSED*/
+long
+_bfd_n1 (ignore_abfd)
+     bfd *ignore_abfd ATTRIBUTE_UNUSED;
+{
+  bfd_set_error (bfd_error_invalid_operation);
+  return -1;
+}
+
+/*ARGSUSED*/
 void 
-DEFUN(bfd_void,(ignore),
-      bfd *ignore)
+bfd_void (ignore)
+     bfd *ignore ATTRIBUTE_UNUSED;
 {
 }
 
+/*ARGSUSED*/
 boolean
-DEFUN(_bfd_dummy_core_file_matches_executable_p,(ignore_core_bfd, ignore_exec_bfd),
-      bfd *ignore_core_bfd AND
-      bfd *ignore_exec_bfd)
+_bfd_nocore_core_file_matches_executable_p (ignore_core_bfd, ignore_exec_bfd)
+     bfd *ignore_core_bfd ATTRIBUTE_UNUSED;
+     bfd *ignore_exec_bfd ATTRIBUTE_UNUSED;
 {
-  bfd_error = invalid_operation;
+  bfd_set_error (bfd_error_invalid_operation);
   return false;
 }
 
-/* of course you can't initialize a function to be the same as another, grr */
+/* Routine to handle core_file_failing_command entry point for targets
+   without core file support.  */
 
+/*ARGSUSED*/
 char *
-DEFUN(_bfd_dummy_core_file_failing_command,(ignore_abfd),
-      bfd *ignore_abfd)
+_bfd_nocore_core_file_failing_command (ignore_abfd)
+     bfd *ignore_abfd ATTRIBUTE_UNUSED;
 {
+  bfd_set_error (bfd_error_invalid_operation);
   return (char *)NULL;
 }
 
+/* Routine to handle core_file_failing_signal entry point for targets
+   without core file support.  */
+
+/*ARGSUSED*/
 int
-DEFUN(_bfd_dummy_core_file_failing_signal,(ignore_abfd),
-     bfd *ignore_abfd)
+_bfd_nocore_core_file_failing_signal (ignore_abfd)
+     bfd *ignore_abfd ATTRIBUTE_UNUSED;
 {
+  bfd_set_error (bfd_error_invalid_operation);
   return 0;
 }
 
-bfd_target *
-DEFUN(_bfd_dummy_target,(ignore_abfd),
-     bfd *ignore_abfd)
+/*ARGSUSED*/
+const bfd_target *
+_bfd_dummy_target (ignore_abfd)
+     bfd *ignore_abfd ATTRIBUTE_UNUSED;
 {
+  bfd_set_error (bfd_error_wrong_format);
   return 0;
 }
 \f
-/** zalloc -- allocate and clear storage */
+/* Allocate memory using malloc.  */
 
-
-#ifndef zalloc
-char *
-DEFUN(zalloc,(size),
-      bfd_size_type size)
+PTR
+bfd_malloc (size)
+     size_t size;
 {
-  char *ptr = (char *) malloc ((size_t)size);
-
-  if ((ptr != NULL) && (size != 0))
-   memset(ptr,0, (size_t) size);
+  PTR ptr;
 
+  ptr = (PTR) malloc (size);
+  if (ptr == NULL && size != 0)
+    bfd_set_error (bfd_error_no_memory);
   return ptr;
 }
-#endif
 
-/*
-INTERNAL_FUNCTION
-       bfd_xmalloc
+/* Reallocate memory using realloc.  */
 
-SYNOPSIS
-       PTR  bfd_xmalloc( bfd_size_type size);
+PTR
+bfd_realloc (ptr, size)
+     PTR ptr;
+     size_t size;
+{
+  PTR ret;
 
-DESCRIPTION
-       Like malloc, but exit if no more memory.
+  if (ptr == NULL)
+    ret = malloc (size);
+  else
+    ret = realloc (ptr, size);
 
-*/
+  if (ret == NULL)
+    bfd_set_error (bfd_error_no_memory);
 
-/** There is major inconsistency in how running out of memory is handled.
-  Some routines return a NULL, and set bfd_error to no_memory.
-  However, obstack routines can't do this ... */
+  return ret;
+}
 
+/* Allocate memory using malloc and clear it.  */
 
-DEFUN(PTR bfd_xmalloc,(size),
-      bfd_size_type size)
+PTR
+bfd_zmalloc (size)
+     size_t size;
 {
-  static CONST char no_memory_message[] = "Virtual memory exhausted!\n";
   PTR ptr;
-  if (size == 0) size = 1;
-  ptr = (PTR)malloc((size_t) size);
-  if (!ptr)
-    {
-      write (2, no_memory_message, sizeof(no_memory_message)-1);
-      exit (-1);
-    }
-  return ptr;
-}
 
-/*
-INTERNAL_FUNCTION
-       bfd_xmalloc_by_size_t
+  ptr = (PTR) malloc (size);
 
-SYNOPSIS
-       PTR bfd_xmalloc_by_size_t ( size_t size);
+  if (size != 0)
+    {
+      if (ptr == NULL)
+       bfd_set_error (bfd_error_no_memory);
+      else
+       memset (ptr, 0, size);
+    }
 
-DESCRIPTION
-       Like malloc, but exit if no more memory.
-       Uses size_t, so it's suitable for use as obstack_chunk_alloc.
- */
-PTR
-DEFUN(bfd_xmalloc_by_size_t, (size),
-      size_t size)
-{
-  return bfd_xmalloc ((bfd_size_type) size);
+  return ptr;
 }
 \f
 /* Some IO code */
@@ -190,31 +225,314 @@ DEFUN(bfd_xmalloc_by_size_t, (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 DEFUN(real_read,(where, a,b, file),
-          PTR where AND
-          int a AND
-          int b AND
-          FILE *file)
+static int
+real_read (where, a,b, file)
+     PTR where;
+     size_t a;
+     size_t b;
+     FILE *file;
 {
-  return fread(where, a,b,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 (FIXME: how are errors and end of file dealt
+   with?  We never call bfd_set_error, which is probably a mistake).  */
+
 bfd_size_type
-DEFUN(bfd_read,(ptr, size, nitems, abfd),
-      PTR ptr AND
-      bfd_size_type size AND
-      bfd_size_type nitems AND
-      bfd *abfd)
+bfd_read (ptr, size, nitems, abfd)
+     PTR ptr;
+     bfd_size_type size;
+     bfd_size_type nitems;
+     bfd *abfd;
 {
   int nread;
-  nread = real_read (ptr, 1, (int)(size*nitems), bfd_cache_lookup(abfd));
-#ifdef FILE_OFFSET_IS_CHAR_INDEX
+
+  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 * nitems;
+      if (abfd->where + get > bim->size)
+       {
+         if (bim->size < abfd->where)
+           get = 0;
+         else
+           get = bim->size - abfd->where;
+         bfd_set_error (bfd_error_file_truncated);
+       }
+      memcpy (ptr, bim->buffer + abfd->where, get);
+      abfd->where += get;
+      return get;
+    }
+
+  nread = real_read (ptr, 1, (size_t)(size*nitems), bfd_cache_lookup(abfd));
   if (nread > 0)
     abfd->where += nread;
-#endif
+
+  /* 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 != (int) (size * nitems))
+    {
+      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;
+}
+\f
+/* 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;
+  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, (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)
+    {
+      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)
+      && (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;
+      bfd_set_error (bfd_error_no_memory);
+      return false;
+    }
+  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;
+}
+
+#endif /* USE_MMAP */
+\f
 bfd_size_type
 bfd_write (ptr, size, nitems, abfd)
      CONST PTR ptr;
@@ -222,18 +540,44 @@ bfd_write (ptr, size, nitems, abfd)
      bfd_size_type nitems;
      bfd *abfd;
 {
-  int nwrote = fwrite (ptr, 1, (int) (size * nitems), bfd_cache_lookup (abfd));
-#ifdef FILE_OFFSET_IS_CHAR_INDEX
+  long nwrote;
+
+  if ((abfd->flags & BFD_IN_MEMORY) != 0)
+    {
+      struct bfd_in_memory *bim = (struct bfd_in_memory *) (abfd->iostream);
+      size *= nitems;
+      if (abfd->where + size > bim->size)
+       {
+         long newsize, oldsize = (bim->size + 127) & ~127;
+         bim->size = abfd->where + size;
+         /* Round up to cut down on memory fragmentation */
+         newsize = (bim->size + 127) & ~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);
+      abfd->where += size;
+      return size;
+    }
+
+  nwrote = fwrite (ptr, 1, (size_t) (size * nitems),
+                  bfd_cache_lookup (abfd));
   if (nwrote > 0)
     abfd->where += nwrote;
-#endif
-  if (nwrote != size * nitems)
+  if ((bfd_size_type) nwrote != size * nitems)
     {
 #ifdef ENOSPC
       if (nwrote >= 0)
        errno = ENOSPC;
 #endif
-      bfd_error = system_call_error;
+      bfd_set_error (bfd_error_system_call);
     }
   return nwrote;
 }
@@ -246,27 +590,31 @@ SYNOPSIS
        void bfd_write_bigendian_4byte_int(bfd *abfd,  int i);
 
 DESCRIPTION
-       Writes a 4 byte integer to the outputing bfd, in big endian
-       mode regardless of what else is going on.  This is useful in
+       Write a 4 byte integer @var{i} to the output BFD @var{abfd}, in big
+       endian order regardless of what else is going on.  This is useful in
        archives.
 
 */
 void
-DEFUN(bfd_write_bigendian_4byte_int,(abfd, i),
-      bfd *abfd AND
-      int i)
+bfd_write_bigendian_4byte_int (abfd, i)
+     bfd *abfd;
+     int i;
 {
   bfd_byte buffer[4];
   bfd_putb32(i, buffer);
-  bfd_write((PTR)buffer, 4, 1, abfd);
+  if (bfd_write((PTR)buffer, 4, 1, abfd) != 4)
+    abort ();
 }
 
 long
-DEFUN(bfd_tell,(abfd),
-      bfd *abfd)
+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)
@@ -276,25 +624,47 @@ DEFUN(bfd_tell,(abfd),
 }
 
 int
-DEFUN(bfd_flush,(abfd),
-      bfd *abfd)
+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
-DEFUN(bfd_stat,(abfd, statbuf),
-      bfd *abfd AND
-      struct stat *statbuf)
+bfd_stat (abfd, statbuf)
+     bfd *abfd;
+     struct stat *statbuf;
 {
-  return fstat (fileno(bfd_cache_lookup(abfd)), 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
-DEFUN(bfd_seek,(abfd, position, direction),
-      bfd * CONST abfd AND
-      CONST file_ptr position AND
-      CONST int direction)
+bfd_seek (abfd, position, direction)
+     bfd *abfd;
+     file_ptr position;
+     int direction;
 {
   int result;
   FILE *f;
@@ -307,10 +677,31 @@ DEFUN(bfd_seek,(abfd, position, direction),
 
   if (direction == SEEK_CUR && position == 0)
     return 0;
-#ifdef FILE_OFFSET_IS_CHAR_INDEX
+
+  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)
+       {
+         abfd->where = bim->size;
+         bfd_set_error (bfd_error_file_truncated);
+         return -1;
+       }
+      
+      return 0;
+    }
+
   if (abfd->format != bfd_archive && abfd->my_archive == 0)
     {
-#ifndef NDEBUG
+#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'
@@ -341,7 +732,6 @@ DEFUN(bfd_seek,(abfd, position, direction),
 
         In the meantime, no optimization for archives.  */
     }
-#endif
 
   f = bfd_cache_lookup (abfd);
   file_position = position;
@@ -352,76 +742,32 @@ DEFUN(bfd_seek,(abfd, position, direction),
 
   if (result != 0)
     {
+      int hold_errno = errno;
+
       /* Force redetermination of `where' field.  */
       bfd_tell (abfd);
-      bfd_error = system_call_error;
+
+      /* 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
     {
-#ifdef FILE_OFFSET_IS_CHAR_INDEX
       /* Adjust `where' field.  */
       if (direction == SEEK_SET)
        abfd->where = position;
       else
        abfd->where += position;
-#endif
     }
   return result;
 }
 \f
-/** 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
-DEFUN(bfd_add_to_string_table,(table, new_string, table_length, free_ptr),
-      char **table AND
-      char *new_string AND
-      unsigned int *table_length AND
-      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 = zalloc ((bfd_size_type) space_length);
-
-    if (base == NULL) {
-      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_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;
-}
-\f
 /** The do-it-yourself (byte) sex-change kit */
 
 /* The middle letter e.g. get<b>short indicates Big or Little endian
@@ -446,22 +792,22 @@ DESCRIPTION
        mangling performs any necessary endian translations and
        removes alignment restrictions.  Note that types accepted and
        returned by these macros are identical so they can be swapped
-       around in macros--for example libaout.h defines GET_WORD to
-       either bfd_get_32 or bfd_get_64.
+       around in macros---for example, @file{libaout.h} defines <<GET_WORD>>
+       to either <<bfd_get_32>> or <<bfd_get_64>>.
 
-       In the put routines, val must be a bfd_vma.  If we are on a
+       In the put routines, @var{val} must be a <<bfd_vma>>.  If we are on a
        system without prototypes, the caller is responsible for making
        sure that is true, with a cast if necessary.  We don't cast
-       them in the macro definitions because that would prevent lint
-       or gcc -Wall from detecting sins such as passing a pointer.
-       To detect calling these with less than a bfd_vma, use gcc
-       -Wconversion on a host with 64 bit bfd_vma's.
+       them in the macro definitions because that would prevent <<lint>>
+       or <<gcc -Wall>> from detecting sins such as passing a pointer.
+       To detect calling these with less than a <<bfd_vma>>, use
+       <<gcc -Wconversion>> on a host with 64 bit <<bfd_vma>>'s.
 
 .
 .{* Byte swapping macros for user section data.  *}
 .
 .#define bfd_put_8(abfd, val, ptr) \
-.                (*((unsigned char *)(ptr)) = (unsigned char)val)
+.                ((void) (*((unsigned char *)(ptr)) = (unsigned char)(val)))
 .#define bfd_put_signed_8 \
 .              bfd_put_8
 .#define bfd_get_8(abfd, ptr) \
@@ -496,20 +842,33 @@ DESCRIPTION
 .#define bfd_get_signed_64(abfd, ptr) \
 .               BFD_SEND(abfd, bfd_getx_signed_64, (ptr))
 .
+.#define bfd_get(bits, abfd, ptr)                              \
+.                ((bits) == 8 ? bfd_get_8 (abfd, ptr)          \
+.               : (bits) == 16 ? bfd_get_16 (abfd, ptr)        \
+.               : (bits) == 32 ? bfd_get_32 (abfd, ptr)        \
+.               : (bits) == 64 ? bfd_get_64 (abfd, ptr)        \
+.               : (abort (), (bfd_vma) - 1))
+.
+.#define bfd_put(bits, abfd, val, ptr)                         \
+.                ((bits) == 8 ? bfd_put_8 (abfd, val, ptr)     \
+.               : (bits) == 16 ? bfd_put_16 (abfd, val, ptr)   \
+.               : (bits) == 32 ? bfd_put_32 (abfd, val, ptr)   \
+.               : (bits) == 64 ? bfd_put_64 (abfd, val, ptr)   \
+.               : (abort (), (void) 0))
+.
 */ 
 
 /*
 FUNCTION
        bfd_h_put_size
-FUNCTION
        bfd_h_get_size
 
 DESCRIPTION
        These macros have the same function as their <<bfd_get_x>>
-       bretherin, except that they are used for removing information
+       bretheren, except that they are used for removing information
        for the header records of object files. Believe it or not,
        some object files keep their header records in big endian
-       order, and their data in little endian order.
+       order and their data in little endian order.
 .
 .{* Byte swapping macros for file header data.  *}
 .
@@ -553,92 +912,113 @@ DESCRIPTION
 
 /* Sign extension to bfd_signed_vma.  */
 #define COERCE16(x) (((bfd_signed_vma) (x) ^ 0x8000) - 0x8000)
-#define COERCE32(x) (((bfd_signed_vma) (x) ^ 0x80000000) - 0x80000000)
-#define EIGHT_GAZILLION (((HOST_64_BIT)0x80000000) << 32)
+#define COERCE32(x) \
+  ((bfd_signed_vma) (long) (((unsigned long) (x) ^ 0x80000000) - 0x80000000))
+#define EIGHT_GAZILLION (((BFD_HOST_64_BIT)0x80000000) << 32)
 #define COERCE64(x) \
   (((bfd_signed_vma) (x) ^ EIGHT_GAZILLION) - EIGHT_GAZILLION)
 
 bfd_vma
-DEFUN(bfd_getb16,(addr),
-      register bfd_byte *addr)
+bfd_getb16 (addr)
+     register const bfd_byte *addr;
 {
-        return (addr[0] << 8) | addr[1];
+  return (addr[0] << 8) | addr[1];
 }
 
 bfd_vma
-DEFUN(bfd_getl16,(addr),
-      register bfd_byte *addr)
+bfd_getl16 (addr)
+     register const bfd_byte *addr;
 {
-        return (addr[1] << 8) | addr[0];
+  return (addr[1] << 8) | addr[0];
 }
 
 bfd_signed_vma
-DEFUN(bfd_getb_signed_16,(addr),
-      register bfd_byte *addr)
+bfd_getb_signed_16 (addr)
+     register const bfd_byte *addr;
 {
-        return COERCE16((addr[0] << 8) | addr[1]);
+  return COERCE16((addr[0] << 8) | addr[1]);
 }
 
 bfd_signed_vma
-DEFUN(bfd_getl_signed_16,(addr),
-      register bfd_byte *addr)
+bfd_getl_signed_16 (addr)
+     register const bfd_byte *addr;
 {
-        return COERCE16((addr[1] << 8) | addr[0]);
+  return COERCE16((addr[1] << 8) | addr[0]);
 }
 
 void
-DEFUN(bfd_putb16,(data, addr),
-      bfd_vma data AND
-      register bfd_byte *addr)
+bfd_putb16 (data, addr)
+     bfd_vma data;
+     register bfd_byte *addr;
 {
-        addr[0] = (bfd_byte)(data >> 8);
-        addr[1] = (bfd_byte )data;
+  addr[0] = (bfd_byte)(data >> 8);
+  addr[1] = (bfd_byte )data;
 }
 
 void
-DEFUN(bfd_putl16,(data, addr),
-      bfd_vma data AND              
-      register bfd_byte *addr)
+bfd_putl16 (data, addr)
+     bfd_vma data;             
+     register bfd_byte *addr;
 {
-        addr[0] = (bfd_byte )data;
-        addr[1] = (bfd_byte)(data >> 8);
+  addr[0] = (bfd_byte )data;
+  addr[1] = (bfd_byte)(data >> 8);
 }
 
 bfd_vma
 bfd_getb32 (addr)
-     register bfd_byte *addr;
+     register const bfd_byte *addr;
 {
-        return (((((bfd_vma)addr[0] << 8) | addr[1]) << 8)
-               | addr[2]) << 8 | addr[3];
+  unsigned long v;
+
+  v = (unsigned long) addr[0] << 24;
+  v |= (unsigned long) addr[1] << 16;
+  v |= (unsigned long) addr[2] << 8;
+  v |= (unsigned long) addr[3];
+  return (bfd_vma) v;
 }
 
 bfd_vma
 bfd_getl32 (addr)
-        register bfd_byte *addr;
+     register const bfd_byte *addr;
 {
-        return (((((bfd_vma)addr[3] << 8) | addr[2]) << 8)
-               | addr[1]) << 8 | addr[0];
+  unsigned long v;
+
+  v = (unsigned long) addr[0];
+  v |= (unsigned long) addr[1] << 8;
+  v |= (unsigned long) addr[2] << 16;
+  v |= (unsigned long) addr[3] << 24;
+  return (bfd_vma) v;
 }
 
 bfd_signed_vma
 bfd_getb_signed_32 (addr)
-     register bfd_byte *addr;
+     register const bfd_byte *addr;
 {
-        return COERCE32((((((bfd_vma)addr[0] << 8) | addr[1]) << 8)
-                        | addr[2]) << 8 | addr[3]);
+  unsigned long v;
+
+  v = (unsigned long) addr[0] << 24;
+  v |= (unsigned long) addr[1] << 16;
+  v |= (unsigned long) addr[2] << 8;
+  v |= (unsigned long) addr[3];
+  return COERCE32 (v);
 }
 
 bfd_signed_vma
 bfd_getl_signed_32 (addr)
-        register bfd_byte *addr;
+     register const bfd_byte *addr;
 {
-        return COERCE32((((((bfd_vma)addr[3] << 8) | addr[2]) << 8)
-                        | addr[1]) << 8 | addr[0]);
+  unsigned long v;
+
+  v = (unsigned long) addr[0];
+  v |= (unsigned long) addr[1] << 8;
+  v |= (unsigned long) addr[2] << 16;
+  v |= (unsigned long) addr[3] << 24;
+  return COERCE32 (v);
 }
 
 bfd_vma
-DEFUN(bfd_getb64,(addr),
-      register bfd_byte *addr)
+bfd_getb64 (addr)
+     register const bfd_byte *addr ATTRIBUTE_UNUSED;
 {
 #ifdef BFD64
   bfd_vma low, high;
@@ -658,14 +1038,12 @@ DEFUN(bfd_getb64,(addr),
   BFD_FAIL();
   return 0;
 #endif
-
 }
 
 bfd_vma
-DEFUN(bfd_getl64,(addr),
-      register bfd_byte *addr)
+bfd_getl64 (addr)
+     register const bfd_byte *addr ATTRIBUTE_UNUSED;
 {
-
 #ifdef BFD64
   bfd_vma low, high;
   high= (((((((addr[7] << 8) |
@@ -687,8 +1065,8 @@ DEFUN(bfd_getl64,(addr),
 }
 
 bfd_signed_vma
-DEFUN(bfd_getb_signed_64,(addr),
-      register bfd_byte *addr)
+bfd_getb_signed_64 (addr)
+     register const bfd_byte *addr ATTRIBUTE_UNUSED;
 {
 #ifdef BFD64
   bfd_vma low, high;
@@ -708,14 +1086,12 @@ DEFUN(bfd_getb_signed_64,(addr),
   BFD_FAIL();
   return 0;
 #endif
-
 }
 
 bfd_signed_vma
-DEFUN(bfd_getl_signed_64,(addr),
-      register bfd_byte *addr)
+bfd_getl_signed_64 (addr)
+     register const bfd_byte *addr ATTRIBUTE_UNUSED;
 {
-
 #ifdef BFD64
   bfd_vma low, high;
   high= (((((((addr[7] << 8) |
@@ -733,13 +1109,12 @@ DEFUN(bfd_getl_signed_64,(addr),
   BFD_FAIL();
   return 0;
 #endif
-
 }
 
 void
-DEFUN(bfd_putb32,(data, addr),
-      bfd_vma data AND
-      register bfd_byte *addr)
+bfd_putb32 (data, addr)
+     bfd_vma data;
+     register bfd_byte *addr;
 {
         addr[0] = (bfd_byte)(data >> 24);
         addr[1] = (bfd_byte)(data >> 16);
@@ -748,19 +1123,20 @@ DEFUN(bfd_putb32,(data, addr),
 }
 
 void
-DEFUN(bfd_putl32,(data, addr),
-      bfd_vma data AND
-      register bfd_byte *addr)
+bfd_putl32 (data, addr)
+     bfd_vma data;
+     register bfd_byte *addr;
 {
         addr[0] = (bfd_byte)data;
         addr[1] = (bfd_byte)(data >>  8);
         addr[2] = (bfd_byte)(data >> 16);
         addr[3] = (bfd_byte)(data >> 24);
 }
+
 void
-DEFUN(bfd_putb64,(data, addr),
-        bfd_vma data AND
-        register bfd_byte *addr)
+bfd_putb64 (data, addr)
+     bfd_vma data ATTRIBUTE_UNUSED;
+     register bfd_byte *addr ATTRIBUTE_UNUSED;
 {
 #ifdef BFD64
   addr[0] = (bfd_byte)(data >> (7*8));
@@ -774,13 +1150,12 @@ DEFUN(bfd_putb64,(data, addr),
 #else
   BFD_FAIL();
 #endif
-
 }
 
 void
-DEFUN(bfd_putl64,(data, addr),
-      bfd_vma data AND
-      register bfd_byte *addr)
+bfd_putl64 (data, addr)
+     bfd_vma data ATTRIBUTE_UNUSED;
+     register bfd_byte *addr ATTRIBUTE_UNUSED;
 {
 #ifdef BFD64
   addr[7] = (bfd_byte)(data >> (7*8));
@@ -794,27 +1169,77 @@ DEFUN(bfd_putl64,(data, addr),
 #else
   BFD_FAIL();
 #endif
-
 }
-
 \f
 /* Default implementation */
 
 boolean
-DEFUN(bfd_generic_get_section_contents, (abfd, section, location, offset, count),
-      bfd *abfd AND
-      sec_ptr section AND
-      PTR location AND
-      file_ptr offset AND
-      bfd_size_type count)
-{
-    if (count == 0)
-        return true;
-    if ((bfd_size_type)(offset+count) > section->_raw_size
-        || bfd_seek(abfd, (file_ptr)(section->filepos + offset), SEEK_SET) == -1
-        || bfd_read(location, (bfd_size_type)1, count, abfd) != count)
-        return (false); /* on error */
-    return (true);
+_bfd_generic_get_section_contents (abfd, section, location, offset, count)
+     bfd *abfd;
+     sec_ptr section;
+     PTR location;
+     file_ptr offset;
+     bfd_size_type count;
+{
+  if (count == 0)
+    return true;
+
+  if ((bfd_size_type) (offset + count) > section->_raw_size)
+    {
+      bfd_set_error (bfd_error_invalid_operation);
+      return false;
+    }
+
+  if (bfd_seek (abfd, section->filepos + offset, SEEK_SET) != 0
+      || bfd_read (location, (bfd_size_type) 1, count, abfd) != count)
+    return false;
+
+  return true;
+}
+
+boolean
+_bfd_generic_get_section_contents_in_window (abfd, section, w, offset, count)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     sec_ptr section ATTRIBUTE_UNUSED;
+     bfd_window *w ATTRIBUTE_UNUSED;
+     file_ptr offset ATTRIBUTE_UNUSED;
+     bfd_size_type count ATTRIBUTE_UNUSED;
+{
+#ifdef USE_MMAP
+  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) bfd_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, true)
+         == false))
+    return false;
+  return true;
+#else
+  abort ();
+#endif
 }
 
 /* This generic function can only be used in implementations where creating
@@ -822,7 +1247,7 @@ DEFUN(bfd_generic_get_section_contents, (abfd, section, location, offset, count)
    in read-write files, though.  See other set_section_contents functions
    to see why it doesn't work for new sections.  */
 boolean
-bfd_generic_set_section_contents (abfd, section, location, offset, count)
+_bfd_generic_set_section_contents (abfd, section, location, offset, count)
      bfd *abfd;
      sec_ptr section;
      PTR location;
@@ -832,12 +1257,6 @@ bfd_generic_set_section_contents (abfd, section, location, offset, count)
   if (count == 0)
     return true;
 
-  if (offset + count > bfd_get_section_size_after_reloc (section))
-    {
-      bfd_error = bad_value;
-      return false;
-    }
-
   if (bfd_seek (abfd, (file_ptr) (section->filepos + offset), SEEK_SET) == -1
       || bfd_write (location, (bfd_size_type) 1, count, abfd) != count)
     return false;
@@ -849,20 +1268,55 @@ bfd_generic_set_section_contents (abfd, section, location, offset, count)
 INTERNAL_FUNCTION
        bfd_log2
 
-DESCRIPTION
-       Return the log base 2 of the value supplied, rounded up. eg an
-       arg of 1025 would return 11.
-
 SYNOPSIS
        unsigned int bfd_log2(bfd_vma x);
+
+DESCRIPTION
+       Return the log base 2 of the value supplied, rounded up.  E.g., an
+       @var{x} of 1025 returns 11.
 */
 
-unsigned
-bfd_log2(x)
+unsigned int
+bfd_log2 (x)
      bfd_vma x;
 {
-  unsigned result = 0;
-  while ( (bfd_vma)(1<< result) < x)
-    result++;
+  unsigned int result = 0;
+
+  while ((x = (x >> 1)) != 0)
+    ++result;
   return result;
 }
+
+boolean
+bfd_generic_is_local_label_name (abfd, name)
+     bfd *abfd;
+     const char *name;
+{
+  char locals_prefix = (bfd_get_symbol_leading_char (abfd) == '_') ? 'L' : '.';
+
+  return (name[0] == locals_prefix);
+}
+
+/*  Can be used from / for bfd_merge_private_bfd_data to check that
+    endianness matches between input and output file.  Returns
+    true for a match, otherwise returns false and emits an error.  */
+boolean
+_bfd_generic_verify_endian_match (ibfd, obfd)
+     bfd *ibfd;
+     bfd *obfd;
+{
+  if (ibfd->xvec->byteorder != obfd->xvec->byteorder
+      && obfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN)
+    {
+      (*_bfd_error_handler)
+       ("%s: compiled for a %s endian system and target is %s endian",
+        bfd_get_filename (ibfd),
+        bfd_big_endian (ibfd) ? "big" : "little",
+        bfd_big_endian (obfd) ? "big" : "little");
+
+      bfd_set_error (bfd_error_wrong_format);
+      return false;
+    }
+
+  return true;
+}