| 1 | /* Simulator memory option handling. |
| 2 | Copyright (C) 1996-1999, 2007, 2008, 2009, 2010, 2011 |
| 3 | Free Software Foundation, Inc. |
| 4 | Contributed by Cygnus Support. |
| 5 | |
| 6 | This file is part of GDB, the GNU debugger. |
| 7 | |
| 8 | This program is free software; you can redistribute it and/or modify |
| 9 | it under the terms of the GNU General Public License as published by |
| 10 | the Free Software Foundation; either version 3 of the License, or |
| 11 | (at your option) any later version. |
| 12 | |
| 13 | This program is distributed in the hope that it will be useful, |
| 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 16 | GNU General Public License for more details. |
| 17 | |
| 18 | You should have received a copy of the GNU General Public License |
| 19 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
| 20 | |
| 21 | #include "cconfig.h" |
| 22 | |
| 23 | #include "sim-main.h" |
| 24 | #include "sim-assert.h" |
| 25 | #include "sim-options.h" |
| 26 | |
| 27 | #ifdef HAVE_STRING_H |
| 28 | #include <string.h> |
| 29 | #else |
| 30 | #ifdef HAVE_STRINGS_H |
| 31 | #include <strings.h> |
| 32 | #endif |
| 33 | #endif |
| 34 | #ifdef HAVE_STDLIB_H |
| 35 | #include <stdlib.h> |
| 36 | #endif |
| 37 | #ifdef HAVE_ERRNO_H |
| 38 | #include <errno.h> |
| 39 | #endif |
| 40 | #ifdef HAVE_FCNTL_H |
| 41 | #include <fcntl.h> |
| 42 | #endif |
| 43 | #ifdef HAVE_SYS_MMAN_H |
| 44 | #include <sys/mman.h> |
| 45 | #endif |
| 46 | #ifdef HAVE_SYS_STAT_H |
| 47 | #include <sys/stat.h> |
| 48 | #endif |
| 49 | #ifdef HAVE_UNISTD_H |
| 50 | #include <unistd.h> |
| 51 | #endif |
| 52 | |
| 53 | /* Memory fill byte. */ |
| 54 | static unsigned8 fill_byte_value; |
| 55 | static int fill_byte_flag = 0; |
| 56 | |
| 57 | /* Memory mapping; see OPTION_MEMORY_MAPFILE. */ |
| 58 | static int mmap_next_fd = -1; |
| 59 | |
| 60 | /* Memory command line options. */ |
| 61 | |
| 62 | enum { |
| 63 | OPTION_MEMORY_DELETE = OPTION_START, |
| 64 | OPTION_MEMORY_REGION, |
| 65 | OPTION_MEMORY_SIZE, |
| 66 | OPTION_MEMORY_INFO, |
| 67 | OPTION_MEMORY_ALIAS, |
| 68 | OPTION_MEMORY_CLEAR, |
| 69 | OPTION_MEMORY_FILL, |
| 70 | OPTION_MEMORY_MAPFILE, |
| 71 | OPTION_MAP_INFO |
| 72 | }; |
| 73 | |
| 74 | static DECLARE_OPTION_HANDLER (memory_option_handler); |
| 75 | |
| 76 | static const OPTION memory_options[] = |
| 77 | { |
| 78 | { {"memory-delete", required_argument, NULL, OPTION_MEMORY_DELETE }, |
| 79 | '\0', "ADDRESS|all", "Delete memory at ADDRESS (all addresses)", |
| 80 | memory_option_handler }, |
| 81 | { {"delete-memory", required_argument, NULL, OPTION_MEMORY_DELETE }, |
| 82 | '\0', "ADDRESS", NULL, |
| 83 | memory_option_handler }, |
| 84 | |
| 85 | { {"memory-region", required_argument, NULL, OPTION_MEMORY_REGION }, |
| 86 | '\0', "ADDRESS,SIZE[,MODULO]", "Add a memory region", |
| 87 | memory_option_handler }, |
| 88 | |
| 89 | { {"memory-alias", required_argument, NULL, OPTION_MEMORY_ALIAS }, |
| 90 | '\0', "ADDRESS,SIZE{,ADDRESS}", "Add memory shadow", |
| 91 | memory_option_handler }, |
| 92 | |
| 93 | { {"memory-size", required_argument, NULL, OPTION_MEMORY_SIZE }, |
| 94 | '\0', "<size>[in bytes, Kb (k suffix), Mb (m suffix) or Gb (g suffix)]", |
| 95 | "Add memory at address zero", memory_option_handler }, |
| 96 | |
| 97 | { {"memory-fill", required_argument, NULL, OPTION_MEMORY_FILL }, |
| 98 | '\0', "VALUE", "Fill subsequently added memory regions", |
| 99 | memory_option_handler }, |
| 100 | |
| 101 | { {"memory-clear", no_argument, NULL, OPTION_MEMORY_CLEAR }, |
| 102 | '\0', NULL, "Clear subsequently added memory regions", |
| 103 | memory_option_handler }, |
| 104 | |
| 105 | #if defined(HAVE_MMAP) && defined(HAVE_MUNMAP) |
| 106 | { {"memory-mapfile", required_argument, NULL, OPTION_MEMORY_MAPFILE }, |
| 107 | '\0', "FILE", "Memory-map next memory region from file", |
| 108 | memory_option_handler }, |
| 109 | #endif |
| 110 | |
| 111 | { {"memory-info", no_argument, NULL, OPTION_MEMORY_INFO }, |
| 112 | '\0', NULL, "List configurable memory regions", |
| 113 | memory_option_handler }, |
| 114 | { {"info-memory", no_argument, NULL, OPTION_MEMORY_INFO }, |
| 115 | '\0', NULL, NULL, |
| 116 | memory_option_handler }, |
| 117 | { {"map-info", no_argument, NULL, OPTION_MAP_INFO }, |
| 118 | '\0', NULL, "List mapped regions", |
| 119 | memory_option_handler }, |
| 120 | |
| 121 | { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL } |
| 122 | }; |
| 123 | |
| 124 | |
| 125 | static sim_memopt * |
| 126 | do_memopt_add (SIM_DESC sd, |
| 127 | int level, |
| 128 | int space, |
| 129 | address_word addr, |
| 130 | address_word nr_bytes, |
| 131 | unsigned modulo, |
| 132 | sim_memopt **entry, |
| 133 | void *buffer) |
| 134 | { |
| 135 | void *fill_buffer; |
| 136 | unsigned fill_length; |
| 137 | void *free_buffer; |
| 138 | unsigned long free_length; |
| 139 | |
| 140 | if (buffer != NULL) |
| 141 | { |
| 142 | /* Buffer already given. sim_memory_uninstall will free it. */ |
| 143 | sim_core_attach (sd, NULL, |
| 144 | level, access_read_write_exec, space, |
| 145 | addr, nr_bytes, modulo, NULL, buffer); |
| 146 | |
| 147 | free_buffer = buffer; |
| 148 | free_length = 0; |
| 149 | fill_buffer = buffer; |
| 150 | fill_length = (modulo == 0) ? nr_bytes : modulo; |
| 151 | } |
| 152 | else |
| 153 | { |
| 154 | /* Allocate new well-aligned buffer, just as sim_core_attach(). */ |
| 155 | void *aligned_buffer; |
| 156 | int padding = (addr % sizeof (unsigned64)); |
| 157 | unsigned long bytes; |
| 158 | |
| 159 | #ifdef HAVE_MMAP |
| 160 | struct stat s; |
| 161 | |
| 162 | if (mmap_next_fd >= 0) |
| 163 | { |
| 164 | /* Check that given file is big enough. */ |
| 165 | int rc = fstat (mmap_next_fd, &s); |
| 166 | |
| 167 | if (rc < 0) |
| 168 | sim_io_error (sd, "Error, unable to stat file: %s\n", |
| 169 | strerror (errno)); |
| 170 | |
| 171 | /* Autosize the mapping to the file length. */ |
| 172 | if (nr_bytes == 0) |
| 173 | nr_bytes = s.st_size; |
| 174 | } |
| 175 | #endif |
| 176 | |
| 177 | bytes = (modulo == 0 ? nr_bytes : modulo) + padding; |
| 178 | |
| 179 | free_buffer = NULL; |
| 180 | free_length = bytes; |
| 181 | |
| 182 | #ifdef HAVE_MMAP |
| 183 | /* Memory map or malloc(). */ |
| 184 | if (mmap_next_fd >= 0) |
| 185 | { |
| 186 | /* Some kernels will SIGBUS the application if mmap'd file |
| 187 | is not large enough. */ |
| 188 | if (s.st_size < bytes) |
| 189 | { |
| 190 | sim_io_error (sd, |
| 191 | "Error, cannot confirm that mmap file is large enough " |
| 192 | "(>= %ld bytes)\n", bytes); |
| 193 | } |
| 194 | |
| 195 | free_buffer = mmap (0, bytes, PROT_READ|PROT_WRITE, MAP_SHARED, mmap_next_fd, 0); |
| 196 | if (free_buffer == 0 || free_buffer == (char*)-1) /* MAP_FAILED */ |
| 197 | { |
| 198 | sim_io_error (sd, "Error, cannot mmap file (%s).\n", |
| 199 | strerror(errno)); |
| 200 | } |
| 201 | } |
| 202 | #endif |
| 203 | |
| 204 | /* Need heap allocation? */ |
| 205 | if (free_buffer == NULL) |
| 206 | { |
| 207 | /* If filling with non-zero value, do not use clearing allocator. */ |
| 208 | if (fill_byte_flag && fill_byte_value != 0) |
| 209 | free_buffer = xmalloc (bytes); /* don't clear */ |
| 210 | else |
| 211 | free_buffer = zalloc (bytes); /* clear */ |
| 212 | } |
| 213 | |
| 214 | aligned_buffer = (char*) free_buffer + padding; |
| 215 | |
| 216 | sim_core_attach (sd, NULL, |
| 217 | level, access_read_write_exec, space, |
| 218 | addr, nr_bytes, modulo, NULL, aligned_buffer); |
| 219 | |
| 220 | fill_buffer = aligned_buffer; |
| 221 | fill_length = (modulo == 0) ? nr_bytes : modulo; |
| 222 | |
| 223 | /* If we just used a clearing allocator, and are about to fill with |
| 224 | zero, truncate the redundant fill operation. */ |
| 225 | |
| 226 | if (fill_byte_flag && fill_byte_value == 0) |
| 227 | fill_length = 1; /* avoid boundary length=0 case */ |
| 228 | } |
| 229 | |
| 230 | if (fill_byte_flag) |
| 231 | { |
| 232 | ASSERT (fill_buffer != 0); |
| 233 | memset ((char*) fill_buffer, fill_byte_value, fill_length); |
| 234 | } |
| 235 | |
| 236 | while ((*entry) != NULL) |
| 237 | entry = &(*entry)->next; |
| 238 | (*entry) = ZALLOC (sim_memopt); |
| 239 | (*entry)->level = level; |
| 240 | (*entry)->space = space; |
| 241 | (*entry)->addr = addr; |
| 242 | (*entry)->nr_bytes = nr_bytes; |
| 243 | (*entry)->modulo = modulo; |
| 244 | (*entry)->buffer = free_buffer; |
| 245 | |
| 246 | /* Record memory unmapping info. */ |
| 247 | if (mmap_next_fd >= 0) |
| 248 | { |
| 249 | (*entry)->munmap_length = free_length; |
| 250 | close (mmap_next_fd); |
| 251 | mmap_next_fd = -1; |
| 252 | } |
| 253 | else |
| 254 | (*entry)->munmap_length = 0; |
| 255 | |
| 256 | return (*entry); |
| 257 | } |
| 258 | |
| 259 | static SIM_RC |
| 260 | do_memopt_delete (SIM_DESC sd, |
| 261 | int level, |
| 262 | int space, |
| 263 | address_word addr) |
| 264 | { |
| 265 | sim_memopt **entry = &STATE_MEMOPT (sd); |
| 266 | sim_memopt *alias; |
| 267 | while ((*entry) != NULL |
| 268 | && ((*entry)->level != level |
| 269 | || (*entry)->space != space |
| 270 | || (*entry)->addr != addr)) |
| 271 | entry = &(*entry)->next; |
| 272 | if ((*entry) == NULL) |
| 273 | { |
| 274 | sim_io_eprintf (sd, "Memory at 0x%lx not found, not deleted\n", |
| 275 | (long) addr); |
| 276 | return SIM_RC_FAIL; |
| 277 | } |
| 278 | /* delete any buffer */ |
| 279 | if ((*entry)->buffer != NULL) |
| 280 | { |
| 281 | #ifdef HAVE_MUNMAP |
| 282 | if ((*entry)->munmap_length > 0) |
| 283 | munmap ((*entry)->buffer, (*entry)->munmap_length); |
| 284 | else |
| 285 | #endif |
| 286 | free ((*entry)->buffer); |
| 287 | } |
| 288 | |
| 289 | /* delete it and its aliases */ |
| 290 | alias = *entry; |
| 291 | *entry = (*entry)->next; |
| 292 | while (alias != NULL) |
| 293 | { |
| 294 | sim_memopt *dead = alias; |
| 295 | alias = alias->alias; |
| 296 | sim_core_detach (sd, NULL, dead->level, dead->space, dead->addr); |
| 297 | free (dead); |
| 298 | } |
| 299 | return SIM_RC_OK; |
| 300 | } |
| 301 | |
| 302 | |
| 303 | static char * |
| 304 | parse_size (char *chp, |
| 305 | address_word *nr_bytes, |
| 306 | unsigned *modulo) |
| 307 | { |
| 308 | /* <nr_bytes>[K|M|G] [ "%" <modulo> ] */ |
| 309 | *nr_bytes = strtoul (chp, &chp, 0); |
| 310 | switch (*chp) |
| 311 | { |
| 312 | case '%': |
| 313 | *modulo = strtoul (chp + 1, &chp, 0); |
| 314 | break; |
| 315 | case 'g': case 'G': /* Gigabyte suffix. */ |
| 316 | *nr_bytes <<= 10; |
| 317 | /* Fall through. */ |
| 318 | case 'm': case 'M': /* Megabyte suffix. */ |
| 319 | *nr_bytes <<= 10; |
| 320 | /* Fall through. */ |
| 321 | case 'k': case 'K': /* Kilobyte suffix. */ |
| 322 | *nr_bytes <<= 10; |
| 323 | /* Check for a modulo specifier after the suffix. */ |
| 324 | ++ chp; |
| 325 | if (* chp == 'b' || * chp == 'B') |
| 326 | ++ chp; |
| 327 | if (* chp == '%') |
| 328 | *modulo = strtoul (chp + 1, &chp, 0); |
| 329 | break; |
| 330 | } |
| 331 | return chp; |
| 332 | } |
| 333 | |
| 334 | static char * |
| 335 | parse_ulong_value (char *chp, |
| 336 | unsigned long *value) |
| 337 | { |
| 338 | *value = strtoul (chp, &chp, 0); |
| 339 | return chp; |
| 340 | } |
| 341 | |
| 342 | static char * |
| 343 | parse_addr (char *chp, |
| 344 | int *level, |
| 345 | int *space, |
| 346 | address_word *addr) |
| 347 | { |
| 348 | /* [ <space> ": " ] <addr> [ "@" <level> ] */ |
| 349 | *addr = (unsigned long) strtoul (chp, &chp, 0); |
| 350 | if (*chp == ':') |
| 351 | { |
| 352 | *space = *addr; |
| 353 | *addr = (unsigned long) strtoul (chp + 1, &chp, 0); |
| 354 | } |
| 355 | if (*chp == '@') |
| 356 | { |
| 357 | *level = strtoul (chp + 1, &chp, 0); |
| 358 | } |
| 359 | return chp; |
| 360 | } |
| 361 | |
| 362 | |
| 363 | static SIM_RC |
| 364 | memory_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt, |
| 365 | char *arg, int is_command) |
| 366 | { |
| 367 | switch (opt) |
| 368 | { |
| 369 | |
| 370 | case OPTION_MEMORY_DELETE: |
| 371 | if (strcasecmp (arg, "all") == 0) |
| 372 | { |
| 373 | while (STATE_MEMOPT (sd) != NULL) |
| 374 | do_memopt_delete (sd, |
| 375 | STATE_MEMOPT (sd)->level, |
| 376 | STATE_MEMOPT (sd)->space, |
| 377 | STATE_MEMOPT (sd)->addr); |
| 378 | return SIM_RC_OK; |
| 379 | } |
| 380 | else |
| 381 | { |
| 382 | int level = 0; |
| 383 | int space = 0; |
| 384 | address_word addr = 0; |
| 385 | parse_addr (arg, &level, &space, &addr); |
| 386 | return do_memopt_delete (sd, level, space, addr); |
| 387 | } |
| 388 | |
| 389 | case OPTION_MEMORY_REGION: |
| 390 | { |
| 391 | char *chp = arg; |
| 392 | int level = 0; |
| 393 | int space = 0; |
| 394 | address_word addr = 0; |
| 395 | address_word nr_bytes = 0; |
| 396 | unsigned modulo = 0; |
| 397 | /* parse the arguments */ |
| 398 | chp = parse_addr (chp, &level, &space, &addr); |
| 399 | if (*chp != ',') |
| 400 | { |
| 401 | /* let the file autosize */ |
| 402 | if (mmap_next_fd == -1) |
| 403 | { |
| 404 | sim_io_eprintf (sd, "Missing size for memory-region\n"); |
| 405 | return SIM_RC_FAIL; |
| 406 | } |
| 407 | } |
| 408 | else |
| 409 | chp = parse_size (chp + 1, &nr_bytes, &modulo); |
| 410 | /* old style */ |
| 411 | if (*chp == ',') |
| 412 | modulo = strtoul (chp + 1, &chp, 0); |
| 413 | /* try to attach/insert it */ |
| 414 | do_memopt_add (sd, level, space, addr, nr_bytes, modulo, |
| 415 | &STATE_MEMOPT (sd), NULL); |
| 416 | return SIM_RC_OK; |
| 417 | } |
| 418 | |
| 419 | case OPTION_MEMORY_ALIAS: |
| 420 | { |
| 421 | char *chp = arg; |
| 422 | int level = 0; |
| 423 | int space = 0; |
| 424 | address_word addr = 0; |
| 425 | address_word nr_bytes = 0; |
| 426 | unsigned modulo = 0; |
| 427 | sim_memopt *entry; |
| 428 | /* parse the arguments */ |
| 429 | chp = parse_addr (chp, &level, &space, &addr); |
| 430 | if (*chp != ',') |
| 431 | { |
| 432 | sim_io_eprintf (sd, "Missing size for memory-region\n"); |
| 433 | return SIM_RC_FAIL; |
| 434 | } |
| 435 | chp = parse_size (chp + 1, &nr_bytes, &modulo); |
| 436 | /* try to attach/insert the main record */ |
| 437 | entry = do_memopt_add (sd, level, space, addr, nr_bytes, modulo, |
| 438 | &STATE_MEMOPT (sd), |
| 439 | NULL); |
| 440 | /* now attach all the aliases */ |
| 441 | while (*chp == ',') |
| 442 | { |
| 443 | int a_level = level; |
| 444 | int a_space = space; |
| 445 | address_word a_addr = addr; |
| 446 | chp = parse_addr (chp + 1, &a_level, &a_space, &a_addr); |
| 447 | do_memopt_add (sd, a_level, a_space, a_addr, nr_bytes, modulo, |
| 448 | &entry->alias, entry->buffer); |
| 449 | } |
| 450 | return SIM_RC_OK; |
| 451 | } |
| 452 | |
| 453 | case OPTION_MEMORY_SIZE: |
| 454 | { |
| 455 | int level = 0; |
| 456 | int space = 0; |
| 457 | address_word addr = 0; |
| 458 | address_word nr_bytes = 0; |
| 459 | unsigned modulo = 0; |
| 460 | /* parse the arguments */ |
| 461 | parse_size (arg, &nr_bytes, &modulo); |
| 462 | /* try to attach/insert it */ |
| 463 | do_memopt_add (sd, level, space, addr, nr_bytes, modulo, |
| 464 | &STATE_MEMOPT (sd), NULL); |
| 465 | return SIM_RC_OK; |
| 466 | } |
| 467 | |
| 468 | case OPTION_MEMORY_CLEAR: |
| 469 | { |
| 470 | fill_byte_value = (unsigned8) 0; |
| 471 | fill_byte_flag = 1; |
| 472 | return SIM_RC_OK; |
| 473 | break; |
| 474 | } |
| 475 | |
| 476 | case OPTION_MEMORY_FILL: |
| 477 | { |
| 478 | unsigned long fill_value; |
| 479 | parse_ulong_value (arg, &fill_value); |
| 480 | if (fill_value > 255) |
| 481 | { |
| 482 | sim_io_eprintf (sd, "Missing fill value between 0 and 255\n"); |
| 483 | return SIM_RC_FAIL; |
| 484 | } |
| 485 | fill_byte_value = (unsigned8) fill_value; |
| 486 | fill_byte_flag = 1; |
| 487 | return SIM_RC_OK; |
| 488 | break; |
| 489 | } |
| 490 | |
| 491 | case OPTION_MEMORY_MAPFILE: |
| 492 | { |
| 493 | if (mmap_next_fd >= 0) |
| 494 | { |
| 495 | sim_io_eprintf (sd, "Duplicate memory-mapfile option\n"); |
| 496 | return SIM_RC_FAIL; |
| 497 | } |
| 498 | |
| 499 | mmap_next_fd = open (arg, O_RDWR); |
| 500 | if (mmap_next_fd < 0) |
| 501 | { |
| 502 | sim_io_eprintf (sd, "Cannot open file `%s': %s\n", |
| 503 | arg, strerror(errno)); |
| 504 | return SIM_RC_FAIL; |
| 505 | } |
| 506 | |
| 507 | return SIM_RC_OK; |
| 508 | } |
| 509 | |
| 510 | case OPTION_MEMORY_INFO: |
| 511 | { |
| 512 | sim_memopt *entry; |
| 513 | sim_io_printf (sd, "Memory maps:\n"); |
| 514 | for (entry = STATE_MEMOPT (sd); entry != NULL; entry = entry->next) |
| 515 | { |
| 516 | sim_memopt *alias; |
| 517 | sim_io_printf (sd, " memory"); |
| 518 | if (entry->alias == NULL) |
| 519 | sim_io_printf (sd, " region "); |
| 520 | else |
| 521 | sim_io_printf (sd, " alias "); |
| 522 | if (entry->space != 0) |
| 523 | sim_io_printf (sd, "0x%lx:", (long) entry->space); |
| 524 | sim_io_printf (sd, "0x%08lx", (long) entry->addr); |
| 525 | if (entry->level != 0) |
| 526 | sim_io_printf (sd, "@0x%lx", (long) entry->level); |
| 527 | sim_io_printf (sd, ",0x%lx", |
| 528 | (long) entry->nr_bytes); |
| 529 | if (entry->modulo != 0) |
| 530 | sim_io_printf (sd, "%%0x%lx", (long) entry->modulo); |
| 531 | for (alias = entry->alias; |
| 532 | alias != NULL; |
| 533 | alias = alias->next) |
| 534 | { |
| 535 | if (alias->space != 0) |
| 536 | sim_io_printf (sd, "0x%lx:", (long) alias->space); |
| 537 | sim_io_printf (sd, ",0x%08lx", (long) alias->addr); |
| 538 | if (alias->level != 0) |
| 539 | sim_io_printf (sd, "@0x%lx", (long) alias->level); |
| 540 | } |
| 541 | sim_io_printf (sd, "\n"); |
| 542 | } |
| 543 | return SIM_RC_OK; |
| 544 | break; |
| 545 | } |
| 546 | |
| 547 | case OPTION_MAP_INFO: |
| 548 | { |
| 549 | sim_core *memory = STATE_CORE (sd); |
| 550 | unsigned nr_map; |
| 551 | |
| 552 | for (nr_map = 0; nr_map < nr_maps; ++nr_map) |
| 553 | { |
| 554 | sim_core_map *map = &memory->common.map[nr_map]; |
| 555 | sim_core_mapping *mapping = map->first; |
| 556 | |
| 557 | if (!mapping) |
| 558 | continue; |
| 559 | |
| 560 | sim_io_printf (sd, "%s maps:\n", map_to_str (nr_map)); |
| 561 | do |
| 562 | { |
| 563 | unsigned modulo; |
| 564 | |
| 565 | sim_io_printf (sd, " map "); |
| 566 | if (mapping->space != 0) |
| 567 | sim_io_printf (sd, "0x%x:", mapping->space); |
| 568 | sim_io_printf (sd, "0x%08lx", (long) mapping->base); |
| 569 | if (mapping->level != 0) |
| 570 | sim_io_printf (sd, "@0x%x", mapping->level); |
| 571 | sim_io_printf (sd, ",0x%lx", (long) mapping->nr_bytes); |
| 572 | modulo = mapping->mask + 1; |
| 573 | if (modulo != 0) |
| 574 | sim_io_printf (sd, "%%0x%x", modulo); |
| 575 | sim_io_printf (sd, "\n"); |
| 576 | |
| 577 | mapping = mapping->next; |
| 578 | } |
| 579 | while (mapping); |
| 580 | } |
| 581 | |
| 582 | return SIM_RC_OK; |
| 583 | break; |
| 584 | } |
| 585 | |
| 586 | default: |
| 587 | sim_io_eprintf (sd, "Unknown memory option %d\n", opt); |
| 588 | return SIM_RC_FAIL; |
| 589 | |
| 590 | } |
| 591 | |
| 592 | return SIM_RC_FAIL; |
| 593 | } |
| 594 | |
| 595 | |
| 596 | /* "memory" module install handler. |
| 597 | |
| 598 | This is called via sim_module_install to install the "memory" subsystem |
| 599 | into the simulator. */ |
| 600 | |
| 601 | static MODULE_INIT_FN sim_memory_init; |
| 602 | static MODULE_UNINSTALL_FN sim_memory_uninstall; |
| 603 | |
| 604 | SIM_RC |
| 605 | sim_memopt_install (SIM_DESC sd) |
| 606 | { |
| 607 | SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); |
| 608 | sim_add_option_table (sd, NULL, memory_options); |
| 609 | sim_module_add_uninstall_fn (sd, sim_memory_uninstall); |
| 610 | sim_module_add_init_fn (sd, sim_memory_init); |
| 611 | return SIM_RC_OK; |
| 612 | } |
| 613 | |
| 614 | |
| 615 | /* Uninstall the "memory" subsystem from the simulator. */ |
| 616 | |
| 617 | static void |
| 618 | sim_memory_uninstall (SIM_DESC sd) |
| 619 | { |
| 620 | sim_memopt **entry = &STATE_MEMOPT (sd); |
| 621 | sim_memopt *alias; |
| 622 | |
| 623 | while ((*entry) != NULL) |
| 624 | { |
| 625 | /* delete any buffer */ |
| 626 | if ((*entry)->buffer != NULL) |
| 627 | { |
| 628 | #ifdef HAVE_MUNMAP |
| 629 | if ((*entry)->munmap_length > 0) |
| 630 | munmap ((*entry)->buffer, (*entry)->munmap_length); |
| 631 | else |
| 632 | #endif |
| 633 | free ((*entry)->buffer); |
| 634 | } |
| 635 | |
| 636 | /* delete it and its aliases */ |
| 637 | alias = *entry; |
| 638 | |
| 639 | /* next victim */ |
| 640 | *entry = (*entry)->next; |
| 641 | |
| 642 | while (alias != NULL) |
| 643 | { |
| 644 | sim_memopt *dead = alias; |
| 645 | alias = alias->alias; |
| 646 | sim_core_detach (sd, NULL, dead->level, dead->space, dead->addr); |
| 647 | free (dead); |
| 648 | } |
| 649 | } |
| 650 | } |
| 651 | |
| 652 | |
| 653 | static SIM_RC |
| 654 | sim_memory_init (SIM_DESC sd) |
| 655 | { |
| 656 | /* Reinitialize option modifier flags, in case they were left |
| 657 | over from a previous sim startup event. */ |
| 658 | fill_byte_flag = 0; |
| 659 | mmap_next_fd = -1; |
| 660 | |
| 661 | return SIM_RC_OK; |
| 662 | } |