inbound sim/common patch: mmap support

Frank Ch. Eigler fche@redhat.com
Fri Mar 16 13:29:00 GMT 2001


Hi -

In the absence of complaints, I plan to commit the following patch
to sim/common shortly.  It implements a new option "--memory-mapfile FILE",
used as a prefix to the other "--memory-region/alias/size" commands.
It allows user-defined simulated memory regions to be mmap'd to a file.
This allows an external program to share target memory with the simulator.

(A similar patch went into sid a few days ago; this way, even dissimilar
simulators can work together to model a shared-memory system.)

I tested it on a couple of platforms, and added in some token autoconf
tests.  It looks pretty portable to me -- improvement suggestions are
welcome.

- FChE


2001-03-16  Frank Ch. Eigler  <fche@redhat.com>

	Add support for mmap-based memory regions.
	* sim-memopt.c (mmap_next_fd): New global.
	(sim_memory_init): Reinitialize it.
	(OPTION_MEMORY_MAPFILE, memory_option_handler): Support new
	"--memory-mapfile FILE" option.  Check for some errors.
	(do_memopt_add): Conditionally do mmap instead of malloc for
	backing store of simulated memory.  Check for more errors.
	(do_simopt_delete, sim_memory_uninstall): Corresponding cleanup.
	* sim-memopt.h (munmap_length): New member of _sim_memopt.
	* configure.in: Look for mmap/fstat related functions and headers.
	* config.in, configure: Regenerated.


Index: config.in
===================================================================
RCS file: /cvs/src/src/sim/common/config.in,v
retrieving revision 1.1.1.1
diff -u -1 -0 -p -r1.1.1.1 config.in
--- config.in	1999/04/16 01:34:56	1.1.1.1
+++ config.in	2001/03/16 21:27:42
@@ -75,20 +75,23 @@
 
 /* Define if you have the getcwd function.  */
 #undef HAVE_GETCWD
 
 /* Define if you have the getpagesize function.  */
 #undef HAVE_GETPAGESIZE
 
 /* Define if you have the getrusage function.  */
 #undef HAVE_GETRUSAGE
 
+/* Define if you have the mmap function.  */
+#undef HAVE_MMAP
+
 /* Define if you have the munmap function.  */
 #undef HAVE_MUNMAP
 
 /* Define if you have the putenv function.  */
 #undef HAVE_PUTENV
 
 /* Define if you have the setenv function.  */
 #undef HAVE_SETENV
 
 /* Define if you have the setlocale function.  */
@@ -138,30 +141,42 @@
 
 /* Define if you have the <stdlib.h> header file.  */
 #undef HAVE_STDLIB_H
 
 /* Define if you have the <string.h> header file.  */
 #undef HAVE_STRING_H
 
 /* Define if you have the <strings.h> header file.  */
 #undef HAVE_STRINGS_H
 
+/* Define if you have the <sys/mman.h> header file.  */
+#undef HAVE_SYS_MMAN_H
+
 /* Define if you have the <sys/param.h> header file.  */
 #undef HAVE_SYS_PARAM_H
 
 /* Define if you have the <sys/resource.h> header file.  */
 #undef HAVE_SYS_RESOURCE_H
 
+/* Define if you have the <sys/stat.h> header file.  */
+#undef HAVE_SYS_STAT_H
+
 /* Define if you have the <sys/time.h> header file.  */
 #undef HAVE_SYS_TIME_H
 
 /* Define if you have the <sys/times.h> header file.  */
 #undef HAVE_SYS_TIMES_H
 
 /* Define if you have the <time.h> header file.  */
 #undef HAVE_TIME_H
 
 /* Define if you have the <unistd.h> header file.  */
 #undef HAVE_UNISTD_H
 
 /* Define if you have the <values.h> header file.  */
 #undef HAVE_VALUES_H
+
+/* Define if you have the nsl library (-lnsl).  */
+#undef HAVE_LIBNSL
+
+/* Define if you have the socket library (-lsocket).  */
+#undef HAVE_LIBSOCKET
Index: configure
===================================================================
RCS file: /cvs/src/src/sim/common/configure,v
retrieving revision 1.2
diff -u -1 -0 -p -r1.2 configure
--- configure	2000/05/24 04:39:47	1.2
+++ configure	2001/03/16 21:27:42
@@ -3515,21 +3515,21 @@ CPP_FOR_TARGET="\` \
 
 # Set TARGET_SUBDIR, needed by CPP_FOR_TARGET.
 if test x"${host}" = x"${target}" ; then
 	TARGET_SUBDIR="."
 else
 	TARGET_SUBDIR=${target_alias}
 fi
 
 
 # These aren't all needed yet, but will be eventually.
