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