| /* Simulator memory option handling. |
| Copyright (C) 1996-1999 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 |
| the Free Software Foundation; either version 2, 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. |
| |
| 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 "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 |
| |
| /* Memory fill byte */ |
| static unsigned8 fill_byte_value; |
| static int fill_byte_flag = 0; |
| |
| /* 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 |
| }; |
| |
| 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 }, |
| '\0', "ADDRESS", NULL, |
| memory_option_handler }, |
| |
| { {"memory-region", required_argument, NULL, OPTION_MEMORY_REGION }, |
| '\0', "ADDRESS,SIZE[,MODULO]", "Add a memory region", |
| memory_option_handler }, |
| |
| { {"memory-alias", required_argument, NULL, OPTION_MEMORY_ALIAS }, |
| '\0', "ADDRESS,SIZE{,ADDRESS}", "Add memory shadow", |
| memory_option_handler }, |
| |
| { {"memory-size", required_argument, NULL, OPTION_MEMORY_SIZE }, |
| '\0', "SIZE", "Add memory at address zero", |
| 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 }, |
| |
| { {"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 } |
| }; |
| |
| |
| static sim_memopt * |
| do_memopt_add (SIM_DESC sd, |
| int level, |
| 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; |
| |
| 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; |
| 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. */ |
| |
| 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 |
| zero, truncate the redundant fill operation. */ |
| |
| if (fill_byte_flag && fill_byte_value == 0) |
| fill_length = 1; /* avoid boundary length=0 case */ |
| } |
| |
| if (fill_byte_flag) |
| { |
| ASSERT (fill_buffer != 0); |
| memset ((char*) fill_buffer, fill_byte_value, fill_length); |
| } |
| |
| 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; |
| |
| return (*entry); |
| } |
| |
| static SIM_RC |
| do_memopt_delete (SIM_DESC sd, |
| int level, |
| int space, |
| address_word addr) |
| { |
| sim_memopt **entry = &STATE_MEMOPT (sd); |
| sim_memopt *alias; |
| while ((*entry) != NULL |
| && ((*entry)->level != level |
| || (*entry)->space != space |
| || (*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); |
| /* 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); |
| } |
| return SIM_RC_OK; |
| } |
| |
| |
| static char * |
| parse_size (char *chp, |
| address_word *nr_bytes, |
| unsigned *modulo) |
| { |
| /* <nr_bytes> [ "%" <modulo> ] */ |
| *nr_bytes = strtoul (chp, &chp, 0); |
| if (*chp == '%') |
| { |
| *modulo = strtoul (chp + 1, &chp, 0); |
| } |
| return chp; |
| } |
| |
| static char * |
| parse_ulong_value (char *chp, |
| unsigned long *value) |
| { |
| *value = strtoul (chp, &chp, 0); |
| return chp; |
| } |
| |
| static char * |
| parse_addr (char *chp, |
| int *level, |
| int *space, |
| address_word *addr) |
| { |
| /* [ <space> ": " ] <addr> [ "@" <level> ] */ |
| *addr = (unsigned long) strtoul (chp, &chp, 0); |
| if (*chp == ':') |
| { |
| *space = *addr; |
| *addr = (unsigned long) strtoul (chp + 1, &chp, 0); |
| } |
| if (*chp == '@') |
| { |
| *level = strtoul (chp + 1, &chp, 0); |
| } |
| return chp; |
| } |
| |
| |
| static SIM_RC |
| memory_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt, |
| char *arg, int is_command) |
| { |
| switch (opt) |
| { |
| |
| case OPTION_MEMORY_DELETE: |
| if (strcasecmp (arg, "all") == 0) |
| { |
| while (STATE_MEMOPT (sd) != NULL) |
| do_memopt_delete (sd, |
| STATE_MEMOPT (sd)->level, |
| STATE_MEMOPT (sd)->space, |
| STATE_MEMOPT (sd)->addr); |
| return SIM_RC_OK; |
| } |
| else |
| { |
| int level = 0; |
| int space = 0; |
| address_word addr = 0; |
| parse_addr (arg, &level, &space, &addr); |
| return do_memopt_delete (sd, level, space, addr); |
| } |
| |
| case OPTION_MEMORY_REGION: |
| { |
| char *chp = arg; |
| int level = 0; |
| int space = 0; |
| address_word addr = 0; |
| address_word nr_bytes = 0; |
| unsigned modulo = 0; |
| /* parse the arguments */ |
| chp = parse_addr (chp, &level, &space, &addr); |
| if (*chp != ',') |
| { |
| sim_io_eprintf (sd, "Missing size for memory-region\n"); |
| return SIM_RC_FAIL; |
| } |
| chp = parse_size (chp + 1, &nr_bytes, &modulo); |
| /* old style */ |
| if (*chp == ',') |
| modulo = strtoul (chp + 1, &chp, 0); |
| /* try to attach/insert it */ |
| do_memopt_add (sd, level, space, addr, nr_bytes, modulo, |
| &STATE_MEMOPT (sd), NULL); |
| return SIM_RC_OK; |
| } |
| |
| case OPTION_MEMORY_ALIAS: |
| { |
| char *chp = arg; |
| int level = 0; |
| int space = 0; |
| address_word addr = 0; |
| address_word nr_bytes = 0; |
| unsigned modulo = 0; |
| sim_memopt *entry; |
| /* parse the arguments */ |
| chp = parse_addr (chp, &level, &space, &addr); |
| if (*chp != ',') |
| { |
| sim_io_eprintf (sd, "Missing size for memory-region\n"); |
| return SIM_RC_FAIL; |
| } |
| chp = parse_size (chp + 1, &nr_bytes, &modulo); |
| /* try to attach/insert the main record */ |
| entry = do_memopt_add (sd, level, space, addr, nr_bytes, modulo, |
| &STATE_MEMOPT (sd), |
| NULL); |
| /* now attach all the aliases */ |
| while (*chp == ',') |
| { |
| int a_level = level; |
| int a_space = space; |
| address_word a_addr = addr; |
| chp = parse_addr (chp + 1, &a_level, &a_space, &a_addr); |
| do_memopt_add (sd, a_level, a_space, a_addr, nr_bytes, modulo, |
| &entry->alias, entry->buffer); |
| } |
| return SIM_RC_OK; |
| } |
| |
| case OPTION_MEMORY_SIZE: |
| { |
| int level = 0; |
| int space = 0; |
| address_word addr = 0; |
| address_word nr_bytes = 0; |
| unsigned modulo = 0; |
| /* parse the arguments */ |
| parse_size (arg, &nr_bytes, &modulo); |
| /* try to attach/insert it */ |
| do_memopt_add (sd, level, space, addr, nr_bytes, modulo, |
| &STATE_MEMOPT (sd), NULL); |
| return SIM_RC_OK; |
| } |
| |
| case OPTION_MEMORY_CLEAR: |
| { |
| fill_byte_value = (unsigned8) 0; |
| fill_byte_flag = 1; |
| return SIM_RC_OK; |
| break; |
| } |
| |
| case OPTION_MEMORY_FILL: |
| { |
| unsigned long fill_value; |
| parse_ulong_value (arg, &fill_value); |
| if (fill_value > 255) |
| { |
| 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_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 "); |
| else |
| sim_io_printf (sd, " alias "); |
| if (entry->space != 0) |
| sim_io_printf (sd, "0x%lx:", (long) entry->space); |
| sim_io_printf (sd, "0x%08lx", (long) entry->addr); |
| if (entry->level != 0) |
| sim_io_printf (sd, "@0x%lx", (long) entry->level); |
| sim_io_printf (sd, ",0x%lx", |
| (long) entry->nr_bytes); |
| if (entry->modulo != 0) |
| sim_io_printf (sd, "%%0x%lx", (long) entry->modulo); |
| for (alias = entry->alias; |
| alias != NULL; |
| alias = alias->next) |
| { |
| if (alias->space != 0) |
| sim_io_printf (sd, "0x%lx:", (long) alias->space); |
| sim_io_printf (sd, ",0x%08lx", (long) alias->addr); |
| if (alias->level != 0) |
| sim_io_printf (sd, "@0x%lx", (long) alias->level); |
| } |
| sim_io_printf (sd, "\n"); |
| } |
| return SIM_RC_OK; |
| break; |
| } |
| |
| default: |
| sim_io_eprintf (sd, "Unknown memory option %d\n", opt); |
| return SIM_RC_FAIL; |
| |
| } |
| |
| return SIM_RC_FAIL; |
| } |
| |
| |
| /* "memory" module install handler. |
| |
| This is called via sim_module_install to install the "memory" subsystem |
| into the simulator. */ |
| |
| static MODULE_INIT_FN sim_memory_init; |
| static MODULE_UNINSTALL_FN sim_memory_uninstall; |
| |
| SIM_RC |
| sim_memopt_install (SIM_DESC sd) |
| { |
| SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); |
| sim_add_option_table (sd, NULL, memory_options); |
| sim_module_add_uninstall_fn (sd, sim_memory_uninstall); |
| sim_module_add_init_fn (sd, sim_memory_init); |
| return SIM_RC_OK; |
| } |
| |
| |
| /* Uninstall the "memory" subsystem from the simulator. */ |
| |
| 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); |
| |
| /* delete it and its aliases */ |
| alias = *entry; |
| |
| /* next victim */ |
| *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); |
| } |
| } |
| } |
| |
| |
| static SIM_RC |
| sim_memory_init (SIM_DESC sd) |
| { |
| /* FIXME: anything needed? */ |
| return SIM_RC_OK; |
| } |