lto: Don't add indirect symbols for versioned aliases in IR
[binutils-gdb.git] / sim / common / sim-memopt.c
index 6e12a4555295a4c3a2af833396e75cdeb74a2b20..7d46a864afc56920f8364f72d7210b61e6af1718 100644 (file)
@@ -1,42 +1,48 @@
 /* Simulator memory option handling.
 /* Simulator memory option handling.
-   Copyright (C) 1996-1999 Free Software Foundation, Inc.
+   Copyright (C) 1996-2023 Free Software Foundation, Inc.
    Contributed by Cygnus Support.
 
 This file is part of GDB, the GNU debugger.
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
    Contributed by Cygnus Support.
 
 This file is part of GDB, the GNU debugger.
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+the Free Software Foundation; either version 3 of the License, or
+(at your option) 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.
 
 
 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.  */
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 
-#include "sim-main.h"
-#include "sim-assert.h"
-#include "sim-options.h"
+/* This must come before any other includes.  */
+#include "defs.h"
 
 
-#ifdef HAVE_STRING_H
-#include <string.h>
-#else
-#ifdef HAVE_STRINGS_H
-#include <strings.h>
-#endif
+#include <errno.h>
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
 #endif
 #endif
-#ifdef HAVE_STDLIB_H
 #include <stdlib.h>
 #include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
 #endif
 #endif
+#include <sys/stat.h>
+
+#include "sim-main.h"
+#include "sim-assert.h"
+#include "sim-options.h"
 
 
-/* Memory fill byte */
-static unsigned8 fill_byte_value;
+/* Memory fill byte. */
+static uint8_t fill_byte_value;
 static int fill_byte_flag = 0;
 
 static int fill_byte_flag = 0;
 