-for ac_hdr in stdlib.h string.h strings.h time.h sys/times.h
+for ac_hdr in stdlib.h string.h strings.h time.h sys/times.h sys/stat.h sys/mman.h
 do
 ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
 echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
 echo "configure:3530: checking for $ac_hdr" >&5
 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
 #line 3535 "configure"
 #include "confdefs.h"
@@ -3548,20 +3548,75 @@ else
   rm -rf conftest*
   eval "ac_cv_header_$ac_safe=no"
 fi
 rm -f conftest*
 fi
 if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
   echo "$ac_t""yes" 1>&6
     ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
   cat >> confdefs.h <<EOF
 #define $ac_tr_hdr 1
+EOF
+ 
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_func in mmap munmap
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:3569: checking for $ac_func" >&5
+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 <<EOF
+#line 3574 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* 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 echo configure:3597: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  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 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
 EOF
  
 else
   echo "$ac_t""no" 1>&6
 fi
 done
 
 
 trap '' 1 2 15
 cat > confcache <<\EOF
Index: configure.in
===================================================================
RCS file: /cvs/src/src/sim/common/configure.in,v
retrieving revision 1.1.1.1
diff -u -1 -0 -p -r1.1.1.1 configure.in
--- configure.in	1999/04/16 01:34:56	1.1.1.1
+++ configure.in	2001/03/16 21:27:42
@@ -27,14 +27,15 @@ AC_SUBST(CPP_FOR_TARGET)
 
 # Set TARGET_SUBDIR, needed by CPP_FOR_TARGET.
 if test x"${host}" = x"${target}" ; then
 	TARGET_SUBDIR="."
 else
 	TARGET_SUBDIR=${target_alias}
 fi
 AC_SUBST(TARGET_SUBDIR)
 
 # These aren't all needed yet, but will be eventually.
-AC_CHECK_HEADERS(stdlib.h string.h strings.h time.h sys/times.h)
+AC_CHECK_HEADERS(stdlib.h string.h strings.h time.h sys/times.h sys/stat.h sys/mman.h)
+AC_CHECK_FUNCS(mmap munmap)
 
 AC_OUTPUT(Makefile,
 [case x$CONFIG_HEADERS in xcconfig.h:config.in) echo > stamp-h ;; esac])
Index: sim-memopt.c
===================================================================
RCS file: /cvs/src/src/sim/common/sim-memopt.c,v
retrieving revision 1.1.1.2
diff -u -1 -0 -p -r1.1.1.2 sim-memopt.c
--- sim-memopt.c	1999/04/26 18:31:41	1.1.1.2
+++ sim-memopt.c	2001/03/16 21:27:42
@@ -11,49 +11,67 @@ any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 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.,
 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
+#include "cconfig.h"
+
 #include "sim-main.h"
 #include "sim-assert.h"
 #include "sim-options.h"
 
 #ifdef HAVE_STRING_H
 #include <string.h>
 #else
 #ifdef HAVE_STRINGS_H
 #include <strings.h>
 #endif
 #endif
 #ifdef HAVE_STDLIB_H
 #include <stdlib.h>
 #endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
 
-/* Memory fill byte */
+/* Memory fill byte. */
 static unsigned8 fill_byte_value;
 static int fill_byte_flag = 0;
 
+/* Memory mapping; see OPTION_MEMORY_MAPFILE. */
+static int mmap_next_fd = -1;
+
 /* Memory command line options. */
 
 enum {
   OPTION_MEMORY_DELETE = OPTION_START,
   OPTION_MEMORY_REGION,
   OPTION_MEMORY_SIZE,
   OPTION_MEMORY_INFO,
   OPTION_MEMORY_ALIAS,
   OPTION_MEMORY_CLEAR,
-  OPTION_MEMORY_FILL
+  OPTION_MEMORY_FILL,
+  OPTION_MEMORY_MAPFILE
 };
 
 static DECLARE_OPTION_HANDLER (memory_option_handler);
 
 static const OPTION memory_options[] =
 {
   { {"memory-delete", required_argument, NULL, OPTION_MEMORY_DELETE },
       '\0', "ADDRESS|all", "Delete memory at ADDRESS (all addresses)",
       memory_option_handler },
   { {"delete-memory", required_argument, NULL, OPTION_MEMORY_DELETE },
@@ -73,20 +91,26 @@ static const OPTION memory_options[] =
       memory_option_handler },
 
   { {"memory-fill", required_argument, NULL, OPTION_MEMORY_FILL },
       '\0', "VALUE", "Fill subsequently added memory regions",
       memory_option_handler },
 
   { {"memory-clear", no_argument, NULL, OPTION_MEMORY_CLEAR },
       '\0', NULL, "Clear subsequently added memory regions",
       memory_option_handler },
 
+#if defined(HAVE_MMAP) && defined(HAVE_MUNMAP)
+  { {"memory-mapfile", required_argument, NULL, OPTION_MEMORY_MAPFILE },
+      '\0', "FILE", "Memory-map next memory region from file",
+      memory_option_handler },
+#endif
+
   { {"memory-info", no_argument, NULL, OPTION_MEMORY_INFO },
       '\0', NULL, "List configurable memory regions",
       memory_option_handler },
   { {"info-memory", no_argument, NULL, OPTION_MEMORY_INFO },
       '\0', NULL, NULL,
       memory_option_handler },
 
   { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL }
 };
 
