This commit was generated by cvs2svn to track changes on a CVS vendor
[platform/upstream/binutils.git] / gdb / memattr.c
1 /* Memory attributes support, for GDB.
2
3    Copyright (C) 2001, 2002 Free Software Foundation, Inc.
4
5    This file is part of GDB.
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 of the License, or
10    (at your option) 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
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin Street, Fifth Floor,
20    Boston, MA 02110-1301, USA.  */
21
22 #include "defs.h"
23 #include "command.h"
24 #include "gdbcmd.h"
25 #include "memattr.h"
26 #include "target.h"
27 #include "value.h"
28 #include "language.h"
29 #include "gdb_string.h"
30
31 const struct mem_attrib default_mem_attrib =
32 {
33   MEM_RW,                       /* mode */
34   MEM_WIDTH_UNSPECIFIED,
35   0,                            /* hwbreak */
36   0,                            /* cache */
37   0                             /* verify */
38 };
39
40 static struct mem_region *mem_region_chain = NULL;
41 static int mem_number = 0;
42
43 static struct mem_region *
44 create_mem_region (CORE_ADDR lo, CORE_ADDR hi,
45                    const struct mem_attrib *attrib)
46 {
47   struct mem_region *n, *new;
48
49   /* lo == hi is a useless empty region */
50   if (lo >= hi && hi != 0)
51     {
52       printf_unfiltered (_("invalid memory region: low >= high\n"));
53       return NULL;
54     }
55
56   n = mem_region_chain;
57   while (n)
58     {
59       /* overlapping node */
60       if ((lo >= n->lo && (lo < n->hi || n->hi == 0)) 
61           || (hi > n->lo && (hi <= n->hi || n->hi == 0))
62           || (lo <= n->lo && (hi >= n->hi || hi == 0)))
63         {
64           printf_unfiltered (_("overlapping memory region\n"));
65           return NULL;
66         }
67       n = n->next;
68     }
69
70   new = xmalloc (sizeof (struct mem_region));
71   new->lo = lo;
72   new->hi = hi;
73   new->number = ++mem_number;
74   new->enabled_p = 1;
75   new->attrib = *attrib;
76
77   /* link in new node */
78   new->next = mem_region_chain;
79   mem_region_chain = new;
80
81   return new;
82 }
83
84 static void
85 delete_mem_region (struct mem_region *m)
86 {
87   xfree (m);
88 }
89
90 /*
91  * Look up the memory region cooresponding to ADDR.
92  */
93 struct mem_region *
94 lookup_mem_region (CORE_ADDR addr)
95 {
96   static struct mem_region region;
97   struct mem_region *m;
98   CORE_ADDR lo;
99   CORE_ADDR hi;
100
101   /* First we initialize LO and HI so that they describe the entire
102      memory space.  As we process the memory region chain, they are
103      redefined to describe the minimal region containing ADDR.  LO
104      and HI are used in the case where no memory region is defined
105      that contains ADDR.  If a memory region is disabled, it is
106      treated as if it does not exist.  */
107
108   lo = (CORE_ADDR) 0;
109   hi = (CORE_ADDR) ~ 0;
110
111   for (m = mem_region_chain; m; m = m->next)
112     {
113       if (m->enabled_p == 1)
114         {
115           if (addr >= m->lo && (addr < m->hi || m->hi == 0))
116             return m;
117
118           if (addr >= m->hi && lo < m->hi)
119             lo = m->hi;
120
121           if (addr <= m->lo && hi > m->lo)
122             hi = m->lo;
123         }
124     }
125
126   /* Because no region was found, we must cons up one based on what
127      was learned above.  */
128   region.lo = lo;
129   region.hi = hi;
130   region.attrib = default_mem_attrib;
131   return &region;
132 }
133 \f
134
135 static void
136 mem_command (char *args, int from_tty)
137 {
138   CORE_ADDR lo, hi;
139   char *tok;
140   struct mem_attrib attrib;
141
142   if (!args)
143     error_no_arg (_("No mem"));
144
145   tok = strtok (args, " \t");
146   if (!tok)
147     error (_("no lo address"));
148   lo = parse_and_eval_address (tok);
149
150   tok = strtok (NULL, " \t");
151   if (!tok)
152     error (_("no hi address"));
153   hi = parse_and_eval_address (tok);
154
155   attrib = default_mem_attrib;
156   while ((tok = strtok (NULL, " \t")) != NULL)
157     {
158       if (strcmp (tok, "rw") == 0)
159         attrib.mode = MEM_RW;
160       else if (strcmp (tok, "ro") == 0)
161         attrib.mode = MEM_RO;
162       else if (strcmp (tok, "wo") == 0)
163         attrib.mode = MEM_WO;
164
165       else if (strcmp (tok, "8") == 0)
166         attrib.width = MEM_WIDTH_8;
167       else if (strcmp (tok, "16") == 0)
168         {
169           if ((lo % 2 != 0) || (hi % 2 != 0))
170             error (_("region bounds not 16 bit aligned"));
171           attrib.width = MEM_WIDTH_16;
172         }
173       else if (strcmp (tok, "32") == 0)
174         {
175           if ((lo % 4 != 0) || (hi % 4 != 0))
176             error (_("region bounds not 32 bit aligned"));
177           attrib.width = MEM_WIDTH_32;
178         }
179       else if (strcmp (tok, "64") == 0)
180         {
181           if ((lo % 8 != 0) || (hi % 8 != 0))
182             error (_("region bounds not 64 bit aligned"));
183           attrib.width = MEM_WIDTH_64;
184         }
185
186 #if 0
187       else if (strcmp (tok, "hwbreak") == 0)
188         attrib.hwbreak = 1;
189       else if (strcmp (tok, "swbreak") == 0)
190         attrib.hwbreak = 0;
191 #endif
192
193       else if (strcmp (tok, "cache") == 0)
194         attrib.cache = 1;
195       else if (strcmp (tok, "nocache") == 0)
196         attrib.cache = 0;
197
198 #if 0
199       else if (strcmp (tok, "verify") == 0)
200         attrib.verify = 1;
201       else if (strcmp (tok, "noverify") == 0)
202         attrib.verify = 0;
203 #endif
204
205       else
206         error (_("unknown attribute: %s"), tok);
207     }
208
209   create_mem_region (lo, hi, &attrib);
210 }
211 \f
212
213 static void
214 mem_info_command (char *args, int from_tty)
215 {
216   struct mem_region *m;
217   struct mem_attrib *attrib;
218
219   if (!mem_region_chain)
220     {
221       printf_unfiltered (_("There are no memory regions defined.\n"));
222       return;
223     }
224
225   printf_filtered ("Num ");
226   printf_filtered ("Enb ");
227   printf_filtered ("Low Addr   ");
228   if (TARGET_ADDR_BIT > 32)
229     printf_filtered ("        ");
230   printf_filtered ("High Addr  ");
231   if (TARGET_ADDR_BIT > 32)
232     printf_filtered ("        ");
233   printf_filtered ("Attrs ");
234   printf_filtered ("\n");
235
236   for (m = mem_region_chain; m; m = m->next)
237     {
238       char *tmp;
239       printf_filtered ("%-3d %-3c\t",
240                        m->number,
241                        m->enabled_p ? 'y' : 'n');
242       if (TARGET_ADDR_BIT <= 32)
243         tmp = hex_string_custom ((unsigned long) m->lo, 8);
244       else
245         tmp = hex_string_custom ((unsigned long) m->lo, 16);
246       
247       printf_filtered ("%s ", tmp);
248
249       if (TARGET_ADDR_BIT <= 32)
250         {
251         if (m->hi == 0)
252           tmp = "0x100000000";
253         else
254           tmp = hex_string_custom ((unsigned long) m->hi, 8);
255         }
256       else
257         {
258         if (m->hi == 0)
259           tmp = "0x10000000000000000";
260         else
261           tmp = hex_string_custom ((unsigned long) m->hi, 16);
262         }
263
264       printf_filtered ("%s ", tmp);
265
266       /* Print a token for each attribute.
267
268        * FIXME: Should we output a comma after each token?  It may
269        * make it easier for users to read, but we'd lose the ability
270        * to cut-and-paste the list of attributes when defining a new
271        * region.  Perhaps that is not important.
272        *
273        * FIXME: If more attributes are added to GDB, the output may
274        * become cluttered and difficult for users to read.  At that
275        * time, we may want to consider printing tokens only if they
276        * are different from the default attribute.  */
277
278       attrib = &m->attrib;
279       switch (attrib->mode)
280         {
281         case MEM_RW:
282           printf_filtered ("rw ");
283           break;
284         case MEM_RO:
285           printf_filtered ("ro ");
286           break;
287         case MEM_WO:
288           printf_filtered ("wo ");
289           break;
290         }
291
292       switch (attrib->width)
293         {
294         case MEM_WIDTH_8:
295           printf_filtered ("8 ");
296           break;
297         case MEM_WIDTH_16:
298           printf_filtered ("16 ");
299           break;
300         case MEM_WIDTH_32:
301           printf_filtered ("32 ");
302           break;
303         case MEM_WIDTH_64:
304           printf_filtered ("64 ");
305           break;
306         case MEM_WIDTH_UNSPECIFIED:
307           break;
308         }
309
310 #if 0
311       if (attrib->hwbreak)
312         printf_filtered ("hwbreak");
313       else
314         printf_filtered ("swbreak");
315 #endif
316
317       if (attrib->cache)
318         printf_filtered ("cache ");
319       else
320         printf_filtered ("nocache ");
321
322 #if 0
323       if (attrib->verify)
324         printf_filtered ("verify ");
325       else
326         printf_filtered ("noverify ");
327 #endif
328
329       printf_filtered ("\n");
330
331       gdb_flush (gdb_stdout);
332     }
333 }
334 \f
335
336 /* Enable the memory region number NUM. */
337
338 static void
339 mem_enable (int num)
340 {
341   struct mem_region *m;
342
343   for (m = mem_region_chain; m; m = m->next)
344     if (m->number == num)
345       {
346         m->enabled_p = 1;
347         return;
348       }
349   printf_unfiltered (_("No memory region number %d.\n"), num);
350 }
351
352 static void
353 mem_enable_command (char *args, int from_tty)
354 {
355   char *p = args;
356   char *p1;
357   int num;
358   struct mem_region *m;
359
360   dcache_invalidate (target_dcache);
361
362   if (p == 0)
363     {
364       for (m = mem_region_chain; m; m = m->next)
365         m->enabled_p = 1;
366     }
367   else
368     while (*p)
369       {
370         p1 = p;
371         while (*p1 >= '0' && *p1 <= '9')
372           p1++;
373         if (*p1 && *p1 != ' ' && *p1 != '\t')
374           error (_("Arguments must be memory region numbers."));
375
376         num = atoi (p);
377         mem_enable (num);
378
379         p = p1;
380         while (*p == ' ' || *p == '\t')
381           p++;
382       }
383 }
384 \f
385
386 /* Disable the memory region number NUM. */
387
388 static void
389 mem_disable (int num)
390 {
391   struct mem_region *m;
392
393   for (m = mem_region_chain; m; m = m->next)
394     if (m->number == num)
395       {
396         m->enabled_p = 0;
397         return;
398       }
399   printf_unfiltered (_("No memory region number %d.\n"), num);
400 }
401
402 static void
403 mem_disable_command (char *args, int from_tty)
404 {
405   char *p = args;
406   char *p1;
407   int num;
408   struct mem_region *m;
409
410   dcache_invalidate (target_dcache);
411
412   if (p == 0)
413     {
414       for (m = mem_region_chain; m; m = m->next)
415         m->enabled_p = 0;
416     }
417   else
418     while (*p)
419       {
420         p1 = p;
421         while (*p1 >= '0' && *p1 <= '9')
422           p1++;
423         if (*p1 && *p1 != ' ' && *p1 != '\t')
424           error (_("Arguments must be memory region numbers."));
425
426         num = atoi (p);
427         mem_disable (num);
428
429         p = p1;
430         while (*p == ' ' || *p == '\t')
431           p++;
432       }
433 }
434
435 /* Clear memory region list */
436
437 static void
438 mem_clear (void)
439 {
440   struct mem_region *m;
441
442   while ((m = mem_region_chain) != 0)
443     {
444       mem_region_chain = m->next;
445       delete_mem_region (m);
446     }
447 }
448
449 /* Delete the memory region number NUM. */
450
451 static void
452 mem_delete (int num)
453 {
454   struct mem_region *m1, *m;
455
456   if (!mem_region_chain)
457     {
458       printf_unfiltered (_("No memory region number %d.\n"), num);
459       return;
460     }
461
462   if (mem_region_chain->number == num)
463     {
464       m1 = mem_region_chain;
465       mem_region_chain = m1->next;
466       delete_mem_region (m1);
467     }
468   else
469     for (m = mem_region_chain; m->next; m = m->next)
470       {
471         if (m->next->number == num)
472           {
473             m1 = m->next;
474             m->next = m1->next;
475             delete_mem_region (m1);
476             break;
477           }
478       }
479 }
480
481 static void
482 mem_delete_command (char *args, int from_tty)
483 {
484   char *p = args;
485   char *p1;
486   int num;
487
488   dcache_invalidate (target_dcache);
489
490   if (p == 0)
491     {
492       if (query ("Delete all memory regions? "))
493         mem_clear ();
494       dont_repeat ();
495       return;
496     }
497
498   while (*p)
499     {
500       p1 = p;
501       while (*p1 >= '0' && *p1 <= '9')
502         p1++;
503       if (*p1 && *p1 != ' ' && *p1 != '\t')
504         error (_("Arguments must be memory region numbers."));
505
506       num = atoi (p);
507       mem_delete (num);
508
509       p = p1;
510       while (*p == ' ' || *p == '\t')
511         p++;
512     }
513
514   dont_repeat ();
515 }
516 \f
517 extern initialize_file_ftype _initialize_mem; /* -Wmissing-prototype */
518
519 void
520 _initialize_mem (void)
521 {
522   add_com ("mem", class_vars, mem_command, _("\
523 Define attributes for memory region.\n\
524 Usage: mem <lo addr> <hi addr> [<mode> <width> <cache>], \n\
525 where <mode>  may be rw (read/write), ro (read-only) or wo (write-only), \n\
526       <width> may be 8, 16, 32, or 64, and \n\
527       <cache> may be cache or nocache"));
528
529   add_cmd ("mem", class_vars, mem_enable_command, _("\
530 Enable memory region.\n\
531 Arguments are the code numbers of the memory regions to enable.\n\
532 Usage: enable mem <code number>\n\
533 Do \"info mem\" to see current list of code numbers."), &enablelist);
534
535   add_cmd ("mem", class_vars, mem_disable_command, _("\
536 Disable memory region.\n\
537 Arguments are the code numbers of the memory regions to disable.\n\
538 Usage: disable mem <code number>\n\
539 Do \"info mem\" to see current list of code numbers."), &disablelist);
540
541   add_cmd ("mem", class_vars, mem_delete_command, _("\
542 Delete memory region.\n\
543 Arguments are the code numbers of the memory regions to delete.\n\
544 Usage: delete mem <code number>\n\
545 Do \"info mem\" to see current list of code numbers."), &deletelist);
546
547   add_info ("mem", mem_info_command,
548             _("Memory region attributes"));
549 }