* mmap support for common simulators
[external/binutils.git] / sim / common / sim-memopt.c
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 "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
50 /* Memory fill byte. */
51 static unsigned8 fill_byte_value;
52 static int fill_byte_flag = 0;
53
54 /* Memory mapping; see OPTION_MEMORY_MAPFILE. */
55 static int mmap_next_fd = -1;
56
57 /* Memory command line options. */
58
59 enum {
60   OPTION_MEMORY_DELETE = OPTION_START,
61   OPTION_MEMORY_REGION,
62   OPTION_MEMORY_SIZE,
63   OPTION_MEMORY_INFO,
64   OPTION_MEMORY_ALIAS,
65   OPTION_MEMORY_CLEAR,
66   OPTION_MEMORY_FILL,
67   OPTION_MEMORY_MAPFILE
68 };
69
70 static DECLARE_OPTION_HANDLER (memory_option_handler);
71
72 static const OPTION memory_options[] =
73 {
74   { {"memory-delete", required_argument, NULL, OPTION_MEMORY_DELETE },
75       '\0', "ADDRESS|all", "Delete memory at ADDRESS (all addresses)",
76       memory_option_handler },
77   { {"delete-memory", required_argument, NULL, OPTION_MEMORY_DELETE },
78       '\0', "ADDRESS", NULL,
79       memory_option_handler },
80
81   { {"memory-region", required_argument, NULL, OPTION_MEMORY_REGION },
82       '\0', "ADDRESS,SIZE[,MODULO]", "Add a memory region",
83       memory_option_handler },
84
85   { {"memory-alias", required_argument, NULL, OPTION_MEMORY_ALIAS },
86       '\0', "ADDRESS,SIZE{,ADDRESS}", "Add memory shadow",
87       memory_option_handler },
88
89   { {"memory-size", required_argument, NULL, OPTION_MEMORY_SIZE },
90       '\0', "SIZE", "Add memory at address zero",
91       memory_option_handler },
92
93   { {"memory-fill", required_argument, NULL, OPTION_MEMORY_FILL },
94       '\0', "VALUE", "Fill subsequently added memory regions",
95       memory_option_handler },
96
97   { {"memory-clear", no_argument, NULL, OPTION_MEMORY_CLEAR },
98       '\0', NULL, "Clear subsequently added memory regions",
99       memory_option_handler },
100
101 #if defined(HAVE_MMAP) && defined(HAVE_MUNMAP)
102   { {"memory-mapfile", required_argument, NULL, OPTION_MEMORY_MAPFILE },
103       '\0', "FILE", "Memory-map next memory region from file",
104       memory_option_handler },
105 #endif
106
107   { {"memory-info", no_argument, NULL, OPTION_MEMORY_INFO },
108       '\0', NULL, "List configurable memory regions",
109       memory_option_handler },
110   { {"info-memory", no_argument, NULL, OPTION_MEMORY_INFO },
111       '\0', NULL, NULL,
112       memory_option_handler },
113
114   { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL }
115 };
116
117
118 static sim_memopt *
119 do_memopt_add (SIM_DESC sd,
120                int level,
121                int space,
122                address_word addr,
123                address_word nr_bytes,
124                unsigned modulo,
125                sim_memopt **entry,
126                void *buffer)
127 {
128   void *fill_buffer;
129   unsigned fill_length;
130   void *free_buffer;
131   unsigned long free_length;
132
133   if (buffer != NULL)
134     {
135       /* Buffer already given.  sim_memory_uninstall will free it. */
136       sim_core_attach (sd, NULL,
137                        level, access_read_write_exec, space,
138                        addr, nr_bytes, modulo, NULL, buffer);
139
140       free_buffer = buffer;
141       free_length = 0;
142       fill_buffer = buffer;
143       fill_length = (modulo == 0) ? nr_bytes : modulo;
144     }
145   else
146     {
147       /* Allocate new well-aligned buffer, just as sim_core_attach(). */
148       void *aligned_buffer;
149       int padding = (addr % sizeof (unsigned64));
150       unsigned long bytes = (modulo == 0 ? nr_bytes : modulo) + padding;
151
152       free_buffer = NULL;
153       free_length = bytes;
154
155 #ifdef HAVE_MMAP
156       /* Memory map or malloc(). */
157       if (mmap_next_fd >= 0)
158         {
159           /* Check that given file is big enough. */
160           struct stat s;
161           int rc;
162
163           /* Some kernels will SIGBUS the application if mmap'd file
164              is not large enough.  */ 
165           rc = fstat (mmap_next_fd, &s);
166           if (rc < 0 || s.st_size < bytes)
167             {
168               sim_io_error (sd,
169                             "Error, cannot confirm that mmap file is large enough "
170                             "(>= %d bytes)\n", bytes);
171             }
172
173           free_buffer = mmap (0, bytes, PROT_READ|PROT_WRITE, MAP_SHARED, mmap_next_fd, 0);
174           if (free_buffer == 0 || free_buffer == (char*)-1) /* MAP_FAILED */
175             {
176               sim_io_error (sd, "Error, cannot mmap file (%s).\n",
177                             strerror(errno));
178             }
179         }
180 #endif 
181
182       /* Need heap allocation? */ 
183       if (free_buffer == NULL)
184         {
185           /* If filling with non-zero value, do not use clearing allocator. */
186           if (fill_byte_flag && fill_byte_value != 0)
187             free_buffer = xmalloc (bytes); /* don't clear */
188           else
189             free_buffer = zalloc (bytes); /* clear */
190         }
191
192       aligned_buffer = (char*) free_buffer + padding;
193
194       sim_core_attach (sd, NULL,
195                        level, access_read_write_exec, space,
196                        addr, nr_bytes, modulo, NULL, aligned_buffer);
197
198       fill_buffer = aligned_buffer;
199       fill_length = (modulo == 0) ? nr_bytes : modulo;
200
201       /* If we just used a clearing allocator, and are about to fill with
202          zero, truncate the redundant fill operation. */
203
204       if (fill_byte_flag && fill_byte_value == 0)
205          fill_length = 1; /* avoid boundary length=0 case */
206     }
207
208   if (fill_byte_flag)
209     {
210       ASSERT (fill_buffer != 0);
211       memset ((char*) fill_buffer, fill_byte_value, fill_length);
212     }
213
214   while ((*entry) != NULL)
215     entry = &(*entry)->next;
216   (*entry) = ZALLOC (sim_memopt);
217   (*entry)->level = level;
218   (*entry)->space = space;
219   (*entry)->addr = addr;
220   (*entry)->nr_bytes = nr_bytes;
221   (*entry)->modulo = modulo;
222   (*entry)->buffer = free_buffer;
223
224   /* Record memory unmapping info.  */
225   if (mmap_next_fd >= 0)
226     {
227       (*entry)->munmap_length = free_length;
228       close (mmap_next_fd);
229       mmap_next_fd = -1;
230     }
231   else
232     (*entry)->munmap_length = 0;
233
234   return (*entry);
235 }
236
237 static SIM_RC
238 do_memopt_delete (SIM_DESC sd,
239                   int level,
240                   int space,
241                   address_word addr)
242 {
243   sim_memopt **entry = &STATE_MEMOPT (sd);
244   sim_memopt *alias;
245   while ((*entry) != NULL
246          && ((*entry)->level != level
247               || (*entry)->space != space
248               || (*entry)->addr != addr))
249     entry = &(*entry)->next;
250   if ((*entry) == NULL)
251     {
252       sim_io_eprintf (sd, "Memory at 0x%lx not found, not deleted\n",
253                       (long) addr);
254       return SIM_RC_FAIL;
255     }
256   /* delete any buffer */
257   if ((*entry)->buffer != NULL)
258     {
259 #ifdef HAVE_MUNMAP
260       if ((*entry)->munmap_length > 0)
261         munmap ((*entry)->buffer, (*entry)->munmap_length);
262       else
263 #endif
264         zfree ((*entry)->buffer);
265     }
266
267   /* delete it and its aliases */
268   alias = *entry;
269   *entry = (*entry)->next;
270   while (alias != NULL)
271     {
272       sim_memopt *dead = alias;
273       alias = alias->alias;
274       sim_core_detach (sd, NULL, dead->level, dead->space, dead->addr);
275       zfree (dead);
276     }
277   return SIM_RC_OK;
278 }
279
280
281 static char *
282 parse_size (char *chp,
283             address_word *nr_bytes,
284             unsigned *modulo)
285 {
286   /* <nr_bytes> [ "%" <modulo> ] */
287   *nr_bytes = strtoul (chp, &chp, 0);
288   if (*chp == '%')
289     {
290       *modulo = strtoul (chp + 1, &chp, 0);
291     }
292   return chp;
293 }
294
295 static char *
296 parse_ulong_value (char *chp,
297                      unsigned long *value)
298 {
299   *value = strtoul (chp, &chp, 0);
300   return chp;
301 }
302
303 static char *
304 parse_addr (char *chp,
305             int *level,
306             int *space,
307             address_word *addr)
308 {
309   /* [ <space> ": " ] <addr> [ "@" <level> ] */
310   *addr = (unsigned long) strtoul (chp, &chp, 0);
311   if (*chp == ':')
312     {
313       *space = *addr;
314       *addr = (unsigned long) strtoul (chp + 1, &chp, 0);
315     }
316   if (*chp == '@')
317     {
318       *level = strtoul (chp + 1, &chp, 0);
319     }
320   return chp;
321 }
322
323
324 static SIM_RC
325 memory_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt,
326                        char *arg, int is_command)
327 {
328   switch (opt)
329     {
330
331     case OPTION_MEMORY_DELETE:
332       if (strcasecmp (arg, "all") == 0)
333         {
334           while (STATE_MEMOPT (sd) != NULL)
335             do_memopt_delete (sd,
336                               STATE_MEMOPT (sd)->level,
337                               STATE_MEMOPT (sd)->space,
338                               STATE_MEMOPT (sd)->addr);
339           return SIM_RC_OK;
340         }
341       else
342         {
343           int level = 0;
344           int space = 0;
345           address_word addr = 0;
346           parse_addr (arg, &level, &space, &addr);
347           return do_memopt_delete (sd, level, space, addr);
348         }
349     
350     case OPTION_MEMORY_REGION:
351       {
352         char *chp = arg;
353         int level = 0;
354         int space = 0;
355         address_word addr = 0;
356         address_word nr_bytes = 0;
357         unsigned modulo = 0;
358         /* parse the arguments */
359         chp = parse_addr (chp, &level, &space, &addr);
360         if (*chp != ',')
361           {
362             sim_io_eprintf (sd, "Missing size for memory-region\n");
363             return SIM_RC_FAIL;
364           }
365         chp = parse_size (chp + 1, &nr_bytes, &modulo);
366         /* old style */
367         if (*chp == ',')
368           modulo = strtoul (chp + 1, &chp, 0);
369         /* try to attach/insert it */
370         do_memopt_add (sd, level, space, addr, nr_bytes, modulo,
371                        &STATE_MEMOPT (sd), NULL);
372         return SIM_RC_OK;
373       }
374
375     case OPTION_MEMORY_ALIAS:
376       {
377         char *chp = arg;
378         int level = 0;
379         int space = 0;
380         address_word addr = 0;
381         address_word nr_bytes = 0;
382         unsigned modulo = 0;
383         sim_memopt *entry;
384         /* parse the arguments */
385         chp = parse_addr (chp, &level, &space, &addr);
386         if (*chp != ',')
387           {
388             sim_io_eprintf (sd, "Missing size for memory-region\n");
389             return SIM_RC_FAIL;
390           }
391         chp = parse_size (chp + 1, &nr_bytes, &modulo);
392         /* try to attach/insert the main record */
393         entry = do_memopt_add (sd, level, space, addr, nr_bytes, modulo,
394                                &STATE_MEMOPT (sd),
395                                NULL);
396         /* now attach all the aliases */
397         while (*chp == ',')
398           {
399             int a_level = level;
400             int a_space = space;
401             address_word a_addr = addr;
402             chp = parse_addr (chp + 1, &a_level, &a_space, &a_addr);
403             do_memopt_add (sd, a_level, a_space, a_addr, nr_bytes, modulo,
404                            &entry->alias, entry->buffer);
405           }
406         return SIM_RC_OK;
407       }
408
409     case OPTION_MEMORY_SIZE:
410       {
411         int level = 0;
412         int space = 0;
413         address_word addr = 0;
414         address_word nr_bytes = 0;
415         unsigned modulo = 0;
416         /* parse the arguments */
417         parse_size (arg, &nr_bytes, &modulo);
418         /* try to attach/insert it */
419         do_memopt_add (sd, level, space, addr, nr_bytes, modulo,
420                        &STATE_MEMOPT (sd), NULL);
421         return SIM_RC_OK;
422       }
423
424     case OPTION_MEMORY_CLEAR:
425       {
426         fill_byte_value = (unsigned8) 0;
427         fill_byte_flag = 1;
428         return SIM_RC_OK;
429         break;
430       }
431
432     case OPTION_MEMORY_FILL:
433       {
434         unsigned long fill_value;
435         parse_ulong_value (arg, &fill_value);
436         if (fill_value > 255)
437           {
438             sim_io_eprintf (sd, "Missing fill value between 0 and 255\n");
439             return SIM_RC_FAIL;
440           }
441         fill_byte_value = (unsigned8) fill_value;
442         fill_byte_flag = 1;
443         return SIM_RC_OK;
444         break;
445       }
446
447     case OPTION_MEMORY_MAPFILE:
448       {
449         if (mmap_next_fd >= 0)
450           {
451             sim_io_eprintf (sd, "Duplicate memory-mapfile option\n");
452             return SIM_RC_FAIL;
453           }
454
455         mmap_next_fd = open (arg, O_RDWR);
456         if (mmap_next_fd < 0)
457           {
458             sim_io_eprintf (sd, "Cannot open file `%s': %s\n",
459                             arg, strerror(errno));
460             return SIM_RC_FAIL;
461           }
462
463         return SIM_RC_OK;
464       }
465
466     case OPTION_MEMORY_INFO:
467       {
468         sim_memopt *entry;
469         sim_io_printf (sd, "Memory maps:\n");
470         for (entry = STATE_MEMOPT (sd); entry != NULL; entry = entry->next)
471           {
472             sim_memopt *alias;
473             sim_io_printf (sd, " memory");
474             if (entry->alias == NULL)
475               sim_io_printf (sd, " region ");
476             else
477               sim_io_printf (sd, " alias ");
478             if (entry->space != 0)
479               sim_io_printf (sd, "0x%lx:", (long) entry->space);
480             sim_io_printf (sd, "0x%08lx", (long) entry->addr);
481             if (entry->level != 0)
482               sim_io_printf (sd, "@0x%lx", (long) entry->level);
483             sim_io_printf (sd, ",0x%lx",
484                            (long) entry->nr_bytes);
485             if (entry->modulo != 0)
486               sim_io_printf (sd, "%%0x%lx", (long) entry->modulo);
487             for (alias = entry->alias;
488                  alias != NULL;
489                  alias = alias->next)
490               {
491                 if (alias->space != 0)
492                   sim_io_printf (sd, "0x%lx:", (long) alias->space);
493                 sim_io_printf (sd, ",0x%08lx", (long) alias->addr);
494                 if (alias->level != 0)
495                   sim_io_printf (sd, "@0x%lx", (long) alias->level);
496               }
497             sim_io_printf (sd, "\n");
498           }
499         return SIM_RC_OK;
500         break;
501       }
502
503     default:
504       sim_io_eprintf (sd, "Unknown memory option %d\n", opt);
505       return SIM_RC_FAIL;
506
507     }
508
509   return SIM_RC_FAIL;
510 }
511
512
513 /* "memory" module install handler.
514
515    This is called via sim_module_install to install the "memory" subsystem
516    into the simulator.  */
517
518 static MODULE_INIT_FN sim_memory_init;
519 static MODULE_UNINSTALL_FN sim_memory_uninstall;
520
521 SIM_RC
522 sim_memopt_install (SIM_DESC sd)
523 {
524   SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
525   sim_add_option_table (sd, NULL, memory_options);
526   sim_module_add_uninstall_fn (sd, sim_memory_uninstall);
527   sim_module_add_init_fn (sd, sim_memory_init);
528   return SIM_RC_OK;
529 }
530
531
532 /* Uninstall the "memory" subsystem from the simulator.  */
533
534 static void
535 sim_memory_uninstall (SIM_DESC sd)
536 {
537   sim_memopt **entry = &STATE_MEMOPT (sd);
538   sim_memopt *alias;
539
540   while ((*entry) != NULL)
541     {
542       /* delete any buffer */
543       if ((*entry)->buffer != NULL)
544         {
545 #ifdef HAVE_MUNMAP
546           if ((*entry)->munmap_length > 0)
547             munmap ((*entry)->buffer, (*entry)->munmap_length);
548           else
549 #endif
550             zfree ((*entry)->buffer);
551         }
552
553       /* delete it and its aliases */
554       alias = *entry;
555
556       /* next victim */
557       *entry = (*entry)->next;
558
559       while (alias != NULL)
560         {
561           sim_memopt *dead = alias;
562           alias = alias->alias;
563           sim_core_detach (sd, NULL, dead->level, dead->space, dead->addr);
564           zfree (dead);
565         }
566     }
567 }
568
569
570 static SIM_RC
571 sim_memory_init (SIM_DESC sd)
572 {
573   /* Reinitialize option modifier flags, in case they were left
574      over from a previous sim startup event.  */
575   fill_byte_flag = 0;
576   mmap_next_fd = -1;
577
578   return SIM_RC_OK;
579 }