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