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