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