This is the mail archive of the binutils-cvs@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[binutils-gdb] Use mmap and cache the view buffer for get_view


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=2aec968d4df313f893f239a1a69aef2392a16b85

commit 2aec968d4df313f893f239a1a69aef2392a16b85
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Fri Feb 6 09:05:35 2015 -0800

    Use mmap and cache the view buffer for get_view
    
    This patch uses mmap if it is available and works.  It also caches the
    view buffer for get_view.
    
    	* configure.ac: Add AC_FUNC_MMAP.
    	* config.in: Regenerated.
    	* configure: Likewise.
    	* plugin.c: Include <sys/mman.h>.
    	(MAP_FAILED): New.  Defined if not defined.
    	(PROT_READ): Likewise.
    	(MAP_PRIVATE): Likewise.
    	(view_buffer_t): New.
    	(plugin_input_file_t): Add view_buffer.
    	(get_view): Try mmap and cache the view buffer.
    	(plugin_maybe_claim): Initialize view_buffer.

Diff:
---
 ld/ChangeLog    |  14 +++++
 ld/config.in    |   6 ++
 ld/configure    | 182 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 ld/configure.ac |   3 +
 ld/plugin.c     |  89 +++++++++++++++++++++------
 5 files changed, 275 insertions(+), 19 deletions(-)

diff --git a/ld/ChangeLog b/ld/ChangeLog
index 4ae174b..e838ac8 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,3 +1,17 @@
+2015-02-06  H.J. Lu  <hongjiu.lu@intel.com>
+
+	* configure.ac: Add AC_FUNC_MMAP.
+	* config.in: Regenerated.
+	* configure: Likewise.
+	* plugin.c: Include <sys/mman.h>.
+	(MAP_FAILED): New.  Defined if not defined.
+	(PROT_READ): Likewise.
+	(MAP_PRIVATE): Likewise.
+	(view_buffer_t): New.
+	(plugin_input_file_t): Add view_buffer.
+	(get_view): Try mmap and cache the view buffer.
+	(plugin_maybe_claim): Initialize view_buffer.
+
 2015-02-05  H.J. Lu  <hongjiu.lu@intel.com>
 
 	* plugin.c (release_input_file): Set fd to -1 after closing it.
diff --git a/ld/config.in b/ld/config.in
index 2ab4844..ad015fe 100644
--- a/ld/config.in
+++ b/ld/config.in
@@ -56,6 +56,9 @@
 /* Define to 1 if you have the <fcntl.h> header file. */
 #undef HAVE_FCNTL_H
 
+/* Define to 1 if you have the `getpagesize' function. */
+#undef HAVE_GETPAGESIZE
+
 /* Define to 1 if you have the `glob' function. */
 #undef HAVE_GLOB
 
@@ -83,6 +86,9 @@
 /* Define to 1 if you have the `mkstemp' function. */
 #undef HAVE_MKSTEMP
 
