2002-06-24 Don Howard <dhoward@redhat.com>
[external/binutils.git] / gdb / memattr.c
1 /* Memory attributes support, for GDB.
2
3    Copyright 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., 59 Temple Place - Suite 330,
20    Boston, MA 02111-1307, 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       CORE_ADDR hi;
239       char *tmp;
240       printf_filtered ("%-3d %-3c\t",
241                        m->number,
242                        m->enabled_p ? 'y' : 'n');
243       if (TARGET_ADDR_BIT <= 32)
244         tmp = local_hex_string_custom ((unsigned long) m->lo, "08l");
245       else
246         tmp = local_hex_string_custom ((unsigned long) m->lo, "016l");
247       
248       printf_filtered ("%s ", tmp);
249       hi = (m->hi == 0 ? ~0 : m->hi);
250
251       if (TARGET_ADDR_BIT <= 32)
252         tmp = local_hex_string_custom ((unsigned long) hi, "08l");
253       else
254         tmp = local_hex_string_custom ((unsigned long) hi, "016l");
255       
256       printf_filtered ("%s ", tmp);
257
258       /* Print a token for each attribute.
259
260        * FIXME: Should we output a comma after each token?  It may
261        * make it easier for users to read, but we'd lose the ability
262        * to cut-and-paste the list of attributes when defining a new
263        * region.  Perhaps that is not important.
264        *
265        * FIXME: If more attributes are added to GDB, the output may
266        * become cluttered and difficult for users to read.  At that
267        * time, we may want to consider printing tokens only if they
268        * are different from the default attribute.  */
269
270       attrib = &m->attrib;
271       switch (attrib->mode)
272         {
273         case MEM_RW:
274           printf_filtered ("rw ");
275           break;
276         case MEM_RO:
277           printf_filtered ("ro ");
278           break;
279         case MEM_WO:
280           printf_filtered ("wo ");
281           break;
282         }
283
284       switch (attrib->width)
285         {
286         case MEM_WIDTH_8:
287           printf_filtered ("8 ");
288           break;
289         case MEM_WIDTH_16:
290           printf_filtered ("16 ");
291           break;
292         case MEM_WIDTH_32:
293           printf_filtered ("32 ");
294           break;
295         case MEM_WIDTH_64:
296           printf_filtered ("64 ");
297           break;
298         case MEM_WIDTH_UNSPECIFIED:
299           break;
300         }
301
302 #if 0
303       if (attrib->hwbreak)
304         printf_filtered ("hwbreak");
305       else
306         printf_filtered ("swbreak");
307 #endif
308
309       if (attrib->cache)
310         printf_filtered ("cache ");
311       else
312         printf_filtered ("nocache ");
313
314 #if 0
315       if (attrib->verify)
316         printf_filtered ("verify ");
317       else
318         printf_filtered ("noverify ");
319 #endif
320
321       printf_filtered ("\n");
322
323       gdb_flush (gdb_stdout);
324     }
325 }
326 \f
327
328 /* Enable the memory region number NUM. */
329
330 static void
331 mem_enable (int num)
332 {
333   struct mem_region *m;
334
335   for (m = mem_region_chain; m; m = m->next)
336     if (m->number == num)
337       {
338         m->enabled_p = 1;
339         return;
340       }
341   printf_unfiltered ("No memory region number %d.\n", num);
342 }
343
344 static void
345 mem_enable_command (char *args, int from_tty)
346 {
347   char *p = args;
348   char *p1;
349   int num;
350   struct mem_region *m;
351
352   dcache_invalidate (target_dcache);
353
354   if (p == 0)
355     {
356       for (m = mem_region_chain; m; m = m->next)
357         m->enabled_p = 1;
358     }
359   else
360     while (*p)
361       {
362         p1 = p;
363         while (*p1 >= '0' && *p1 <= '9')
364           p1++;
365         if (*p1 && *p1 != ' ' && *p1 != '\t')
366           error ("Arguments must be memory region numbers.");
367
368         num = atoi (p);
369         mem_enable (num);
370
371         p = p1;
372         while (*p == ' ' || *p == '\t')
373           p++;
374       }
375 }
376 \f
377
378 /* Disable the memory region number NUM. */
379
380 static void
381 mem_disable (int num)
382 {
383   struct mem_region *m;
384
385   for (m = mem_region_chain; m; m = m->next)
386     if (m->number == num)
387       {
388         m->enabled_p = 0;
389         return;
390       }
391   printf_unfiltered ("No memory region number %d.\n", num);
392 }
393
394 static void
395 mem_disable_command (char *args, int from_tty)
396 {
397   char *p = args;
398   char *p1;
399   int num;
400   struct mem_region *m;
401
402   dcache_invalidate (target_dcache);
403
404   if (p == 0)
405     {
406       for (m = mem_region_chain; m; m = m->next)
407         m->enabled_p = 0;
408     }
409   else
410     while (*p)
411       {
412         p1 = p;
413         while (*p1 >= '0' && *p1 <= '9')
414           p1++;
415         if (*p1 && *p1 != ' ' && *p1 != '\t')
416           error ("Arguments must be memory region numbers.");
417
418         num = atoi (p);
419         mem_disable (num);
420
421         p = p1;
422         while (*p == ' ' || *p == '\t')
423           p++;
424       }
425 }
426
427 /* Clear memory region list */
428
429 static void
430 mem_clear (void)
431 {
432   struct mem_region *m;
433
434   while ((m = mem_region_chain) != 0)
435     {
436       mem_region_chain = m->next;
437       delete_mem_region (m);
438     }
439 }
440
441 /* Delete the memory region number NUM. */
442
443 static void
444 mem_delete (int num)
445 {
446   struct mem_region *m1, *m;
447
448   if (!mem_region_chain)
449     {
450       printf_unfiltered ("No memory region number %d.\n", num);
451       return;
452     }
453
454   if (mem_region_chain->number == num)
455     {
456       m1 = mem_region_chain;
457       mem_region_chain = m1->next;
458       delete_mem_region (m1);
459     }
460   else
461     for (m = mem_region_chain; m->next; m = m->next)
462       {
463         if (m->next->number == num)
464           {
465             m1 = m->next;
466             m->next = m1->next;
467             delete_mem_region (m1);
468             break;
469           }
470       }
471 }
472
473 static void
474 mem_delete_command (char *args, int from_tty)
475 {
476   char *p = args;
477   char *p1;
478   int num;
479
480   dcache_invalidate (target_dcache);
481
482   if (p == 0)
483     {
484       if (query ("Delete all memory regions? "))
485         mem_clear ();
486       dont_repeat ();
487       return;
488     }
489
490   while (*p)
491     {
492       p1 = p;
493       while (*p1 >= '0' && *p1 <= '9')
494         p1++;
495       if (*p1 && *p1 != ' ' && *p1 != '\t')
496         error ("Arguments must be memory region numbers.");
497
498       num = atoi (p);
499       mem_delete (num);
500
501       p = p1;
502       while (*p == ' ' || *p == '\t')
503         p++;
504     }
505
506   dont_repeat ();
507 }
508 \f
509 void
510 _initialize_mem ()
511 {
512   add_com ("mem", class_vars, mem_command,
513            "Define attributes for memory region.\n\
514 Usage: mem <lo addr> <hi addr> [<mode> <width> <cache>], \n\
515 where <mode>  may be rw (read/write), ro (read-only) or wo (write-only), \n\
516       <width> may be 8, 16, 32, or 64, and \n\
517       <cache> may be cache or nocache");
518
519   add_cmd ("mem", class_vars, mem_enable_command,
520            "Enable memory region.\n\
521 Arguments are the code numbers of the memory regions to enable.\n\
522 Usage: enable mem <code number>\n\
523 Do \"info mem\" to see current list of code numbers.", &enablelist);
524
525   add_cmd ("mem", class_vars, mem_disable_command,
526            "Disable memory region.\n\
527 Arguments are the code numbers of the memory regions to disable.\n\
528 Usage: disable mem <code number>\n\
529 Do \"info mem\" to see current list of code numbers.", &disablelist);
530
531   add_cmd ("mem", class_vars, mem_delete_command,
532            "Delete memory region.\n\
533 Arguments are the code numbers of the memory regions to delete.\n\
534 Usage: delete mem <code number>\n\
535 Do \"info mem\" to see current list of code numbers.", &deletelist);
536
537   add_info ("mem", mem_info_command,
538             "Memory region attributes");
539 }