| 1 | /* Simulator memory option handling. |
| 2 | Copyright (C) 1996-1999 Free Software Foundation, Inc. |
| 3 | Contributed by Cygnus Support. |
| 4 | |
| 5 | This file is part of GDB, the GNU debugger. |
| 6 | |
| 7 | This program is free software; you can redistribute it and/or modify |
| 8 | it under the terms of the GNU General Public License as published by |
| 9 | the Free Software Foundation; either version 2, or (at your option) |
| 10 | any later version. |
| 11 | |
| 12 | This program is distributed in the hope that it will be useful, |
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 15 | GNU General Public License for more details. |
| 16 | |
| 17 | You should have received a copy of the GNU General Public License along |
| 18 | with this program; if not, write to the Free Software Foundation, Inc., |
| 19 | 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |
| 20 | |
| 21 | #include "sim-main.h" |
| 22 | #include "sim-assert.h" |
| 23 | #include "sim-options.h" |
| 24 | |
| 25 | #ifdef HAVE_STRING_H |
| 26 | #include <string.h> |
| 27 | #else |
| 28 | #ifdef HAVE_STRINGS_H |
| 29 | #include <strings.h> |
| 30 | #endif |
| 31 | #endif |
| 32 | #ifdef HAVE_STDLIB_H |
| 33 | #include <stdlib.h> |
| 34 | #endif |
| 35 | |
| 36 | /* Memory fill byte */ |
| 37 | static unsigned8 fill_byte_value; |
| 38 | static int fill_byte_flag = 0; |
| 39 | |
| 40 | /* Memory command line options. */ |
| 41 | |
| 42 | enum { |
| 43 | OPTION_MEMORY_DELETE = OPTION_START, |
| 44 | OPTION_MEMORY_REGION, |
| 45 | OPTION_MEMORY_SIZE, |
| 46 | OPTION_MEMORY_INFO, |
| 47 | OPTION_MEMORY_ALIAS, |
| 48 | OPTION_MEMORY_CLEAR, |
| 49 | OPTION_MEMORY_FILL |
| 50 | }; |
| 51 | |
| 52 | static DECLARE_OPTION_HANDLER (memory_option_handler); |
| 53 | |
| 54 | static const OPTION memory_options[] = |
| 55 | { |
| 56 | { {"memory-delete", required_argument, NULL, OPTION_MEMORY_DELETE }, |
| 57 | '\0', "ADDRESS|all", "Delete memory at ADDRESS (all addresses)", |
| 58 | memory_option_handler }, |
| 59 | { {"delete-memory", required_argument, NULL, OPTION_MEMORY_DELETE }, |
| 60 | '\0', "ADDRESS", NULL, |
| 61 | memory_option_handler }, |
| 62 | |
| 63 | { {"memory-region", required_argument, NULL, OPTION_MEMORY_REGION }, |
| 64 | '\0', "ADDRESS,SIZE[,MODULO]", "Add a memory region", |
| 65 | memory_option_handler }, |
| 66 | |
| 67 | { {"memory-alias", required_argument, NULL, OPTION_MEMORY_ALIAS }, |
| 68 | '\0', "ADDRESS,SIZE{,ADDRESS}", "Add memory shadow", |
| 69 | memory_option_handler }, |
| 70 | |
| 71 | { {"memory-size", required_argument, NULL, OPTION_MEMORY_SIZE }, |
| 72 | '\0', "SIZE", "Add memory at address zero", |
| 73 | memory_option_handler }, |
| 74 | |
| 75 | { {"memory-fill", required_argument, NULL, OPTION_MEMORY_FILL }, |
| 76 | '\0', "VALUE", "Fill subsequently added memory regions", |
| 77 | memory_option_handler }, |
| 78 | |
| 79 | { {"memory-clear", no_argument, NULL, OPTION_MEMORY_CLEAR }, |
| 80 | '\0', NULL, "Clear subsequently added memory regions", |
| 81 | memory_option_handler }, |
| 82 | |
| 83 | { {"memory-info", no_argument, NULL, OPTION_MEMORY_INFO }, |
| 84 | '\0', NULL, "List configurable memory regions", |
| 85 | memory_option_handler }, |
| 86 | { {"info-memory", no_argument, NULL, OPTION_MEMORY_INFO }, |
| 87 | '\0', NULL, NULL, |
| 88 | memory_option_handler }, |
| 89 | |
| 90 | { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL } |
| 91 | }; |
| 92 | |
| 93 | |
| 94 | static sim_memopt * |
| 95 | do_memopt_add (SIM_DESC sd, |
| 96 | int level, |
| 97 | int space, |
| 98 | address_word addr, |
| 99 | address_word nr_bytes, |
| 100 | unsigned modulo, |
| 101 | sim_memopt **entry, |
| 102 | void *buffer) |
| 103 | { |
| 104 | void *fill_buffer; |
| 105 | unsigned fill_length; |
| 106 | void *free_buffer; |
| 107 | |
| 108 | if (buffer != NULL) |
| 109 | { |
| 110 | /* Buffer already given. sim_memory_uninstall will free it. */ |
| 111 | sim_core_attach (sd, NULL, |
| 112 | level, access_read_write_exec, space, |
| 113 | addr, nr_bytes, modulo, NULL, buffer); |
| 114 | |
| 115 | free_buffer = buffer; |
| 116 | fill_buffer = buffer; |
| 117 | fill_length = (modulo == 0) ? nr_bytes : modulo; |
| 118 | } |
| 119 | else |
| 120 | { |
| 121 | /* Allocate new well-aligned buffer, just as sim_core_attach(). */ |
| 122 | void *aligned_buffer; |
| 123 | int padding = (addr % sizeof (unsigned64)); |
| 124 | unsigned long bytes = (modulo == 0 ? nr_bytes : modulo) + padding; |
| 125 | |
| 126 | /* If filling with non-zero value, do not use clearing allocator. */ |
| 127 | |
| 128 | if (fill_byte_flag && fill_byte_value != 0) |
| 129 | free_buffer = xmalloc (bytes); /* don't clear */ |
| 130 | else |
| 131 | free_buffer = zalloc (bytes); /* clear */ |
| 132 | |
| 133 | aligned_buffer = (char*) free_buffer + padding; |
| 134 | |
| 135 | sim_core_attach (sd, NULL, |
| 136 | level, access_read_write_exec, space, |
| 137 | addr, nr_bytes, modulo, NULL, aligned_buffer); |
| 138 | |
| 139 | fill_buffer = aligned_buffer; |
| 140 | fill_length = (modulo == 0) ? nr_bytes : modulo; |
| 141 | |
| 142 | /* If we just used a clearing allocator, and are about to fill with |
| 143 | zero, truncate the redundant fill operation. */ |
| 144 | |
| 145 | if (fill_byte_flag && fill_byte_value == 0) |
| 146 | fill_length = 1; /* avoid boundary length=0 case */ |
| 147 | } |
| 148 | |
| 149 | if (fill_byte_flag) |
| 150 | { |
| 151 | ASSERT (fill_buffer != 0); |
| 152 | memset ((char*) fill_buffer, fill_byte_value, fill_length); |
| 153 | } |
| 154 | |
| 155 | while ((*entry) != NULL) |
| 156 | entry = &(*entry)->next; |
| 157 | (*entry) = ZALLOC (sim_memopt); |
| 158 | (*entry)->level = level; |
| 159 | (*entry)->space = space; |
| 160 | (*entry)->addr = addr; |
| 161 | (*entry)->nr_bytes = nr_bytes; |
| 162 | (*entry)->modulo = modulo; |
| 163 | (*entry)->buffer = free_buffer; |
| 164 | |
| 165 | return (*entry); |
| 166 | } |
| 167 | |
| 168 | static SIM_RC |
| 169 | do_memopt_delete (SIM_DESC sd, |
| 170 | int level, |
| 171 | int space, |
| 172 | address_word addr) |
| 173 | { |
| 174 | sim_memopt **entry = &STATE_MEMOPT (sd); |
| 175 | sim_memopt *alias; |
| 176 | while ((*entry) != NULL |
| 177 | && ((*entry)->level != level |
| 178 | || (*entry)->space != space |
| 179 | || (*entry)->addr != addr)) |
| 180 | entry = &(*entry)->next; |
| 181 | if ((*entry) == NULL) |
| 182 | { |
| 183 | sim_io_eprintf (sd, "Memory at 0x%lx not found, not deleted\n", |
| 184 | (long) addr); |
| 185 | return SIM_RC_FAIL; |
| 186 | } |
| 187 | /* delete any buffer */ |
| 188 | if ((*entry)->buffer != NULL) |
| 189 | zfree ((*entry)->buffer); |
| 190 | /* delete it and its aliases */ |
| 191 | alias = *entry; |
| 192 | *entry = (*entry)->next; |
| 193 | while (alias != NULL) |
| 194 | { |
| 195 | sim_memopt *dead = alias; |
| 196 | alias = alias->alias; |
| 197 | sim_core_detach (sd, NULL, dead->level, dead->space, dead->addr); |
| 198 | zfree (dead); |
| 199 | } |
| 200 | return SIM_RC_OK; |
| 201 | } |
| 202 | |
| 203 | |
| 204 | static char * |
| 205 | parse_size (char *chp, |
| 206 | address_word *nr_bytes, |
| 207 | unsigned *modulo) |
| 208 | { |
| 209 | /* <nr_bytes> [ "%" <modulo> ] */ |
| 210 | *nr_bytes = strtoul (chp, &chp, 0); |
| 211 | if (*chp == '%') |
| 212 | { |
| 213 | *modulo = strtoul (chp + 1, &chp, 0); |
| 214 | } |
| 215 | return chp; |
| 216 | } |
| 217 | |
| 218 | static char * |
| 219 | parse_ulong_value (char *chp, |
| 220 | unsigned long *value) |
| 221 | { |
| 222 | *value = strtoul (chp, &chp, 0); |
| 223 | return chp; |
| 224 | } |
| 225 | |
| 226 | static char * |
| 227 | parse_addr (char *chp, |
| 228 | int *level, |
| 229 | int *space, |
| 230 | address_word *addr) |
| 231 | { |
| 232 | /* [ <space> ": " ] <addr> [ "@" <level> ] */ |
| 233 | *addr = (unsigned long) strtoul (chp, &chp, 0); |
| 234 | if (*chp == ':') |
| 235 | { |
| 236 | *space = *addr; |
| 237 | *addr = (unsigned long) strtoul (chp + 1, &chp, 0); |
| 238 | } |
| 239 | if (*chp == '@') |
| 240 | { |
| 241 | *level = strtoul (chp + 1, &chp, 0); |
| 242 | } |
| 243 | return chp; |
| 244 | } |
| 245 | |
| 246 | |
| 247 | static SIM_RC |
| 248 | memory_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt, |
| 249 | char *arg, int is_command) |
| 250 | { |
| 251 | switch (opt) |
| 252 | { |
| 253 | |
| 254 | case OPTION_MEMORY_DELETE: |
| 255 | if (strcasecmp (arg, "all") == 0) |
| 256 | { |
| 257 | while (STATE_MEMOPT (sd) != NULL) |
| 258 | do_memopt_delete (sd, |
| 259 | STATE_MEMOPT (sd)->level, |
| 260 | STATE_MEMOPT (sd)->space, |
| 261 | STATE_MEMOPT (sd)->addr); |
| 262 | return SIM_RC_OK; |
| 263 | } |
| 264 | else |
| 265 | { |
| 266 | int level = 0; |
| 267 | int space = 0; |
| 268 | address_word addr = 0; |
| 269 | parse_addr (arg, &level, &space, &addr); |
| 270 | return do_memopt_delete (sd, level, space, addr); |
| 271 | } |
| 272 | |
| 273 | case OPTION_MEMORY_REGION: |
| 274 | { |
| 275 | char *chp = arg; |
| 276 | int level = 0; |
| 277 | int space = 0; |
| 278 | address_word addr = 0; |
| 279 | address_word nr_bytes = 0; |
| 280 | unsigned modulo = 0; |
| 281 | /* parse the arguments */ |
| 282 | chp = parse_addr (chp, &level, &space, &addr); |
| 283 | if (*chp != ',') |
| 284 | { |
| 285 | sim_io_eprintf (sd, "Missing size for memory-region\n"); |
| 286 | return SIM_RC_FAIL; |
| 287 | } |
| 288 | chp = parse_size (chp + 1, &nr_bytes, &modulo); |
| 289 | /* old style */ |
| 290 | if (*chp == ',') |
| 291 | modulo = strtoul (chp + 1, &chp, 0); |
| 292 | /* try to attach/insert it */ |
| 293 | do_memopt_add (sd, level, space, addr, nr_bytes, modulo, |
| 294 | &STATE_MEMOPT (sd), NULL); |
| 295 | return SIM_RC_OK; |
| 296 | } |
| 297 | |
| 298 | case OPTION_MEMORY_ALIAS: |
| 299 | { |
| 300 | char *chp = arg; |
| 301 | int level = 0; |
| 302 | int space = 0; |
| 303 | address_word addr = 0; |
| 304 | address_word nr_bytes = 0; |
| 305 | unsigned modulo = 0; |
| 306 | sim_memopt *entry; |
| 307 | /* parse the arguments */ |
| 308 | chp = parse_addr (chp, &level, &space, &addr); |
| 309 | if (*chp != ',') |
| 310 | { |
| 311 | sim_io_eprintf (sd, "Missing size for memory-region\n"); |
| 312 | return SIM_RC_FAIL; |
| 313 | } |
| 314 | chp = parse_size (chp + 1, &nr_bytes, &modulo); |
| 315 | /* try to attach/insert the main record */ |
| 316 | entry = do_memopt_add (sd, level, space, addr, nr_bytes, modulo, |
| 317 | &STATE_MEMOPT (sd), |
| 318 | NULL); |
| 319 | /* now attach all the aliases */ |
| 320 | while (*chp == ',') |
| 321 | { |
| 322 | int a_level = level; |
| 323 | int a_space = space; |
| 324 | address_word a_addr = addr; |
| 325 | chp = parse_addr (chp + 1, &a_level, &a_space, &a_addr); |
| 326 | do_memopt_add (sd, a_level, a_space, a_addr, nr_bytes, modulo, |
| 327 | &entry->alias, entry->buffer); |
| 328 | } |
| 329 | return SIM_RC_OK; |
| 330 | } |
| 331 | |
| 332 | case OPTION_MEMORY_SIZE: |
| 333 | { |
| 334 | int level = 0; |
| 335 | int space = 0; |
| 336 | address_word addr = 0; |
| 337 | address_word nr_bytes = 0; |
| 338 | unsigned modulo = 0; |
| 339 | /* parse the arguments */ |
| 340 | parse_size (arg, &nr_bytes, &modulo); |
| 341 | /* try to attach/insert it */ |
| 342 | do_memopt_add (sd, level, space, addr, nr_bytes, modulo, |
| 343 | &STATE_MEMOPT (sd), NULL); |
| 344 | return SIM_RC_OK; |
| 345 | } |
| 346 | |
| 347 | case OPTION_MEMORY_CLEAR: |
| 348 | { |
| 349 | fill_byte_value = (unsigned8) 0; |
| 350 | fill_byte_flag = 1; |
| 351 | return SIM_RC_OK; |
| 352 | break; |
| 353 | } |
| 354 | |
| 355 | case OPTION_MEMORY_FILL: |
| 356 | { |
| 357 | unsigned long fill_value; |
| 358 | parse_ulong_value (arg, &fill_value); |
| 359 | if (fill_value > 255) |
| 360 | { |
| 361 | sim_io_eprintf (sd, "Missing fill value between 0 and 255\n"); |
| 362 | return SIM_RC_FAIL; |
| 363 | } |
| 364 | fill_byte_value = (unsigned8) fill_value; |
| 365 | fill_byte_flag = 1; |
| 366 | return SIM_RC_OK; |
| 367 | break; |
| 368 | } |
| 369 | |
| 370 | case OPTION_MEMORY_INFO: |
| 371 | { |
| 372 | sim_memopt *entry; |
| 373 | sim_io_printf (sd, "Memory maps:\n"); |
| 374 | for (entry = STATE_MEMOPT (sd); entry != NULL; entry = entry->next) |
| 375 | { |
| 376 | sim_memopt *alias; |
| 377 | sim_io_printf (sd, " memory"); |
| 378 | if (entry->alias == NULL) |
| 379 | sim_io_printf (sd, " region "); |
| 380 | else |
| 381 | sim_io_printf (sd, " alias "); |
| 382 | if (entry->space != 0) |
| 383 | sim_io_printf (sd, "0x%lx:", (long) entry->space); |
| 384 | sim_io_printf (sd, "0x%08lx", (long) entry->addr); |
| 385 | if (entry->level != 0) |
| 386 | sim_io_printf (sd, "@0x%lx", (long) entry->level); |
| 387 | sim_io_printf (sd, ",0x%lx", |
| 388 | (long) entry->nr_bytes); |
| 389 | if (entry->modulo != 0) |
| 390 | sim_io_printf (sd, "%%0x%lx", (long) entry->modulo); |
| 391 | for (alias = entry->alias; |
| 392 | alias != NULL; |
| 393 | alias = alias->next) |
| 394 | { |
| 395 | if (alias->space != 0) |
| 396 | sim_io_printf (sd, "0x%lx:", (long) alias->space); |
| 397 | sim_io_printf (sd, ",0x%08lx", (long) alias->addr); |
| 398 | if (alias->level != 0) |
| 399 | sim_io_printf (sd, "@0x%lx", (long) alias->level); |
| 400 | } |
| 401 | sim_io_printf (sd, "\n"); |
| 402 | } |
| 403 | return SIM_RC_OK; |
| 404 | break; |
| 405 | } |
| 406 | |
| 407 | default: |
| 408 | sim_io_eprintf (sd, "Unknown memory option %d\n", opt); |
| 409 | return SIM_RC_FAIL; |
| 410 | |
| 411 | } |
| 412 | |
| 413 | return SIM_RC_FAIL; |
| 414 | } |
| 415 | |
| 416 | |
| 417 | /* "memory" module install handler. |
| 418 | |
| 419 | This is called via sim_module_install to install the "memory" subsystem |
| 420 | into the simulator. */ |
| 421 | |
| 422 | static MODULE_INIT_FN sim_memory_init; |
| 423 | static MODULE_UNINSTALL_FN sim_memory_uninstall; |
| 424 | |
| 425 | SIM_RC |
| 426 | sim_memopt_install (SIM_DESC sd) |
| 427 | { |
| 428 | SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); |
| 429 | sim_add_option_table (sd, NULL, memory_options); |
| 430 | sim_module_add_uninstall_fn (sd, sim_memory_uninstall); |
| 431 | sim_module_add_init_fn (sd, sim_memory_init); |
| 432 | return SIM_RC_OK; |
| 433 | } |
| 434 | |
| 435 | |
| 436 | /* Uninstall the "memory" subsystem from the simulator. */ |
| 437 | |
| 438 | static void |
| 439 | sim_memory_uninstall (SIM_DESC sd) |
| 440 | { |
| 441 | sim_memopt **entry = &STATE_MEMOPT (sd); |
| 442 | sim_memopt *alias; |
| 443 | |
| 444 | while ((*entry) != NULL) |
| 445 | { |
| 446 | /* delete any buffer */ |
| 447 | if ((*entry)->buffer != NULL) |
| 448 | zfree ((*entry)->buffer); |
| 449 | |
| 450 | /* delete it and its aliases */ |
| 451 | alias = *entry; |
| 452 | |
| 453 | /* next victim */ |
| 454 | *entry = (*entry)->next; |
| 455 | |
| 456 | while (alias != NULL) |
| 457 | { |
| 458 | sim_memopt *dead = alias; |
| 459 | alias = alias->alias; |
| 460 | sim_core_detach (sd, NULL, dead->level, dead->space, dead->addr); |
| 461 | zfree (dead); |
| 462 | } |
| 463 | } |
| 464 | } |
| 465 | |
| 466 | |
| 467 | static SIM_RC |
| 468 | sim_memory_init (SIM_DESC sd) |
| 469 | { |
| 470 | /* FIXME: anything needed? */ |
| 471 | return SIM_RC_OK; |
| 472 | } |