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