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