@@ -97,46 +121,81 @@ do_memopt_add (SIM_DESC sd,
 	       int space,
 	       address_word addr,
 	       address_word nr_bytes,
 	       unsigned modulo,
 	       sim_memopt **entry,
 	       void *buffer)
 {
   void *fill_buffer;
   unsigned fill_length;
   void *free_buffer;
+  unsigned long free_length;
 
   if (buffer != NULL)
     {
       /* Buffer already given.  sim_memory_uninstall will free it. */
       sim_core_attach (sd, NULL,
 		       level, access_read_write_exec, space,
 		       addr, nr_bytes, modulo, NULL, buffer);
 
       free_buffer = buffer;
+      free_length = 0;
       fill_buffer = buffer;
       fill_length = (modulo == 0) ? nr_bytes : modulo;
     }
   else
     {
       /* Allocate new well-aligned buffer, just as sim_core_attach(). */
       void *aligned_buffer;
       int padding = (addr % sizeof (unsigned64));
       unsigned long bytes = (modulo == 0 ? nr_bytes : modulo) + padding;
 
-      /* If filling with non-zero value, do not use clearing allocator. */
+      free_buffer = NULL;
+      free_length = bytes;
 
-      if (fill_byte_flag && fill_byte_value != 0)
-        free_buffer = xmalloc (bytes); /* don't clear */
-      else
-        free_buffer = zalloc (bytes); /* clear */
+#ifdef HAVE_MMAP
+      /* Memory map or malloc(). */
+      if (mmap_next_fd >= 0)
+	{
+	  /* Check that given file is big enough. */
+	  struct stat s;
+	  int rc;
+
+	  /* Some kernels will SIGBUS the application if mmap'd file
+	     is not large enough.  */ 
+	  rc = fstat (mmap_next_fd, &s);
+	  if (rc < 0 || s.st_size < bytes)
+	    {
+	      sim_io_error (sd,
+			    "Error, cannot confirm that mmap file is large enough "
+			    "(>= %d bytes)\n", bytes);
+	    }
+
+	  free_buffer = mmap (0, bytes, PROT_READ|PROT_WRITE, MAP_SHARED, mmap_next_fd, 0);
+	  if (free_buffer == 0 || free_buffer == (char*)-1) /* MAP_FAILED */
+	    {
+	      sim_io_error (sd, "Error, cannot mmap file (%s).\n",
+			    strerror(errno));
+	    }
+	}
+#endif 
 
+      /* Need heap allocation? */ 
+      if (free_buffer == NULL)
+	{
+	  /* If filling with non-zero value, do not use clearing allocator. */
+	  if (fill_byte_flag && fill_byte_value != 0)
+	    free_buffer = xmalloc (bytes); /* don't clear */
+	  else
+	    free_buffer = zalloc (bytes); /* clear */
+	}
+
       aligned_buffer = (char*) free_buffer + padding;
 
       sim_core_attach (sd, NULL,
 		       level, access_read_write_exec, space,
 		       addr, nr_bytes, modulo, NULL, aligned_buffer);
 
       fill_buffer = aligned_buffer;
       fill_length = (modulo == 0) ? nr_bytes : modulo;
 
       /* If we just used a clearing allocator, and are about to fill with
@@ -155,20 +214,30 @@ do_memopt_add (SIM_DESC sd,
   while ((*entry) != NULL)
     entry = &(*entry)->next;
   (*entry) = ZALLOC (sim_memopt);
   (*entry)->level = level;
   (*entry)->space = space;
   (*entry)->addr = addr;
   (*entry)->nr_bytes = nr_bytes;
   (*entry)->modulo = modulo;
   (*entry)->buffer = free_buffer;
 
+  /* Record memory unmapping info.  */
+  if (mmap_next_fd >= 0)
+    {
+      (*entry)->munmap_length = free_length;
+      close (mmap_next_fd);
+      mmap_next_fd = -1;
+    }
+  else
+    (*entry)->munmap_length = 0;
+
   return (*entry);
 }
 
 static SIM_RC
 do_memopt_delete (SIM_DESC sd,
 		  int level,
 		  int space,
 		  address_word addr)
 {
   sim_memopt **entry = &STATE_MEMOPT (sd);
@@ -179,21 +248,29 @@ do_memopt_delete (SIM_DESC sd,
 	      || (*entry)->addr != addr))
     entry = &(*entry)->next;
   if ((*entry) == NULL)
     {
       sim_io_eprintf (sd, "Memory at 0x%lx not found, not deleted\n",
 		      (long) addr);
       return SIM_RC_FAIL;
     }
   /* delete any buffer */
   if ((*entry)->buffer != NULL)
-    zfree ((*entry)->buffer);
+    {
+#ifdef HAVE_MUNMAP
+      if ((*entry)->munmap_length > 0)
+	munmap ((*entry)->buffer, (*entry)->munmap_length);
+      else
+#endif
+	zfree ((*entry)->buffer);
+    }
+
   /* delete it and its aliases */
   alias = *entry;
   *entry = (*entry)->next;
   while (alias != NULL)
     {
       sim_memopt *dead = alias;
       alias = alias->alias;
       sim_core_detach (sd, NULL, dead->level, dead->space, dead->addr);
       zfree (dead);
     }
@@ -360,20 +437,39 @@ memory_option_handler (SIM_DESC sd, sim_
 	  {
 	    sim_io_eprintf (sd, "Missing fill value between 0 and 255\n");
 	    return SIM_RC_FAIL;
 	  }
 	fill_byte_value = (unsigned8) fill_value;
 	fill_byte_flag = 1;
 	return SIM_RC_OK;
 	break;
       }
 
+    case OPTION_MEMORY_MAPFILE:
+      {
+	if (mmap_next_fd >= 0)
+	  {
+	    sim_io_eprintf (sd, "Duplicate memory-mapfile option\n");
+	    return SIM_RC_FAIL;
+	  }
+
+	mmap_next_fd = open (arg, O_RDWR);
+	if (mmap_next_fd < 0)
+	  {
+	    sim_io_eprintf (sd, "Cannot open file `%s': %s\n",
+			    arg, strerror(errno));
+	    return SIM_RC_FAIL;
+	  }
+
+	return SIM_RC_OK;
+      }
+
     case OPTION_MEMORY_INFO:
       {
 	sim_memopt *entry;
 	sim_io_printf (sd, "Memory maps:\n");
 	for (entry = STATE_MEMOPT (sd); entry != NULL; entry = entry->next)
 	  {
 	    sim_memopt *alias;
 	    sim_io_printf (sd, " memory");
 	    if (entry->alias == NULL)
 	      sim_io_printf (sd, " region ");
@@ -438,21 +534,28 @@ sim_memopt_install (SIM_DESC sd)
 static void
 sim_memory_uninstall (SIM_DESC sd)
 {
   sim_memopt **entry = &STATE_MEMOPT (sd);
   sim_memopt *alias;
 
   while ((*entry) != NULL)
     {
       /* delete any buffer */
       if ((*entry)->buffer != NULL)
-	zfree ((*entry)->buffer);
+	{
+#ifdef HAVE_MUNMAP
+	  if ((*entry)->munmap_length > 0)
+	    munmap ((*entry)->buffer, (*entry)->munmap_length);
+	  else
+#endif
+	    zfree ((*entry)->buffer);
+	}
 
       /* delete it and its aliases */
       alias = *entry;
 
       /* next victim */
       *entry = (*entry)->next;
 
       while (alias != NULL)
 	{
 	  sim_memopt *dead = alias;
@@ -460,13 +563,17 @@ sim_memory_uninstall (SIM_DESC sd)
 	  sim_core_detach (sd, NULL, dead->level, dead->space, dead->addr);
 	  zfree (dead);
 	}
     }
 }
 
 
 static SIM_RC
 sim_memory_init (SIM_DESC sd)
 {
-  /* FIXME: anything needed? */
+  /* Reinitialize option modifier flags, in case they were left
+     over from a previous sim startup event.  */
+  fill_byte_flag = 0;
+  mmap_next_fd = -1;
+
   return SIM_RC_OK;
 }
Index: sim-memopt.h
===================================================================
RCS file: /cvs/src/src/sim/common/sim-memopt.h,v
retrieving revision 1.1.1.1
diff -u -1 -0 -p -r1.1.1.1 sim-memopt.h
--- sim-memopt.h	1999/04/16 01:34:58	1.1.1.1
+++ sim-memopt.h	2001/03/16 21:27:42
@@ -24,20 +24,21 @@ with this program; if not, write to the 
 /* Provides a command line interface for manipulating the memory core */
 
 typedef struct _sim_memopt sim_memopt;
 struct _sim_memopt {
   int level;
   int space;
   unsigned_word addr;
   unsigned_word nr_bytes;
   unsigned modulo;
   void *buffer;
+  unsigned long munmap_length;
   sim_memopt *alias; /* linked list */
   sim_memopt *next;
 };
 
 
 /* Install the "memopt" module.  */
 
 SIM_RC sim_memopt_install (SIM_DESC sd);
 
 



More information about the Gdb-patches mailing list