+/* Define to 1 if you have a working `mmap' system call. */
+#undef HAVE_MMAP
+
 /* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
 #undef HAVE_NDIR_H
 
diff --git a/ld/configure b/ld/configure
index 8a7bd20..7af2626 100755
--- a/ld/configure
+++ b/ld/configure
@@ -16549,6 +16549,188 @@ fi
 fi
 
 
+for ac_header in stdlib.h unistd.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+eval as_val=\$$as_ac_Header
+   if test "x$as_val" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+for ac_func in getpagesize
+do :
+  ac_fn_c_check_func "$LINENO" "getpagesize" "ac_cv_func_getpagesize"
+if test "x$ac_cv_func_getpagesize" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_GETPAGESIZE 1
+_ACEOF
+
+fi
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working mmap" >&5
+$as_echo_n "checking for working mmap... " >&6; }
+if test "${ac_cv_func_mmap_fixed_mapped+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test "$cross_compiling" = yes; then :
+  ac_cv_func_mmap_fixed_mapped=no
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$ac_includes_default
+/* malloc might have been renamed as rpl_malloc. */
+#undef malloc
+
+/* Thanks to Mike Haertel and Jim Avera for this test.
+   Here is a matrix of mmap possibilities:
+	mmap private not fixed
+	mmap private fixed at somewhere currently unmapped
+	mmap private fixed at somewhere already mapped
+	mmap shared not fixed
+	mmap shared fixed at somewhere currently unmapped
+	mmap shared fixed at somewhere already mapped
+   For private mappings, we should verify that changes cannot be read()
+   back from the file, nor mmap's back from the file at a different
+   address.  (There have been systems where private was not correctly
+   implemented like the infamous i386 svr4.0, and systems where the
+   VM page cache was not coherent with the file system buffer cache
+   like early versions of FreeBSD and possibly contemporary NetBSD.)
+   For shared mappings, we should conversely verify that changes get
+   propagated back to all the places they're supposed to be.
+
+   Grep wants private fixed already mapped.
+   The main things grep needs to know about mmap are:
+   * does it exist and is it safe to write into the mmap'd area
+   * how to use it (BSD variants)  */
+
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#if !defined STDC_HEADERS && !defined HAVE_STDLIB_H
+char *malloc ();
+#endif
+
+/* This mess was copied from the GNU getpagesize.h.  */
+#ifndef HAVE_GETPAGESIZE
+/* Assume that all systems that can run configure have sys/param.h.  */
+# ifndef HAVE_SYS_PARAM_H
+#  define HAVE_SYS_PARAM_H 1
+# endif
+
+# ifdef _SC_PAGESIZE
+#  define getpagesize() sysconf(_SC_PAGESIZE)
+# else /* no _SC_PAGESIZE */
+#  ifdef HAVE_SYS_PARAM_H
+#   include <sys/param.h>
+#   ifdef EXEC_PAGESIZE
+#    define getpagesize() EXEC_PAGESIZE
+#   else /* no EXEC_PAGESIZE */
+#    ifdef NBPG
+#     define getpagesize() NBPG * CLSIZE
+#     ifndef CLSIZE
+#      define CLSIZE 1
+#     endif /* no CLSIZE */
+#    else /* no NBPG */
+#     ifdef NBPC
+#      define getpagesize() NBPC
+#     else /* no NBPC */
+#      ifdef PAGESIZE
+#       define getpagesize() PAGESIZE
+#      endif /* PAGESIZE */
+#     endif /* no NBPC */
+#    endif /* no NBPG */
+#   endif /* no EXEC_PAGESIZE */
+#  else /* no HAVE_SYS_PARAM_H */
+#   define getpagesize() 8192	/* punt totally */
+#  endif /* no HAVE_SYS_PARAM_H */
+# endif /* no _SC_PAGESIZE */
+
+#endif /* no HAVE_GETPAGESIZE */
+
+int
+main ()
+{
+  char *data, *data2, *data3;
+  int i, pagesize;
+  int fd;
+
+  pagesize = getpagesize ();
+
+  /* First, make a file with some known garbage in it. */
+  data = (char *) malloc (pagesize);
+  if (!data)
+    return 1;
+  for (i = 0; i < pagesize; ++i)
+    *(data + i) = rand ();
+  umask (0);
+  fd = creat ("conftest.mmap", 0600);
+  if (fd < 0)
+    return 1;
+  if (write (fd, data, pagesize) != pagesize)
+    return 1;
+  close (fd);
+
+  /* Next, try to mmap the file at a fixed address which already has
+     something else allocated at it.  If we can, also make sure that
+     we see the same garbage.  */
+  fd = open ("conftest.mmap", O_RDWR);
+  if (fd < 0)
+    return 1;
+  data2 = (char *) malloc (2 * pagesize);
+  if (!data2)
+    return 1;
+  data2 += (pagesize - ((long int) data2 & (pagesize - 1))) & (pagesize - 1);
+  if (data2 != mmap (data2, pagesize, PROT_READ | PROT_WRITE,
+		     MAP_PRIVATE | MAP_FIXED, fd, 0L))
+    return 1;
+  for (i = 0; i < pagesize; ++i)
+    if (*(data + i) != *(data2 + i))
+      return 1;
+
+  /* Finally, make sure that changes to the mapped area do not
+     percolate back to the file as seen by read().  (This is a bug on
+     some variants of i386 svr4.0.)  */
+  for (i = 0; i < pagesize; ++i)
+    *(data2 + i) = *(data2 + i) + 1;
+  data3 = (char *) malloc (pagesize);
+  if (!data3)
+    return 1;
+  if (read (fd, data3, pagesize) != pagesize)
+    return 1;
+  for (i = 0; i < pagesize; ++i)
+    if (*(data + i) != *(data3 + i))
+      return 1;
+  close (fd);
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  ac_cv_func_mmap_fixed_mapped=yes
+else
+  ac_cv_func_mmap_fixed_mapped=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_mmap_fixed_mapped" >&5
+$as_echo "$ac_cv_func_mmap_fixed_mapped" >&6; }
+if test $ac_cv_func_mmap_fixed_mapped = yes; then
+
+$as_echo "#define HAVE_MMAP 1" >>confdefs.h
+
+fi
+rm -f conftest.mmap
+
+
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing dlopen" >&5
 $as_echo_n "checking for library containing dlopen... " >&6; }
 if test "${ac_cv_search_dlopen+set}" = set; then :
diff --git a/ld/configure.ac b/ld/configure.ac
index 043c597..e926c03 100644
--- a/ld/configure.ac
+++ b/ld/configure.ac
@@ -195,6 +195,9 @@ AC_CHECK_FUNCS(glob mkstemp realpath sbrk setlocale waitpid)
 AC_CHECK_FUNCS(open lseek close)
 AC_HEADER_DIRENT
 