+/* Memory mapping; see OPTION_MEMORY_MAPFILE. */
+static int mmap_next_fd = -1;
+
 /* Memory command line options. */
 
 enum {
 /* Memory command line options. */
 
 enum {
@@ -46,7 +52,9 @@ enum {
   OPTION_MEMORY_INFO,
   OPTION_MEMORY_ALIAS,
   OPTION_MEMORY_CLEAR,
   OPTION_MEMORY_INFO,
   OPTION_MEMORY_ALIAS,
   OPTION_MEMORY_CLEAR,
-  OPTION_MEMORY_FILL
+  OPTION_MEMORY_FILL,
+  OPTION_MEMORY_MAPFILE,
+  OPTION_MAP_INFO
 };
 
 static DECLARE_OPTION_HANDLER (memory_option_handler);
 };
 
 static DECLARE_OPTION_HANDLER (memory_option_handler);
@@ -69,8 +77,8 @@ static const OPTION memory_options[] =
       memory_option_handler },
 
   { {"memory-size", required_argument, NULL, OPTION_MEMORY_SIZE },
       memory_option_handler },
 
   { {"memory-size", required_argument, NULL, OPTION_MEMORY_SIZE },
-      '\0', "SIZE", "Add memory at address zero",
-      memory_option_handler },
+      '\0', "<size>[in bytes, Kb (k suffix), Mb (m suffix) or Gb (g suffix)]",
+     "Add memory at address zero", memory_option_handler },
 
   { {"memory-fill", required_argument, NULL, OPTION_MEMORY_FILL },
       '\0', "VALUE", "Fill subsequently added memory regions",
 
   { {"memory-fill", required_argument, NULL, OPTION_MEMORY_FILL },
       '\0', "VALUE", "Fill subsequently added memory regions",
@@ -80,12 +88,21 @@ static const OPTION memory_options[] =
       '\0', NULL, "Clear subsequently added memory regions",
       memory_option_handler },
 
       '\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 },
   { {"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 },
+  { {"map-info", no_argument, NULL, OPTION_MAP_INFO },
+      '\0', NULL, "List mapped regions",
+      memory_option_handler },
 
   { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL }
 };
 
   { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL }
 };
@@ -104,6 +121,7 @@ do_memopt_add (SIM_DESC sd,
   void *fill_buffer;
   unsigned fill_length;
   void *free_buffer;
   void *fill_buffer;
   unsigned fill_length;
   void *free_buffer;
+  unsigned long free_length;
 
   if (buffer != NULL)
     {
 
   if (buffer != NULL)
     {
@@ -113,6 +131,7 @@ do_memopt_add (SIM_DESC sd,
                       addr, nr_bytes, modulo, NULL, buffer);
 
       free_buffer = buffer;
                       addr, nr_bytes, modulo, NULL, buffer);
 
       free_buffer = buffer;
+      free_length = 0;
       fill_buffer = buffer;
       fill_length = (modulo == 0) ? nr_bytes : modulo;
     }
       fill_buffer = buffer;
       fill_length = (modulo == 0) ? nr_bytes : modulo;
     }
@@ -120,15 +139,63 @@ do_memopt_add (SIM_DESC sd,
     {
       /* Allocate new well-aligned buffer, just as sim_core_attach(). */
       void *aligned_buffer;
     {
       /* 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;
+      int padding = (addr % sizeof (uint64_t));
+      unsigned long bytes;
 
 
-      /* If filling with non-zero value, do not use clearing allocator. */
+#ifdef HAVE_MMAP
+      struct stat s;
 
 
-      if (fill_byte_flag && fill_byte_value != 0)
-        free_buffer = xmalloc (bytes); /* don't clear */
-      else
-        free_buffer = zalloc (bytes); /* clear */
+      if (mmap_next_fd >= 0)
+       {
+         /* Check that given file is big enough. */
+         int rc = fstat (mmap_next_fd, &s);
+
+         if (rc < 0)
+           sim_io_error (sd, "Error, unable to stat file: %s\n",
+                         strerror (errno));
+
+         /* Autosize the mapping to the file length.  */
+         if (nr_bytes == 0)
+           nr_bytes = s.st_size;
+       }
+#endif
+
+      bytes = (modulo == 0 ? nr_bytes : modulo) + padding;
+
+      free_buffer = NULL;
+      free_length = bytes;
+
+#ifdef HAVE_MMAP
+      /* Memory map or malloc(). */
+      if (mmap_next_fd >= 0)
+       {
+         /* Some kernels will SIGBUS the application if mmap'd file
+            is not large enough.  */
+         if (s.st_size < bytes)
+           {
+             sim_io_error (sd,
+                           "Error, cannot confirm that mmap file is large enough "
+                           "(>= %ld 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;
 
 
       aligned_buffer = (char*) free_buffer + padding;
 
@@ -162,6 +229,16 @@ do_memopt_add (SIM_DESC sd,
   (*entry)->modulo = modulo;
   (*entry)->buffer = free_buffer;
 
   (*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);
 }
 
   return (*entry);
 }
 
@@ -186,7 +263,15 @@ do_memopt_delete (SIM_DESC sd,
     }
   /* delete any buffer */
   if ((*entry)->buffer != 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
+       free ((*entry)->buffer);
+    }
+
   /* delete it and its aliases */
   alias = *entry;
   *entry = (*entry)->next;
   /* delete it and its aliases */
   alias = *entry;
   *entry = (*entry)->next;
@@ -195,7 +280,7 @@ do_memopt_delete (SIM_DESC sd,
       sim_memopt *dead = alias;
       alias = alias->alias;
       sim_core_detach (sd, NULL, dead->level, dead->space, dead->addr);
       sim_memopt *dead = alias;
       alias = alias->alias;
       sim_core_detach (sd, NULL, dead->level, dead->space, dead->addr);
-      zfree (dead);
+      free (dead);
     }
   return SIM_RC_OK;
 }
     }
   return SIM_RC_OK;
 }
@@ -206,11 +291,28 @@ parse_size (char *chp,
            address_word *nr_bytes,
            unsigned *modulo)
 {
            address_word *nr_bytes,
            unsigned *modulo)
 {
-  /* <nr_bytes> [ "%" <modulo> ] */
+  /* <nr_bytes>[K|M|G] [ "%" <modulo> ] */
   *nr_bytes = strtoul (chp, &chp, 0);
   *nr_bytes = strtoul (chp, &chp, 0);
-  if (*chp == '%')
+  switch (*chp)
     {
     {
+    case '%':
       *modulo = strtoul (chp + 1, &chp, 0);
       *modulo = strtoul (chp + 1, &chp, 0);
+      break;
+    case 'g': case 'G': /* Gigabyte suffix.  */
+      *nr_bytes <<= 10;
+      /* Fall through.  */
+    case 'm': case 'M': /* Megabyte suffix.  */
+      *nr_bytes <<= 10;
+      /* Fall through.  */
+    case 'k': case 'K': /* Kilobyte suffix.  */
+      *nr_bytes <<= 10;
+      /* Check for a modulo specifier after the suffix.  */
+      ++ chp;
+      if (* chp == 'b' || * chp == 'B')
+       ++ chp;
+      if (* chp == '%')
+       *modulo = strtoul (chp + 1, &chp, 0);
+      break;
     }
   return chp;
 }
     }
   return chp;
 }
@@ -269,7 +371,7 @@ memory_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt,
          parse_addr (arg, &level, &space, &addr);
          return do_memopt_delete (sd, level, space, addr);
        }
          parse_addr (arg, &level, &space, &addr);
          return do_memopt_delete (sd, level, space, addr);
        }
