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 31const 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 40static struct mem_region *mem_region_chain = NULL; 41static int mem_number = 0; 42 43static struct mem_region * 44create_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 84static void 85delete_mem_region (struct mem_region *m) 86{ 87 xfree (m); 88} 89 90/* 91 * Look up the memory region cooresponding to ADDR. 92 */ 93struct mem_region * 94lookup_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 ®ion; 132} 133 134 135static void 136mem_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 213static void 214mem_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 = local_hex_string_custom ((unsigned long) m->lo, "08l"); 244 else 245 tmp = local_hex_string_custom ((unsigned long) m->lo, "016l"); 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 = local_hex_string_custom ((unsigned long) m->hi, "08l"); 255 } 256 else 257 { 258 if (m->hi == 0) 259 tmp = "0x10000000000000000"; 260 else 261 tmp = local_hex_string_custom ((unsigned long) m->hi, "016l"); 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 338static void 339mem_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 352static void 353mem_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 388static void 389mem_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 402static void 403mem_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 437static void 438mem_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 451static void 452mem_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 481static void 482mem_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 517extern initialize_file_ftype _initialize_mem; /* -Wmissing-prototype */ 518 519void 520_initialize_mem (void) 521{ 522 add_com ("mem", class_vars, mem_command, 523 "Define attributes for memory region.\n\ 524Usage: mem <lo addr> <hi addr> [<mode> <width> <cache>], \n\ 525where <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\ 531Arguments are the code numbers of the memory regions to enable.\n\ 532Usage: enable mem <code number>\n\ 533Do \"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\ 537Arguments are the code numbers of the memory regions to disable.\n\ 538Usage: disable mem <code number>\n\ 539Do \"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\ 543Arguments are the code numbers of the memory regions to delete.\n\ 544Usage: delete mem <code number>\n\ 545Do \"info mem\" to see current list of code numbers.", &deletelist); 546 547 add_info ("mem", mem_info_command, 548 "Memory region attributes"); 549} 550