+dnl AC_CHECK_HEADERS(sys/mman.h)
+AC_FUNC_MMAP
+
 AC_SEARCH_LIBS([dlopen], [dl])
 AM_CONDITIONAL([ENABLE_PLUGINS], [test x$plugins = xyes])
 
diff --git a/ld/plugin.c b/ld/plugin.c
index ae0ac89..7ee45a2 100644
--- a/ld/plugin.c
+++ b/ld/plugin.c
@@ -32,6 +32,18 @@
 #include "plugin.h"
 #include "plugin-api.h"
 #include "elf-bfd.h"
+#if HAVE_MMAP
+# include <sys/mman.h>
+# ifndef MAP_FAILED
+#  define MAP_FAILED ((void *) -1)
+# endif
+# ifndef PROT_READ
+#  define PROT_READ 0
+# endif
+# ifndef MAP_PRIVATE
+#  define MAP_PRIVATE 0
+# endif
+#endif
 #include <errno.h>
 #if !(defined(errno) || defined(_MSC_VER) && defined(_INC_ERRNO))
 extern int errno;
@@ -76,11 +88,19 @@ typedef struct plugin
   bfd_boolean cleanup_done;
 } plugin_t;
 
+typedef struct view_buffer
+{
+  char *addr;
+  size_t filesize;
+  off_t offset;
+} view_buffer_t;
+
 /* The internal version of struct ld_plugin_input_file with a BFD
    pointer.  */
 typedef struct plugin_input_file
 {
   bfd *abfd;
+  view_buffer_t view_buffer;
   char *name;
   int fd;
   off_t offset;
@@ -475,35 +495,63 @@ get_input_file (const void *handle, struct ld_plugin_input_file *file)
 static enum ld_plugin_status
 get_view (const void *handle, const void **viewp)
 {
-  const plugin_input_file_t *input = handle;
+  plugin_input_file_t *input = (plugin_input_file_t *) handle;
   char *buffer;
-  size_t size;
+  size_t size = input->filesize;
 
   ASSERT (called_plugin);
 
-  if (lseek (input->fd, input->offset, SEEK_SET) < 0)
-    return LDPS_ERR;
+  /* FIXME: einfo should support %lld.  */
+  if ((off_t) size != input->filesize)
+    einfo (_("%P%F: unsupported input file size: %s (%ld bytes)\n"),
+	   input->name, (long) input->filesize);
 
-  size = input->filesize;
-  buffer = bfd_alloc (input->abfd, size);
-  if (buffer == NULL)
-    return LDPS_ERR;
-  *viewp = buffer;
+  /* Check the cached view buffer.  */
+  if (input->view_buffer.addr != NULL
+      && input->view_buffer.filesize == size
+      && input->view_buffer.offset == input->offset)
+    {
+      *viewp = input->view_buffer.addr;
+      return LDPS_OK;
+    }
+
+  input->view_buffer.filesize = size;
+  input->view_buffer.offset = input->offset;
 
-  do
+#if HAVE_MMAP
+  buffer = mmap (NULL, size, PROT_READ, MAP_PRIVATE, input->fd,
+		 input->offset);
+  if (buffer == MAP_FAILED)
+#endif
     {
-      ssize_t got = read (input->fd, buffer, size);
-      if (got == 0)
-	break;
-      else if (got > 0)
+      char *p;
+
+      if (lseek (input->fd, input->offset, SEEK_SET) < 0)
+	return LDPS_ERR;
+
+      buffer = bfd_alloc (input->abfd, size);
+      if (buffer == NULL)
+	return LDPS_ERR;
+
+      p = buffer;
+      do
 	{
-	  buffer += got;
-	  size -= got;
+	  ssize_t got = read (input->fd, p, size);
+	  if (got == 0)
+	    break;
+	  else if (got > 0)
+	    {
+	      p += got;
+	      size -= got;
+	    }
+	  else if (errno != EINTR)
+	    return LDPS_ERR;
 	}
-      else if (errno != EINTR)
-	return LDPS_ERR;
+      while (size > 0);
     }
-  while (size > 0);
+
+  input->view_buffer.addr = buffer;
+  *viewp = buffer;
 
   return LDPS_OK;
 }
@@ -951,6 +999,9 @@ plugin_maybe_claim (struct ld_plugin_input_file *file,
 	   bfd_get_error ());
 
   input->abfd = abfd;
+  input->view_buffer.addr = NULL;
+  input->view_buffer.filesize = 0;
+  input->view_buffer.offset = 0;
   input->fd = file->fd;
   input->offset  = file->offset;
   input->filesize = file->filesize;


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]