Back to index

cell-binutils  2.17cvs20070401
bfdwin.c
Go to the documentation of this file.
00001 /* Support for memory-mapped windows into a BFD.
00002    Copyright 1995, 1996, 2001, 2002, 2003, 2005
00003    Free Software Foundation, Inc.
00004    Written by Cygnus Support.
00005 
00006 This file is part of BFD, the Binary File Descriptor library.
00007 
00008 This program is free software; you can redistribute it and/or modify
00009 it under the terms of the GNU General Public License as published by
00010 the Free Software Foundation; either version 2 of the License, or
00011 (at your option) any later version.
00012 
00013 This program is distributed in the hope that it will be useful,
00014 but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016 GNU General Public License for more details.
00017 
00018 You should have received a copy of the GNU General Public License
00019 along with this program; if not, write to the Free Software
00020 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
00021 
00022 #include "sysdep.h"
00023 
00024 #include "bfd.h"
00025 #include "libbfd.h"
00026 
00027 /* Currently, if USE_MMAP is undefined, none if the window stuff is
00028    used.  Okay, so it's mis-named.  At least the command-line option
00029    "--without-mmap" is more obvious than "--without-windows" or some
00030    such.  */
00031 
00032 #ifdef USE_MMAP
00033 
00034 #undef HAVE_MPROTECT /* code's not tested yet */
00035 
00036 #if HAVE_MMAP || HAVE_MPROTECT || HAVE_MADVISE
00037 #include <sys/mman.h>
00038 #endif
00039 
00040 #ifndef MAP_FILE
00041 #define MAP_FILE 0
00042 #endif
00043 
00044 static int debug_windows;
00045 
00046 /* The idea behind the next and refcount fields is that one mapped
00047    region can suffice for multiple read-only windows or multiple
00048    non-overlapping read-write windows.  It's not implemented yet
00049    though.  */
00050 
00051 /*
00052 INTERNAL_DEFINITION
00053 
00054 .struct _bfd_window_internal {
00055 .  struct _bfd_window_internal *next;
00056 .  void *data;
00057 .  bfd_size_type size;
00058 .  int refcount : 31;              {* should be enough...  *}
00059 .  unsigned mapped : 1;            {* 1 = mmap, 0 = malloc *}
00060 .};
00061 */
00062 
00063 void
00064 bfd_init_window (bfd_window *windowp)
00065 {
00066   windowp->data = 0;
00067   windowp->i = 0;
00068   windowp->size = 0;
00069 }
00070 
00071 void
00072 bfd_free_window (bfd_window *windowp)
00073 {
00074   bfd_window_internal *i = windowp->i;
00075   windowp->i = 0;
00076   windowp->data = 0;
00077   if (i == 0)
00078     return;
00079   i->refcount--;
00080   if (debug_windows)
00081     fprintf (stderr, "freeing window @%p<%p,%lx,%p>\n",
00082             windowp, windowp->data, windowp->size, windowp->i);
00083   if (i->refcount != 0)
00084     return;
00085 
00086   if (i->mapped)
00087     {
00088 #ifdef HAVE_MMAP
00089       munmap (i->data, i->size);
00090       goto no_free;
00091 #else
00092       abort ();
00093 #endif
00094     }
00095 #ifdef HAVE_MPROTECT
00096   mprotect (i->data, i->size, PROT_READ | PROT_WRITE);
00097 #endif
00098   free (i->data);
00099 #ifdef HAVE_MMAP
00100  no_free:
00101 #endif
00102   i->data = 0;
00103   /* There should be no more references to i at this point.  */
00104   free (i);
00105 }
00106 
00107 static int ok_to_map = 1;
00108 
00109 bfd_boolean
00110 bfd_get_file_window (bfd *abfd,
00111                    file_ptr offset,
00112                    bfd_size_type size,
00113                    bfd_window *windowp,
00114                    bfd_boolean writable)
00115 {
00116   static size_t pagesize;
00117   bfd_window_internal *i = windowp->i;
00118   bfd_size_type size_to_alloc = size;
00119 
00120   if (debug_windows)
00121     fprintf (stderr, "bfd_get_file_window (%p, %6ld, %6ld, %p<%p,%lx,%p>, %d)",
00122             abfd, (long) offset, (long) size,
00123             windowp, windowp->data, (unsigned long) windowp->size,
00124             windowp->i, writable);
00125 
00126   /* Make sure we know the page size, so we can be friendly to mmap.  */
00127   if (pagesize == 0)
00128     pagesize = getpagesize ();
00129   if (pagesize == 0)
00130     abort ();
00131 
00132   if (i == 0)
00133     {
00134       i = bfd_zmalloc (sizeof (bfd_window_internal));
00135       windowp->i = i;
00136       if (i == 0)
00137        return FALSE;
00138       i->data = 0;
00139     }
00140 #ifdef HAVE_MMAP
00141   if (ok_to_map
00142       && (i->data == 0 || i->mapped == 1)
00143       && (abfd->flags & BFD_IN_MEMORY) == 0)
00144     {
00145       file_ptr file_offset, offset2;
00146       size_t real_size;
00147       int fd;
00148 
00149       /* Find the real file and the real offset into it.  */
00150       while (abfd->my_archive != NULL)
00151        {
00152          offset += abfd->origin;
00153          abfd = abfd->my_archive;
00154        }
00155 
00156       /* Seek into the file, to ensure it is open if cacheable.  */
00157       if (abfd->iostream == NULL
00158          && (abfd->iovec == NULL
00159              || abfd->iovec->bseek (abfd, offset, SEEK_SET) != 0))
00160        return FALSE;
00161       fd = fileno ((FILE *) abfd->iostream);
00162 
00163       /* Compute offsets and size for mmap and for the user's data.  */
00164       offset2 = offset % pagesize;
00165       if (offset2 < 0)
00166        abort ();
00167       file_offset = offset - offset2;
00168       real_size = offset + size - file_offset;
00169       real_size = real_size + pagesize - 1;
00170       real_size -= real_size % pagesize;
00171 
00172       /* If we're re-using a memory region, make sure it's big enough.  */
00173       if (i->data && i->size < size)
00174        {
00175          munmap (i->data, i->size);
00176          i->data = 0;
00177        }
00178       i->data = mmap (i->data, real_size,
00179                     writable ? PROT_WRITE | PROT_READ : PROT_READ,
00180                     (writable
00181                      ? MAP_FILE | MAP_PRIVATE
00182                      : MAP_FILE | MAP_SHARED),
00183                     fd, file_offset);
00184       if (i->data == (void *) -1)
00185        {
00186          /* An error happened.  Report it, or try using malloc, or
00187             something.  */
00188          bfd_set_error (bfd_error_system_call);
00189          i->data = 0;
00190          windowp->data = 0;
00191          if (debug_windows)
00192            fprintf (stderr, "\t\tmmap failed!\n");
00193          return FALSE;
00194        }
00195       if (debug_windows)
00196        fprintf (stderr, "\n\tmapped %ld at %p, offset is %ld\n",
00197                (long) real_size, i->data, (long) offset2);
00198       i->size = real_size;
00199       windowp->data = (bfd_byte *) i->data + offset2;
00200       windowp->size = size;
00201       i->mapped = 1;
00202       return TRUE;
00203     }
00204   else if (debug_windows)
00205     {
00206       if (ok_to_map)
00207        fprintf (stderr, _("not mapping: data=%lx mapped=%d\n"),
00208                (unsigned long) i->data, (int) i->mapped);
00209       else
00210        fprintf (stderr, _("not mapping: env var not set\n"));
00211     }
00212 #else
00213   ok_to_map = 0;
00214 #endif
00215 
00216 #ifdef HAVE_MPROTECT
00217   if (!writable)
00218     {
00219       size_to_alloc += pagesize - 1;
00220       size_to_alloc -= size_to_alloc % pagesize;
00221     }
00222 #endif
00223   if (debug_windows)
00224     fprintf (stderr, "\n\t%s(%6ld)",
00225             i->data ? "realloc" : " malloc", (long) size_to_alloc);
00226   i->data = bfd_realloc (i->data, size_to_alloc);
00227   if (debug_windows)
00228     fprintf (stderr, "\t-> %p\n", i->data);
00229   i->refcount = 1;
00230   if (i->data == NULL)
00231     {
00232       if (size_to_alloc == 0)
00233        return TRUE;
00234       return FALSE;
00235     }
00236   if (bfd_seek (abfd, offset, SEEK_SET) != 0)
00237     return FALSE;
00238   i->size = bfd_bread (i->data, size, abfd);
00239   if (i->size != size)
00240     return FALSE;
00241   i->mapped = 0;
00242 #ifdef HAVE_MPROTECT
00243   if (!writable)
00244     {
00245       if (debug_windows)
00246        fprintf (stderr, "\tmprotect (%p, %ld, PROT_READ)\n", i->data,
00247                (long) i->size);
00248       mprotect (i->data, i->size, PROT_READ);
00249     }
00250 #endif
00251   windowp->data = i->data;
00252   windowp->size = i->size;
00253   return TRUE;
00254 }
00255 
00256 #endif /* USE_MMAP */