]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/memattr.c
* language.c (local_hex_string_custom): Simplify. Do not depend
[thirdparty/binutils-gdb.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 }