gdb/
[deliverable/binutils-gdb.git] / gdb / memattr.c
1 /* Memory attributes support, for GDB.
2
3 Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006
4 Free Software Foundation, Inc.
5
6 This file is part of GDB.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA. */
22
23 #include "defs.h"
24 #include "command.h"
25 #include "gdbcmd.h"
26 #include "memattr.h"
27 #include "target.h"
28 #include "value.h"
29 #include "language.h"
30 #include "vec.h"
31 #include "gdb_string.h"
32
33 const struct mem_attrib default_mem_attrib =
34 {
35 MEM_RW, /* mode */
36 MEM_WIDTH_UNSPECIFIED,
37 0, /* hwbreak */
38 0, /* cache */
39 0, /* verify */
40 -1 /* Flash blocksize not specified. */
41 };
42
43 VEC(mem_region_s) *mem_region_list, *target_mem_region_list;
44 static int mem_number = 0;
45
46 /* If this flag is set, the memory region list should be automatically
47 updated from the target. If it is clear, the list is user-controlled
48 and should be left alone. */
49 static int mem_use_target = 1;
50
51 /* If this flag is set, we have tried to fetch the target memory regions
52 since the last time it was invalidated. If that list is still
53 empty, then the target can't supply memory regions. */
54 static int target_mem_regions_valid;
55
56 /* Predicate function which returns true if LHS should sort before RHS
57 in a list of memory regions, useful for VEC_lower_bound. */
58
59 static int
60 mem_region_lessthan (const struct mem_region *lhs,
61 const struct mem_region *rhs)
62 {
63 return lhs->lo < rhs->lo;
64 }
65
66 /* A helper function suitable for qsort, used to sort a
67 VEC(mem_region_s) by starting address. */
68
69 int
70 mem_region_cmp (const void *untyped_lhs, const void *untyped_rhs)
71 {
72 const struct mem_region *lhs = untyped_lhs;
73 const struct mem_region *rhs = untyped_rhs;
74
75 if (lhs->lo < rhs->lo)
76 return -1;
77 else if (lhs->lo == rhs->lo)
78 return 0;
79 else
80 return 1;
81 }
82
83 /* Allocate a new memory region, with default settings. */
84
85 void
86 mem_region_init (struct mem_region *new)
87 {
88 memset (new, 0, sizeof (struct mem_region));
89 new->enabled_p = 1;
90 new->attrib = default_mem_attrib;
91 }
92
93 /* This function should be called before any command which would
94 modify the memory region list. It will handle switching from
95 a target-provided list to a local list, if necessary. */
96
97 static void
98 require_user_regions (int from_tty)
99 {
100 struct mem_region *m;
101 int ix, length;
102
103 /* If we're already using a user-provided list, nothing to do. */
104 if (!mem_use_target)
105 return;
106
107 /* Switch to a user-provided list (possibly a copy of the current
108 one). */
109 mem_use_target = 0;
110
111 /* If we don't have a target-provided region list yet, then
112 no need to warn. */
113 if (mem_region_list == NULL)
114 return;
115
116 /* Otherwise, let the user know how to get back. */
117 if (from_tty)
118 warning (_("Switching to manual control of memory regions; use "
119 "\"mem auto\" to fetch regions from the target again."));
120
121 /* And create a new list for the user to modify. */
122 length = VEC_length (mem_region_s, target_mem_region_list);
123 mem_region_list = VEC_alloc (mem_region_s, length);
124 for (ix = 0; VEC_iterate (mem_region_s, target_mem_region_list, ix, m); ix++)
125 VEC_quick_push (mem_region_s, mem_region_list, m);
126 }
127
128 /* This function should be called before any command which would
129 read the memory region list, other than those which call
130 require_user_regions. It will handle fetching the
131 target-provided list, if necessary. */
132
133 static void
134 require_target_regions (void)
135 {
136 if (mem_use_target && !target_mem_regions_valid)
137 {
138 target_mem_regions_valid = 1;
139 target_mem_region_list = target_memory_map ();
140 mem_region_list = target_mem_region_list;
141 }
142 }
143
144 static void
145 create_mem_region (CORE_ADDR lo, CORE_ADDR hi,
146 const struct mem_attrib *attrib)
147 {
148 struct mem_region new;
149 int i, ix;
150
151 /* lo == hi is a useless empty region */
152 if (lo >= hi && hi != 0)
153 {
154 printf_unfiltered (_("invalid memory region: low >= high\n"));
155 return;
156 }
157
158 mem_region_init (&new);
159 new.lo = lo;
160 new.hi = hi;
161
162 ix = VEC_lower_bound (mem_region_s, mem_region_list, &new,
163 mem_region_lessthan);
164
165 /* Check for an overlapping memory region. We only need to check
166 in the vicinity - at most one before and one after the
167 insertion point. */
168 for (i = ix - 1; i < ix + 1; i++)
169 {
170 struct mem_region *n;
171
172 if (i < 0)
173 continue;
174 if (i >= VEC_length (mem_region_s, mem_region_list))
175 continue;
176
177 n = VEC_index (mem_region_s, mem_region_list, i);
178
179 if ((lo >= n->lo && (lo < n->hi || n->hi == 0))
180 || (hi > n->lo && (hi <= n->hi || n->hi == 0))
181 || (lo <= n->lo && (hi >= n->hi || hi == 0)))
182 {
183 printf_unfiltered (_("overlapping memory region\n"));
184 return;
185 }
186 }
187
188 new.number = ++mem_number;
189 new.attrib = *attrib;
190 VEC_safe_insert (mem_region_s, mem_region_list, ix, &new);
191 }
192
193 /*
194 * Look up the memory region cooresponding to ADDR.
195 */
196 struct mem_region *
197 lookup_mem_region (CORE_ADDR addr)
198 {
199 static struct mem_region region;
200 struct mem_region *m;
201 CORE_ADDR lo;
202 CORE_ADDR hi;
203 int ix;
204
205 require_target_regions ();
206
207 /* First we initialize LO and HI so that they describe the entire
208 memory space. As we process the memory region chain, they are
209 redefined to describe the minimal region containing ADDR. LO
210 and HI are used in the case where no memory region is defined
211 that contains ADDR. If a memory region is disabled, it is
212 treated as if it does not exist. */
213
214 lo = (CORE_ADDR) 0;
215 hi = (CORE_ADDR) ~ 0;
216
217 /* If we ever want to support a huge list of memory regions, this
218 check should be replaced with a binary search (probably using
219 VEC_lower_bound). */
220 for (ix = 0; VEC_iterate (mem_region_s, mem_region_list, ix, m); ix++)
221 {
222 if (m->enabled_p == 1)
223 {
224 if (addr >= m->lo && (addr < m->hi || m->hi == 0))
225 return m;
226
227 if (addr >= m->hi && lo < m->hi)
228 lo = m->hi;
229
230 if (addr <= m->lo && hi > m->lo)
231 hi = m->lo;
232 }
233 }
234
235 /* Because no region was found, we must cons up one based on what
236 was learned above. */
237 region.lo = lo;
238 region.hi = hi;
239 region.attrib = default_mem_attrib;
240 return &region;
241 }
242
243 /* Invalidate any memory regions fetched from the target. */
244
245 void
246 invalidate_target_mem_regions (void)
247 {
248 struct mem_region *m;
249 int ix;
250
251 if (!target_mem_regions_valid)
252 return;
253
254 target_mem_regions_valid = 0;
255 VEC_free (mem_region_s, target_mem_region_list);
256 if (mem_use_target)
257 mem_region_list = NULL;
258 }
259
260 /* Clear memory region list */
261
262 static void
263 mem_clear (void)
264 {
265 VEC_free (mem_region_s, mem_region_list);
266 }
267 \f
268
269 static void
270 mem_command (char *args, int from_tty)
271 {
272 CORE_ADDR lo, hi;
273 char *tok;
274 struct mem_attrib attrib;
275
276 if (!args)
277 error_no_arg (_("No mem"));
278
279 /* For "mem auto", switch back to using a target provided list. */
280 if (strcmp (args, "auto") == 0)
281 {
282 if (mem_use_target)
283 return;
284
285 if (mem_region_list != target_mem_region_list)
286 {
287 mem_clear ();
288 mem_region_list = target_mem_region_list;
289 }
290
291 mem_use_target = 1;
292 return;
293 }
294
295 require_user_regions (from_tty);
296
297 tok = strtok (args, " \t");
298 if (!tok)
299 error (_("no lo address"));
300 lo = parse_and_eval_address (tok);
301
302 tok = strtok (NULL, " \t");
303 if (!tok)
304 error (_("no hi address"));
305 hi = parse_and_eval_address (tok);
306
307 attrib = default_mem_attrib;
308 while ((tok = strtok (NULL, " \t")) != NULL)
309 {
310 if (strcmp (tok, "rw") == 0)
311 attrib.mode = MEM_RW;
312 else if (strcmp (tok, "ro") == 0)
313 attrib.mode = MEM_RO;
314 else if (strcmp (tok, "wo") == 0)
315 attrib.mode = MEM_WO;
316
317 else if (strcmp (tok, "8") == 0)
318 attrib.width = MEM_WIDTH_8;
319 else if (strcmp (tok, "16") == 0)
320 {
321 if ((lo % 2 != 0) || (hi % 2 != 0))
322 error (_("region bounds not 16 bit aligned"));
323 attrib.width = MEM_WIDTH_16;
324 }
325 else if (strcmp (tok, "32") == 0)
326 {
327 if ((lo % 4 != 0) || (hi % 4 != 0))
328 error (_("region bounds not 32 bit aligned"));
329 attrib.width = MEM_WIDTH_32;
330 }
331 else if (strcmp (tok, "64") == 0)
332 {
333 if ((lo % 8 != 0) || (hi % 8 != 0))
334 error (_("region bounds not 64 bit aligned"));
335 attrib.width = MEM_WIDTH_64;
336 }
337
338 #if 0
339 else if (strcmp (tok, "hwbreak") == 0)
340 attrib.hwbreak = 1;
341 else if (strcmp (tok, "swbreak") == 0)
342 attrib.hwbreak = 0;
343 #endif
344
345 else if (strcmp (tok, "cache") == 0)
346 attrib.cache = 1;
347 else if (strcmp (tok, "nocache") == 0)
348 attrib.cache = 0;
349
350 #if 0
351 else if (strcmp (tok, "verify") == 0)
352 attrib.verify = 1;
353 else if (strcmp (tok, "noverify") == 0)
354 attrib.verify = 0;
355 #endif
356
357 else
358 error (_("unknown attribute: %s"), tok);
359 }
360
361 create_mem_region (lo, hi, &attrib);
362 }
363 \f
364
365 static void
366 mem_info_command (char *args, int from_tty)
367 {
368 struct mem_region *m;
369 struct mem_attrib *attrib;
370 int ix;
371
372 if (mem_use_target)
373 printf_filtered (_("Using memory regions provided by the target.\n"));
374 else
375 printf_filtered (_("Using user-defined memory regions.\n"));
376
377 require_target_regions ();
378
379 if (!mem_region_list)
380 {
381 printf_unfiltered (_("There are no memory regions defined.\n"));
382 return;
383 }
384
385 printf_filtered ("Num ");
386 printf_filtered ("Enb ");
387 printf_filtered ("Low Addr ");
388 if (TARGET_ADDR_BIT > 32)
389 printf_filtered (" ");
390 printf_filtered ("High Addr ");
391 if (TARGET_ADDR_BIT > 32)
392 printf_filtered (" ");
393 printf_filtered ("Attrs ");
394 printf_filtered ("\n");
395
396 for (ix = 0; VEC_iterate (mem_region_s, mem_region_list, ix, m); ix++)
397 {
398 char *tmp;
399 printf_filtered ("%-3d %-3c\t",
400 m->number,
401 m->enabled_p ? 'y' : 'n');
402 if (TARGET_ADDR_BIT <= 32)
403 tmp = hex_string_custom ((unsigned long) m->lo, 8);
404 else
405 tmp = hex_string_custom ((unsigned long) m->lo, 16);
406
407 printf_filtered ("%s ", tmp);
408
409 if (TARGET_ADDR_BIT <= 32)
410 {
411 if (m->hi == 0)
412 tmp = "0x100000000";
413 else
414 tmp = hex_string_custom ((unsigned long) m->hi, 8);
415 }
416 else
417 {
418 if (m->hi == 0)
419 tmp = "0x10000000000000000";
420 else
421 tmp = hex_string_custom ((unsigned long) m->hi, 16);
422 }
423
424 printf_filtered ("%s ", tmp);
425
426 /* Print a token for each attribute.
427
428 * FIXME: Should we output a comma after each token? It may
429 * make it easier for users to read, but we'd lose the ability
430 * to cut-and-paste the list of attributes when defining a new
431 * region. Perhaps that is not important.
432 *
433 * FIXME: If more attributes are added to GDB, the output may
434 * become cluttered and difficult for users to read. At that
435 * time, we may want to consider printing tokens only if they
436 * are different from the default attribute. */
437
438 attrib = &m->attrib;
439 switch (attrib->mode)
440 {
441 case MEM_RW:
442 printf_filtered ("rw ");
443 break;
444 case MEM_RO:
445 printf_filtered ("ro ");
446 break;
447 case MEM_WO:
448 printf_filtered ("wo ");
449 break;
450 case MEM_FLASH:
451 printf_filtered ("flash blocksize 0x%x ", attrib->blocksize);
452 break;
453 }
454
455 switch (attrib->width)
456 {
457 case MEM_WIDTH_8:
458 printf_filtered ("8 ");
459 break;
460 case MEM_WIDTH_16:
461 printf_filtered ("16 ");
462 break;
463 case MEM_WIDTH_32:
464 printf_filtered ("32 ");
465 break;
466 case MEM_WIDTH_64:
467 printf_filtered ("64 ");
468 break;
469 case MEM_WIDTH_UNSPECIFIED:
470 break;
471 }
472
473 #if 0
474 if (attrib->hwbreak)
475 printf_filtered ("hwbreak");
476 else
477 printf_filtered ("swbreak");
478 #endif
479
480 if (attrib->cache)
481 printf_filtered ("cache ");
482 else
483 printf_filtered ("nocache ");
484
485 #if 0
486 if (attrib->verify)
487 printf_filtered ("verify ");
488 else
489 printf_filtered ("noverify ");
490 #endif
491
492 printf_filtered ("\n");
493
494 gdb_flush (gdb_stdout);
495 }
496 }
497 \f
498
499 /* Enable the memory region number NUM. */
500
501 static void
502 mem_enable (int num)
503 {
504 struct mem_region *m;
505 int ix;
506
507 for (ix = 0; VEC_iterate (mem_region_s, mem_region_list, ix, m); ix++)
508 if (m->number == num)
509 {
510 m->enabled_p = 1;
511 return;
512 }
513 printf_unfiltered (_("No memory region number %d.\n"), num);
514 }
515
516 static void
517 mem_enable_command (char *args, int from_tty)
518 {
519 char *p = args;
520 char *p1;
521 int num;
522 struct mem_region *m;
523 int ix;
524
525 require_user_regions (from_tty);
526
527 dcache_invalidate (target_dcache);
528
529 if (p == 0)
530 {
531 for (ix = 0; VEC_iterate (mem_region_s, mem_region_list, ix, m); ix++)
532 m->enabled_p = 1;
533 }
534 else
535 while (*p)
536 {
537 p1 = p;
538 while (*p1 >= '0' && *p1 <= '9')
539 p1++;
540 if (*p1 && *p1 != ' ' && *p1 != '\t')
541 error (_("Arguments must be memory region numbers."));
542
543 num = atoi (p);
544 mem_enable (num);
545
546 p = p1;
547 while (*p == ' ' || *p == '\t')
548 p++;
549 }
550 }
551 \f
552
553 /* Disable the memory region number NUM. */
554
555 static void
556 mem_disable (int num)
557 {
558 struct mem_region *m;
559 int ix;
560
561 for (ix = 0; VEC_iterate (mem_region_s, mem_region_list, ix, m); ix++)
562 if (m->number == num)
563 {
564 m->enabled_p = 0;
565 return;
566 }
567 printf_unfiltered (_("No memory region number %d.\n"), num);
568 }
569
570 static void
571 mem_disable_command (char *args, int from_tty)
572 {
573 char *p = args;
574 char *p1;
575 int num;
576 struct mem_region *m;
577 int ix;
578
579 require_user_regions (from_tty);
580
581 dcache_invalidate (target_dcache);
582
583 if (p == 0)
584 {
585 for (ix = 0; VEC_iterate (mem_region_s, mem_region_list, ix, m); ix++)
586 m->enabled_p = 0;
587 }
588 else
589 while (*p)
590 {
591 p1 = p;
592 while (*p1 >= '0' && *p1 <= '9')
593 p1++;
594 if (*p1 && *p1 != ' ' && *p1 != '\t')
595 error (_("Arguments must be memory region numbers."));
596
597 num = atoi (p);
598 mem_disable (num);
599
600 p = p1;
601 while (*p == ' ' || *p == '\t')
602 p++;
603 }
604 }
605
606 /* Delete the memory region number NUM. */
607
608 static void
609 mem_delete (int num)
610 {
611 struct mem_region *m1, *m;
612 int ix;
613
614 if (!mem_region_list)
615 {
616 printf_unfiltered (_("No memory region number %d.\n"), num);
617 return;
618 }
619
620 for (ix = 0; VEC_iterate (mem_region_s, mem_region_list, ix, m); ix++)
621 if (m->number == num)
622 break;
623
624 if (m == NULL)
625 {
626 printf_unfiltered (_("No memory region number %d.\n"), num);
627 return;
628 }
629
630 VEC_ordered_remove (mem_region_s, mem_region_list, ix);
631 }
632
633 static void
634 mem_delete_command (char *args, int from_tty)
635 {
636 char *p = args;
637 char *p1;
638 int num;
639
640 require_user_regions (from_tty);
641
642 dcache_invalidate (target_dcache);
643
644 if (p == 0)
645 {
646 if (query ("Delete all memory regions? "))
647 mem_clear ();
648 dont_repeat ();
649 return;
650 }
651
652 while (*p)
653 {
654 p1 = p;
655 while (*p1 >= '0' && *p1 <= '9')
656 p1++;
657 if (*p1 && *p1 != ' ' && *p1 != '\t')
658 error (_("Arguments must be memory region numbers."));
659
660 num = atoi (p);
661 mem_delete (num);
662
663 p = p1;
664 while (*p == ' ' || *p == '\t')
665 p++;
666 }
667
668 dont_repeat ();
669 }
670 \f
671 extern initialize_file_ftype _initialize_mem; /* -Wmissing-prototype */
672
673 void
674 _initialize_mem (void)
675 {
676 add_com ("mem", class_vars, mem_command, _("\
677 Define attributes for memory region or reset memory region handling to\n\
678 target-based.\n\
679 Usage: mem auto\n\
680 mem <lo addr> <hi addr> [<mode> <width> <cache>], \n\
681 where <mode> may be rw (read/write), ro (read-only) or wo (write-only), \n\
682 <width> may be 8, 16, 32, or 64, and \n\
683 <cache> may be cache or nocache"));
684
685 add_cmd ("mem", class_vars, mem_enable_command, _("\
686 Enable memory region.\n\
687 Arguments are the code numbers of the memory regions to enable.\n\
688 Usage: enable mem <code number>\n\
689 Do \"info mem\" to see current list of code numbers."), &enablelist);
690
691 add_cmd ("mem", class_vars, mem_disable_command, _("\
692 Disable memory region.\n\
693 Arguments are the code numbers of the memory regions to disable.\n\
694 Usage: disable mem <code number>\n\
695 Do \"info mem\" to see current list of code numbers."), &disablelist);
696
697 add_cmd ("mem", class_vars, mem_delete_command, _("\
698 Delete memory region.\n\
699 Arguments are the code numbers of the memory regions to delete.\n\
700 Usage: delete mem <code number>\n\
701 Do \"info mem\" to see current list of code numbers."), &deletelist);
702
703 add_info ("mem", mem_info_command,
704 _("Memory region attributes"));
705 }
This page took 0.063712 seconds and 4 git commands to generate.