-    
+
     case OPTION_MEMORY_REGION:
       {
        char *chp = arg;
     case OPTION_MEMORY_REGION:
       {
        char *chp = arg;
@@ -282,10 +384,15 @@ memory_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt,
        chp = parse_addr (chp, &level, &space, &addr);
        if (*chp != ',')
          {
        chp = parse_addr (chp, &level, &space, &addr);
        if (*chp != ',')
          {
-           sim_io_eprintf (sd, "Missing size for memory-region\n");
-           return SIM_RC_FAIL;
+           /* let the file autosize */
+           if (mmap_next_fd == -1)
+             {
+               sim_io_eprintf (sd, "Missing size for memory-region\n");
+               return SIM_RC_FAIL;
+             }
          }
          }
-       chp = parse_size (chp + 1, &nr_bytes, &modulo);
+       else
+         chp = parse_size (chp + 1, &nr_bytes, &modulo);
        /* old style */
        if (*chp == ',')
          modulo = strtoul (chp + 1, &chp, 0);
        /* old style */
        if (*chp == ',')
          modulo = strtoul (chp + 1, &chp, 0);
@@ -346,7 +453,7 @@ memory_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt,
 
     case OPTION_MEMORY_CLEAR:
       {
 
     case OPTION_MEMORY_CLEAR:
       {
-       fill_byte_value = (unsigned8) 0;
+       fill_byte_value = (uint8_t) 0;
        fill_byte_flag = 1;
        return SIM_RC_OK;
        break;
        fill_byte_flag = 1;
        return SIM_RC_OK;
        break;
@@ -361,12 +468,31 @@ memory_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt,
            sim_io_eprintf (sd, "Missing fill value between 0 and 255\n");
            return SIM_RC_FAIL;
          }
            sim_io_eprintf (sd, "Missing fill value between 0 and 255\n");
            return SIM_RC_FAIL;
          }
-       fill_byte_value = (unsigned8) fill_value;
+       fill_byte_value = (uint8_t) fill_value;
        fill_byte_flag = 1;
        return SIM_RC_OK;
        break;
       }
 
        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;
     case OPTION_MEMORY_INFO:
       {
        sim_memopt *entry;
@@ -404,6 +530,45 @@ memory_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt,
        break;
       }
 
        break;
       }
 
+    case OPTION_MAP_INFO:
+      {
+       sim_core *memory = STATE_CORE (sd);
+       unsigned nr_map;
+
+       for (nr_map = 0; nr_map < nr_maps; ++nr_map)
+         {
+           sim_core_map *map = &memory->common.map[nr_map];
+           sim_core_mapping *mapping = map->first;
+
+           if (!mapping)
+             continue;
+
+           sim_io_printf (sd, "%s maps:\n", map_to_str (nr_map));
+           do
+             {
+               unsigned modulo;
+
+               sim_io_printf (sd, " map ");
+               if (mapping->space != 0)
+                 sim_io_printf (sd, "0x%x:", mapping->space);
+               sim_io_printf (sd, "0x%08lx", (long) mapping->base);
+               if (mapping->level != 0)
+                 sim_io_printf (sd, "@0x%x", mapping->level);
+               sim_io_printf (sd, ",0x%lx", (long) mapping->nr_bytes);
+               modulo = mapping->mask + 1;
+               if (modulo != 0)
+                 sim_io_printf (sd, "%%0x%x", modulo);
+               sim_io_printf (sd, "\n");
+
+               mapping = mapping->next;
+             }
+           while (mapping);
+         }
+
+       return SIM_RC_OK;
+       break;
+      }
+
     default:
       sim_io_eprintf (sd, "Unknown memory option %d\n", opt);
       return SIM_RC_FAIL;
     default:
       sim_io_eprintf (sd, "Unknown memory option %d\n", opt);
       return SIM_RC_FAIL;
@@ -445,7 +610,14 @@ sim_memory_uninstall (SIM_DESC sd)
     {
       /* delete any buffer */
       if ((*entry)->buffer != 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
+           free ((*entry)->buffer);
+       }
 
       /* delete it and its aliases */
       alias = *entry;
 
       /* delete it and its aliases */
       alias = *entry;
@@ -458,15 +630,30 @@ sim_memory_uninstall (SIM_DESC sd)
          sim_memopt *dead = alias;
          alias = alias->alias;
          sim_core_detach (sd, NULL, dead->level, dead->space, dead->addr);
          sim_memopt *dead = alias;
          alias = alias->alias;
          sim_core_detach (sd, NULL, dead->level, dead->space, dead->addr);
-         zfree (dead);
+         free (dead);
        }
     }
 }
 
        }
     }
 }
 
+void sim_dump_memory (SIM_DESC sd);
+
+/* Convenience function for use when debugging the simulator, to be
+   called from within e.g. gdb.  */
+
+void
+sim_dump_memory (SIM_DESC sd)
+{
+  memory_option_handler (sd, NULL, OPTION_MEMORY_INFO, NULL, 0);
+  memory_option_handler (sd, NULL, OPTION_MAP_INFO, NULL, 0);
+}
 
 static SIM_RC
 sim_memory_init (SIM_DESC sd)
 {
 
 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;
 }
   return SIM_RC_OK;
 }