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