889d03ac8f400f8a1685f79ee03c37fbc011b536
[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. The initial values for LO
213 and HI represent the bottom and top of memory. */
214
215 lo = 0;
216 hi = 0;
217
218 /* If we ever want to support a huge list of memory regions, this
219 check should be replaced with a binary search (probably using
220 VEC_lower_bound). */
221 for (ix = 0; VEC_iterate (mem_region_s, mem_region_list, ix, m); ix++)
222 {
223 if (m->enabled_p == 1)
224 {
225 if (addr >= m->lo && (addr < m->hi || m->hi == 0))
226 return m;
227
228 /* This (correctly) won't match if m->hi == 0, representing
229 the top of the address space, because CORE_ADDR is unsigned;
230 no value of LO is less than zero. */
231 if (addr >= m->hi && lo < m->hi)
232 lo = m->hi;
233
234 /* This will never set HI to zero; if we're here and ADDR
235 is at or below M, and the region starts at zero, then ADDR
236 would have been in the region. */
237 if (addr <= m->lo && (hi == 0 || hi > m->lo))
238 hi = m->lo;
239 }
240 }
241
242 /* Because no region was found, we must cons up one based on what
243 was learned above. */
244 region.lo = lo;
245 region.hi = hi;
246 region.attrib = default_mem_attrib;
247 return &region;
248 }
249
250 /* Invalidate any memory regions fetched from the target. */
251
252 void
253 invalidate_target_mem_regions (void)
254 {
255 struct mem_region *m;
256 int ix;
257
258 if (!target_mem_regions_valid)
259 return;
260
261 target_mem_regions_valid = 0;
262 VEC_free (mem_region_s, target_mem_region_list);
263 if (mem_use_target)
264 mem_region_list = NULL;
265 }
266
267 /* Clear memory region list */
268
269 static void
270 mem_clear (void)
271 {
272 VEC_free (mem_region_s, mem_region_list);
273 }
274 \f
275
276 static void
277 mem_command (char *args, int from_tty)
278 {
279 CORE_ADDR lo, hi;
280 char *tok;
281 struct mem_attrib attrib;
282
283 if (!args)
284 error_no_arg (_("No mem"));
285
286 /* For "mem auto", switch back to using a target provided list. */
287 if (strcmp (args, "auto") == 0)
288 {
289 if (mem_use_target)
290 return;
291
292 if (mem_region_list != target_mem_region_list)
293 {
294 mem_clear ();
295 mem_region_list = target_mem_region_list;
296 }
297
298 mem_use_target = 1;
299 return;
300 }
301
302 require_user_regions (from_tty);
303
304 tok = strtok (args, " \t");
305 if (!tok)
306 error (_("no lo address"));
307 lo = parse_and_eval_address (tok);
308
309 tok = strtok (NULL, " \t");
310 if (!tok)
311 error (_("no hi address"));
312 hi = parse_and_eval_address (tok);
313
314 attrib = default_mem_attrib;
315 while ((tok = strtok (NULL, " \t")) != NULL)
316 {
317 if (strcmp (tok, "rw") == 0)
318 attrib.mode = MEM_RW;
319 else if (strcmp (tok, "ro") == 0)
320 attrib.mode = MEM_RO;
321 else if (strcmp (tok, "wo") == 0)
322 attrib.mode = MEM_WO;
323
324 else if (strcmp (tok, "8") == 0)
325 attrib.width = MEM_WIDTH_8;
326 else if (strcmp (tok, "16") == 0)
327 {
328 if ((lo % 2 != 0) || (hi % 2 != 0))
329 error (_("region bounds not 16 bit aligned"));
330 attrib.width = MEM_WIDTH_16;
331 }
332 else if (strcmp (tok, "32") == 0)
333 {
334 if ((lo % 4 != 0) || (hi % 4 != 0))
335 error (_("region bounds not 32 bit aligned"));
336 attrib.width = MEM_WIDTH_32;
337 }
338 else if (strcmp (tok, "64") == 0)
339 {
340 if ((lo % 8 != 0) || (hi % 8 != 0))
341 error (_("region bounds not 64 bit aligned"));
342 attrib.width = MEM_WIDTH_64;
343 }
344
345 #if 0
346 else if (strcmp (tok, "hwbreak") == 0)
347 attrib.hwbreak = 1;
348 else if (strcmp (tok, "swbreak") == 0)
349 attrib.hwbreak = 0;
350 #endif
351
352 else if (strcmp (tok, "cache") == 0)
353 attrib.cache = 1;
354 else if (strcmp (tok, "nocache") == 0)
355 attrib.cache = 0;
356
357 #if 0
358 else if (strcmp (tok, "verify") == 0)
359 attrib.verify = 1;
360 else if (strcmp (tok, "noverify") == 0)
361 attrib.verify = 0;
362 #endif
363
364 else
365 error (_("unknown attribute: %s"), tok);
366 }
367
368 create_mem_region (lo, hi, &attrib);
369 }
370 \f
371
372 static void
373 mem_info_command (char *args, int from_tty)
374 {
375 struct mem_region *m;
376 struct mem_attrib *attrib;
377 int ix;
378
379 if (mem_use_target)
380 printf_filtered (_("Using memory regions provided by the target.\n"));
381 else
382 printf_filtered (_("Using user-defined memory regions.\n"));
383
384 require_target_regions ();
385
386 if (!mem_region_list)
387 {
388 printf_unfiltered (_("There are no memory regions defined.\n"));
389 return;
390 }
391
392 printf_filtered ("Num ");
393 printf_filtered ("Enb ");
394 printf_filtered ("Low Addr ");
395 if (TARGET_ADDR_BIT > 32)
396 printf_filtered (" ");
397 printf_filtered ("High Addr ");
398 if (TARGET_ADDR_BIT > 32)
399 printf_filtered (" ");
400 printf_filtered ("Attrs ");
401 printf_filtered ("\n");
402
403 for (ix = 0; VEC_iterate (mem_region_s, mem_region_list, ix, m); ix++)
404 {
405 char *tmp;
406 printf_filtered ("%-3d %-3c\t",
407 m->number,
408 m->enabled_p ? 'y' : 'n');
409 if (TARGET_ADDR_BIT <= 32)
410 tmp = hex_string_custom ((unsigned long) m->lo, 8);
411 else
412 tmp = hex_string_custom ((unsigned long) m->lo, 16);
413
414 printf_filtered ("%s ", tmp);
415
416 if (TARGET_ADDR_BIT <= 32)
417 {
418 if (m->hi == 0)
419 tmp = "0x100000000";
420 else
421 tmp = hex_string_custom ((unsigned long) m->hi, 8);
422 }
423 else
424 {
425 if (m->hi == 0)
426 tmp = "0x10000000000000000";
427 else
428 tmp = hex_string_custom ((unsigned long) m->hi, 16);
429 }
430
431 printf_filtered ("%s ", tmp);
432
433 /* Print a token for each attribute.
434
435 * FIXME: Should we output a comma after each token? It may
436 * make it easier for users to read, but we'd lose the ability
437 * to cut-and-paste the list of attributes when defining a new
438 * region. Perhaps that is not important.
439 *
440 * FIXME: If more attributes are added to GDB, the output may
441 * become cluttered and difficult for users to read. At that
442 * time, we may want to consider printing tokens only if they
443 * are different from the default attribute. */
444
445 attrib = &m->attrib;
446 switch (attrib->mode)
447 {
448 case MEM_RW:
449 printf_filtered ("rw ");
450 break;
451 case MEM_RO:
452 printf_filtered ("ro ");
453 break;
454 case MEM_WO:
455 printf_filtered ("wo ");
456 break;
457 case MEM_FLASH:
458 printf_filtered ("flash blocksize 0x%x ", attrib->blocksize);
459 break;
460 }
461
462 switch (attrib->width)
463 {
464 case MEM_WIDTH_8:
465 printf_filtered ("8 ");
466 break;
467 case MEM_WIDTH_16:
468 printf_filtered ("16 ");
469 break;
470 case MEM_WIDTH_32:
471 printf_filtered ("32 ");
472 break;
473 case MEM_WIDTH_64:
474 printf_filtered ("64 ");
475 break;
476 case MEM_WIDTH_UNSPECIFIED:
477 break;
478 }
479
480 #if 0
481 if (attrib->hwbreak)
482 printf_filtered ("hwbreak");
483 else
484 printf_filtered ("swbreak");
485 #endif
486
487 if (attrib->cache)
488 printf_filtered ("cache ");
489 else
490 printf_filtered ("nocache ");
491
492 #if 0
493 if (attrib->verify)
494 printf_filtered ("verify ");
495 else
496 printf_filtered ("noverify ");
497 #endif
498
499 printf_filtered ("\n");
500
501 gdb_flush (gdb_stdout);
502 }
503 }
504 \f
505
506 /* Enable the memory region number NUM. */
507
508 static void
509 mem_enable (int num)
510 {
511 struct mem_region *m;
512 int ix;
513
514 for (ix = 0; VEC_iterate (mem_region_s, mem_region_list, ix, m); ix++)
515 if (m->number == num)
516 {
517 m->enabled_p = 1;
518 return;
519 }
520 printf_unfiltered (_("No memory region number %d.\n"), num);
521 }
522
523 static void
524 mem_enable_command (char *args, int from_tty)
525 {
526 char *p = args;
527 char *p1;
528 int num;
529 struct mem_region *m;
530 int ix;
531
532 require_user_regions (from_tty);
533
534 dcache_invalidate (target_dcache);
535
536 if (p == 0)
537 {
538 for (ix = 0; VEC_iterate (mem_region_s, mem_region_list, ix, m); ix++)
539 m->enabled_p = 1;
540 }
541 else
542 while (*p)
543 {
544 p1 = p;
545 while (*p1 >= '0' && *p1 <= '9')
546 p1++;
547 if (*p1 && *p1 != ' ' && *p1 != '\t')
548 error (_("Arguments must be memory region numbers."));
549
550 num = atoi (p);
551 mem_enable (num);
552
553 p = p1;
554 while (*p == ' ' || *p == '\t')
555 p++;
556 }
557 }
558 \f
559
560 /* Disable the memory region number NUM. */
561
562 static void
563 mem_disable (int num)
564 {
565 struct mem_region *m;
566 int ix;
567
568 for (ix = 0; VEC_iterate (mem_region_s, mem_region_list, ix, m); ix++)
569 if (m->number == num)
570 {
571 m->enabled_p = 0;
572 return;
573 }
574 printf_unfiltered (_("No memory region number %d.\n"), num);
575 }
576
577 static void
578 mem_disable_command (char *args, int from_tty)
579 {
580 char *p = args;
581 char *p1;
582 int num;
583 struct mem_region *m;
584 int ix;
585
586 require_user_regions (from_tty);
587
588 dcache_invalidate (target_dcache);
589
590 if (p == 0)
591 {
592 for (ix = 0; VEC_iterate (mem_region_s, mem_region_list, ix, m); ix++)
593 m->enabled_p = 0;
594 }
595 else
596 while (*p)
597 {
598 p1 = p;
599 while (*p1 >= '0' && *p1 <= '9')
600 p1++;
601 if (*p1 && *p1 != ' ' && *p1 != '\t')
602 error (_("Arguments must be memory region numbers."));
603
604 num = atoi (p);
605 mem_disable (num);
606
607 p = p1;
608 while (*p == ' ' || *p == '\t')
609 p++;
610 }
611 }
612
613 /* Delete the memory region number NUM. */
614
615 static void
616 mem_delete (int num)
617 {
618 struct mem_region *m1, *m;
619 int ix;
620
621 if (!mem_region_list)
622 {
623 printf_unfiltered (_("No memory region number %d.\n"), num);
624 return;
625 }
626
627 for (ix = 0; VEC_iterate (mem_region_s, mem_region_list, ix, m); ix++)
628 if (m->number == num)
629 break;
630
631 if (m == NULL)
632 {
633 printf_unfiltered (_("No memory region number %d.\n"), num);
634 return;
635 }
636
637 VEC_ordered_remove (mem_region_s, mem_region_list, ix);
638 }
639
640 static void
641 mem_delete_command (char *args, int from_tty)
642 {
643 char *p = args;
644 char *p1;
645 int num;
646
647 require_user_regions (from_tty);
648
649 dcache_invalidate (target_dcache);
650
651 if (p == 0)
652 {
653 if (query ("Delete all memory regions? "))
654 mem_clear ();
655 dont_repeat ();
656 return;
657 }
658
659 while (*p)
660 {
661 p1 = p;
662 while (*p1 >= '0' && *p1 <= '9')
663 p1++;
664 if (*p1 && *p1 != ' ' && *p1 != '\t')
665 error (_("Arguments must be memory region numbers."));
666
667 num = atoi (p);
668 mem_delete (num);
669
670 p = p1;
671 while (*p == ' ' || *p == '\t')
672 p++;
673 }
674
675 dont_repeat ();
676 }
677 \f
678 extern initialize_file_ftype _initialize_mem; /* -Wmissing-prototype */
679
680 void
681 _initialize_mem (void)
682 {
683 add_com ("mem", class_vars, mem_command, _("\
684 Define attributes for memory region or reset memory region handling to\n\
685 target-based.\n\
686 Usage: mem auto\n\
687 mem <lo addr> <hi addr> [<mode> <width> <cache>], \n\
688 where <mode> may be rw (read/write), ro (read-only) or wo (write-only), \n\
689 <width> may be 8, 16, 32, or 64, and \n\
690 <cache> may be cache or nocache"));
691
692 add_cmd ("mem", class_vars, mem_enable_command, _("\
693 Enable memory region.\n\
694 Arguments are the code numbers of the memory regions to enable.\n\
695 Usage: enable mem <code number>\n\
696 Do \"info mem\" to see current list of code numbers."), &enablelist);
697
698 add_cmd ("mem", class_vars, mem_disable_command, _("\
699 Disable memory region.\n\
700 Arguments are the code numbers of the memory regions to disable.\n\
701 Usage: disable mem <code number>\n\
702 Do \"info mem\" to see current list of code numbers."), &disablelist);
703
704 add_cmd ("mem", class_vars, mem_delete_command, _("\
705 Delete memory region.\n\
706 Arguments are the code numbers of the memory regions to delete.\n\
707 Usage: delete mem <code number>\n\
708 Do \"info mem\" to see current list of code numbers."), &deletelist);
709
710 add_info ("mem", mem_info_command,
711 _("Memory region attributes"));
712 }
This page took 0.054661 seconds and 4 git commands to generate.