| OLD | NEW |
| 1 /* Caching code for GDB, the GNU debugger. | 1 /* Caching code for GDB, the GNU debugger. |
| 2 | 2 |
| 3 Copyright (C) 1992-1993, 1995-1996, 1998-2001, 2003, 2007-2012 Free | 3 Copyright (C) 1992-2013 Free Software Foundation, Inc. |
| 4 Software Foundation, Inc. | |
| 5 | 4 |
| 6 This file is part of GDB. | 5 This file is part of GDB. |
| 7 | 6 |
| 8 This program is free software; you can redistribute it and/or modify | 7 This program is free software; you can redistribute it and/or modify |
| 9 it under the terms of the GNU General Public License as published by | 8 it under the terms of the GNU General Public License as published by |
| 10 the Free Software Foundation; either version 3 of the License, or | 9 the Free Software Foundation; either version 3 of the License, or |
| 11 (at your option) any later version. | 10 (at your option) any later version. |
| 12 | 11 |
| 13 This program is distributed in the hope that it will be useful, | 12 This program is distributed in the hope that it will be useful, |
| 14 but WITHOUT ANY WARRANTY; without even the implied warranty of | 13 but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 16 GNU General Public License for more details. | 15 GNU General Public License for more details. |
| 17 | 16 |
| 18 You should have received a copy of the GNU General Public License | 17 You should have received a copy of the GNU General Public License |
| 19 along with this program. If not, see <http://www.gnu.org/licenses/>. */ | 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
| 20 | 19 |
| 21 #include "defs.h" | 20 #include "defs.h" |
| 22 #include "dcache.h" | 21 #include "dcache.h" |
| 23 #include "gdbcmd.h" | 22 #include "gdbcmd.h" |
| 24 #include "gdb_string.h" | 23 #include <string.h> |
| 25 #include "gdbcore.h" | 24 #include "gdbcore.h" |
| 26 #include "target.h" | 25 #include "target-dcache.h" |
| 27 #include "inferior.h" | 26 #include "inferior.h" |
| 28 #include "splay-tree.h" | 27 #include "splay-tree.h" |
| 29 | 28 |
| 30 /* Commands with a prefix of `{set,show} dcache'. */ | 29 /* Commands with a prefix of `{set,show} dcache'. */ |
| 31 static struct cmd_list_element *dcache_set_list = NULL; | 30 static struct cmd_list_element *dcache_set_list = NULL; |
| 32 static struct cmd_list_element *dcache_show_list = NULL; | 31 static struct cmd_list_element *dcache_show_list = NULL; |
| 33 | 32 |
| 34 /* The data cache could lead to incorrect results because it doesn't | 33 /* The data cache could lead to incorrect results because it doesn't |
| 35 know about volatile variables, thus making it impossible to debug | 34 know about volatile variables, thus making it impossible to debug |
| 36 functions which use memory mapped I/O devices. Set the nocache | 35 functions which use memory mapped I/O devices. Set the nocache |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 133 | 132 |
| 134 static int dcache_enabled_p = 0; /* OBSOLETE */ | 133 static int dcache_enabled_p = 0; /* OBSOLETE */ |
| 135 | 134 |
| 136 static void | 135 static void |
| 137 show_dcache_enabled_p (struct ui_file *file, int from_tty, | 136 show_dcache_enabled_p (struct ui_file *file, int from_tty, |
| 138 struct cmd_list_element *c, const char *value) | 137 struct cmd_list_element *c, const char *value) |
| 139 { | 138 { |
| 140 fprintf_filtered (file, _("Deprecated remotecache flag is %s.\n"), value); | 139 fprintf_filtered (file, _("Deprecated remotecache flag is %s.\n"), value); |
| 141 } | 140 } |
| 142 | 141 |
| 143 static DCACHE *last_cache; /* Used by info dcache. */ | |
| 144 | |
| 145 /* Add BLOCK to circular block list BLIST, behind the block at *BLIST. | 142 /* Add BLOCK to circular block list BLIST, behind the block at *BLIST. |
| 146 *BLIST is not updated (unless it was previously NULL of course). | 143 *BLIST is not updated (unless it was previously NULL of course). |
| 147 This is for the least-recently-allocated list's sake: | 144 This is for the least-recently-allocated list's sake: |
| 148 BLIST points to the oldest block. | 145 BLIST points to the oldest block. |
| 149 ??? This makes for poor cache usage of the free list, | 146 ??? This makes for poor cache usage of the free list, |
| 150 but is it measurable? */ | 147 but is it measurable? */ |
| 151 | 148 |
| 152 static void | 149 static void |
| 153 append_block (struct dcache_block **blist, struct dcache_block *block) | 150 append_block (struct dcache_block **blist, struct dcache_block *block) |
| 154 { | 151 { |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 219 free_block (struct dcache_block *block, void *param) | 216 free_block (struct dcache_block *block, void *param) |
| 220 { | 217 { |
| 221 xfree (block); | 218 xfree (block); |
| 222 } | 219 } |
| 223 | 220 |
| 224 /* Free a data cache. */ | 221 /* Free a data cache. */ |
| 225 | 222 |
| 226 void | 223 void |
| 227 dcache_free (DCACHE *dcache) | 224 dcache_free (DCACHE *dcache) |
| 228 { | 225 { |
| 229 if (last_cache == dcache) | |
| 230 last_cache = NULL; | |
| 231 | |
| 232 splay_tree_delete (dcache->tree); | 226 splay_tree_delete (dcache->tree); |
| 233 for_each_block (&dcache->oldest, free_block, NULL); | 227 for_each_block (&dcache->oldest, free_block, NULL); |
| 234 for_each_block (&dcache->freelist, free_block, NULL); | 228 for_each_block (&dcache->freelist, free_block, NULL); |
| 235 xfree (dcache); | 229 xfree (dcache); |
| 236 } | 230 } |
| 237 | 231 |
| 238 | 232 |
| 239 /* BLOCK_FUNC function for dcache_invalidate. | 233 /* BLOCK_FUNC function for dcache_invalidate. |
| 240 This doesn't remove the block from the oldest list on purpose. | 234 This doesn't remove the block from the oldest list on purpose. |
| 241 dcache_invalidate will do it later. */ | 235 dcache_invalidate will do it later. */ |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 335 | 329 |
| 336 /* Skip non-readable regions. The cache attribute can be ignored, | 330 /* Skip non-readable regions. The cache attribute can be ignored, |
| 337 since we may be loading this for a stack access. */ | 331 since we may be loading this for a stack access. */ |
| 338 if (region->attrib.mode == MEM_WO) | 332 if (region->attrib.mode == MEM_WO) |
| 339 { | 333 { |
| 340 memaddr += reg_len; | 334 memaddr += reg_len; |
| 341 myaddr += reg_len; | 335 myaddr += reg_len; |
| 342 len -= reg_len; | 336 len -= reg_len; |
| 343 continue; | 337 continue; |
| 344 } | 338 } |
| 345 | 339 |
| 346 res = target_read (¤t_target, TARGET_OBJECT_RAW_MEMORY, | 340 res = target_read_raw_memory (memaddr, myaddr, reg_len); |
| 347 » » » NULL, myaddr, memaddr, reg_len); | 341 if (res != 0) |
| 348 if (res < reg_len) | |
| 349 return 0; | 342 return 0; |
| 350 | 343 |
| 351 memaddr += res; | 344 memaddr += reg_len; |
| 352 myaddr += res; | 345 myaddr += reg_len; |
| 353 len -= res; | 346 len -= reg_len; |
| 354 } | 347 } |
| 355 | 348 |
| 356 return 1; | 349 return 1; |
| 357 } | 350 } |
| 358 | 351 |
| 359 /* Get a free cache block, put or keep it on the valid list, | 352 /* Get a free cache block, put or keep it on the valid list, |
| 360 and return its address. */ | 353 and return its address. */ |
| 361 | 354 |
| 362 static struct dcache_block * | 355 static struct dcache_block * |
| 363 dcache_alloc (DCACHE *dcache, CORE_ADDR addr) | 356 dcache_alloc (DCACHE *dcache, CORE_ADDR addr) |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 462 | 455 |
| 463 dcache->tree = splay_tree_new (dcache_splay_tree_compare, | 456 dcache->tree = splay_tree_new (dcache_splay_tree_compare, |
| 464 NULL, | 457 NULL, |
| 465 NULL); | 458 NULL); |
| 466 | 459 |
| 467 dcache->oldest = NULL; | 460 dcache->oldest = NULL; |
| 468 dcache->freelist = NULL; | 461 dcache->freelist = NULL; |
| 469 dcache->size = 0; | 462 dcache->size = 0; |
| 470 dcache->line_size = dcache_line_size; | 463 dcache->line_size = dcache_line_size; |
| 471 dcache->ptid = null_ptid; | 464 dcache->ptid = null_ptid; |
| 472 last_cache = dcache; | |
| 473 | 465 |
| 474 return dcache; | 466 return dcache; |
| 475 } | 467 } |
| 476 | 468 |
| 477 | 469 |
| 478 /* Read or write LEN bytes from inferior memory at MEMADDR, transferring | 470 /* Read or write LEN bytes from inferior memory at MEMADDR, transferring |
| 479 to or from debugger address MYADDR. Write to inferior if SHOULD_WRITE is | 471 to or from debugger address MYADDR. Write to inferior if SHOULD_WRITE is |
| 480 nonzero. | 472 nonzero. |
| 481 | 473 |
| 482 Return the number of bytes actually transfered, or -1 if the | 474 Return the number of bytes actually transfered, or -1 if the |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 551 | 543 |
| 552 void | 544 void |
| 553 dcache_update (DCACHE *dcache, CORE_ADDR memaddr, gdb_byte *myaddr, int len) | 545 dcache_update (DCACHE *dcache, CORE_ADDR memaddr, gdb_byte *myaddr, int len) |
| 554 { | 546 { |
| 555 int i; | 547 int i; |
| 556 | 548 |
| 557 for (i = 0; i < len; i++) | 549 for (i = 0; i < len; i++) |
| 558 dcache_poke_byte (dcache, memaddr + i, myaddr + i); | 550 dcache_poke_byte (dcache, memaddr + i, myaddr + i); |
| 559 } | 551 } |
| 560 | 552 |
| 553 /* Print DCACHE line INDEX. */ |
| 554 |
| 561 static void | 555 static void |
| 562 dcache_print_line (int index) | 556 dcache_print_line (DCACHE *dcache, int index) |
| 563 { | 557 { |
| 564 splay_tree_node n; | 558 splay_tree_node n; |
| 565 struct dcache_block *db; | 559 struct dcache_block *db; |
| 566 int i, j; | 560 int i, j; |
| 567 | 561 |
| 568 if (!last_cache) | 562 if (dcache == NULL) |
| 569 { | 563 { |
| 570 printf_filtered (_("No data cache available.\n")); | 564 printf_filtered (_("No data cache available.\n")); |
| 571 return; | 565 return; |
| 572 } | 566 } |
| 573 | 567 |
| 574 n = splay_tree_min (last_cache->tree); | 568 n = splay_tree_min (dcache->tree); |
| 575 | 569 |
| 576 for (i = index; i > 0; --i) | 570 for (i = index; i > 0; --i) |
| 577 { | 571 { |
| 578 if (!n) | 572 if (!n) |
| 579 break; | 573 break; |
| 580 n = splay_tree_successor (last_cache->tree, n->key); | 574 n = splay_tree_successor (dcache->tree, n->key); |
| 581 } | 575 } |
| 582 | 576 |
| 583 if (!n) | 577 if (!n) |
| 584 { | 578 { |
| 585 printf_filtered (_("No such cache line exists.\n")); | 579 printf_filtered (_("No such cache line exists.\n")); |
| 586 return; | 580 return; |
| 587 } | 581 } |
| 588 | 582 |
| 589 db = (struct dcache_block *) n->value; | 583 db = (struct dcache_block *) n->value; |
| 590 | 584 |
| 591 printf_filtered (_("Line %d: address %s [%d hits]\n"), | 585 printf_filtered (_("Line %d: address %s [%d hits]\n"), |
| 592 » » index, paddress (target_gdbarch, db->addr), db->refs); | 586 » » index, paddress (target_gdbarch (), db->addr), db->refs); |
| 593 | 587 |
| 594 for (j = 0; j < last_cache->line_size; j++) | 588 for (j = 0; j < dcache->line_size; j++) |
| 595 { | 589 { |
| 596 printf_filtered ("%02x ", db->data[j]); | 590 printf_filtered ("%02x ", db->data[j]); |
| 597 | 591 |
| 598 /* Print a newline every 16 bytes (48 characters). */ | 592 /* Print a newline every 16 bytes (48 characters). */ |
| 599 if ((j % 16 == 15) && (j != last_cache->line_size - 1)) | 593 if ((j % 16 == 15) && (j != dcache->line_size - 1)) |
| 600 printf_filtered ("\n"); | 594 printf_filtered ("\n"); |
| 601 } | 595 } |
| 602 printf_filtered ("\n"); | 596 printf_filtered ("\n"); |
| 603 } | 597 } |
| 604 | 598 |
| 599 /* Parse EXP and show the info about DCACHE. */ |
| 600 |
| 605 static void | 601 static void |
| 606 dcache_info (char *exp, int tty) | 602 dcache_info_1 (DCACHE *dcache, char *exp) |
| 607 { | 603 { |
| 608 splay_tree_node n; | 604 splay_tree_node n; |
| 609 int i, refcount; | 605 int i, refcount; |
| 610 | 606 |
| 611 if (exp) | 607 if (exp) |
| 612 { | 608 { |
| 613 char *linestart; | 609 char *linestart; |
| 614 | 610 |
| 615 i = strtol (exp, &linestart, 10); | 611 i = strtol (exp, &linestart, 10); |
| 616 if (linestart == exp || i < 0) | 612 if (linestart == exp || i < 0) |
| 617 { | 613 { |
| 618 printf_filtered (_("Usage: info dcache [linenumber]\n")); | 614 printf_filtered (_("Usage: info dcache [linenumber]\n")); |
| 619 return; | 615 return; |
| 620 } | 616 } |
| 621 | 617 |
| 622 dcache_print_line (i); | 618 dcache_print_line (dcache, i); |
| 623 return; | 619 return; |
| 624 } | 620 } |
| 625 | 621 |
| 626 printf_filtered (_("Dcache %u lines of %u bytes each.\n"), | 622 printf_filtered (_("Dcache %u lines of %u bytes each.\n"), |
| 627 dcache_size, | 623 dcache_size, |
| 628 » » last_cache ? (unsigned) last_cache->line_size | 624 » » dcache ? (unsigned) dcache->line_size |
| 629 : dcache_line_size); | 625 : dcache_line_size); |
| 630 | 626 |
| 631 if (!last_cache || ptid_equal (last_cache->ptid, null_ptid)) | 627 if (dcache == NULL || ptid_equal (dcache->ptid, null_ptid)) |
| 632 { | 628 { |
| 633 printf_filtered (_("No data cache available.\n")); | 629 printf_filtered (_("No data cache available.\n")); |
| 634 return; | 630 return; |
| 635 } | 631 } |
| 636 | 632 |
| 637 printf_filtered (_("Contains data for %s\n"), | 633 printf_filtered (_("Contains data for %s\n"), |
| 638 » » target_pid_to_str (last_cache->ptid)); | 634 » » target_pid_to_str (dcache->ptid)); |
| 639 | 635 |
| 640 refcount = 0; | 636 refcount = 0; |
| 641 | 637 |
| 642 n = splay_tree_min (last_cache->tree); | 638 n = splay_tree_min (dcache->tree); |
| 643 i = 0; | 639 i = 0; |
| 644 | 640 |
| 645 while (n) | 641 while (n) |
| 646 { | 642 { |
| 647 struct dcache_block *db = (struct dcache_block *) n->value; | 643 struct dcache_block *db = (struct dcache_block *) n->value; |
| 648 | 644 |
| 649 printf_filtered (_("Line %d: address %s [%d hits]\n"), | 645 printf_filtered (_("Line %d: address %s [%d hits]\n"), |
| 650 » » i, paddress (target_gdbarch, db->addr), db->refs); | 646 » » i, paddress (target_gdbarch (), db->addr), db->refs); |
| 651 i++; | 647 i++; |
| 652 refcount += db->refs; | 648 refcount += db->refs; |
| 653 | 649 |
| 654 n = splay_tree_successor (last_cache->tree, n->key); | 650 n = splay_tree_successor (dcache->tree, n->key); |
| 655 } | 651 } |
| 656 | 652 |
| 657 printf_filtered (_("Cache state: %d active lines, %d hits\n"), i, refcount); | 653 printf_filtered (_("Cache state: %d active lines, %d hits\n"), i, refcount); |
| 658 } | 654 } |
| 659 | 655 |
| 660 static void | 656 static void |
| 657 dcache_info (char *exp, int tty) |
| 658 { |
| 659 dcache_info_1 (target_dcache_get (), exp); |
| 660 } |
| 661 |
| 662 static void |
| 661 set_dcache_size (char *args, int from_tty, | 663 set_dcache_size (char *args, int from_tty, |
| 662 struct cmd_list_element *c) | 664 struct cmd_list_element *c) |
| 663 { | 665 { |
| 664 if (dcache_size == 0) | 666 if (dcache_size == 0) |
| 665 { | 667 { |
| 666 dcache_size = DCACHE_DEFAULT_SIZE; | 668 dcache_size = DCACHE_DEFAULT_SIZE; |
| 667 error (_("Dcache size must be greater than 0.")); | 669 error (_("Dcache size must be greater than 0.")); |
| 668 } | 670 } |
| 669 if (last_cache) | 671 target_dcache_invalidate (); |
| 670 dcache_invalidate (last_cache); | |
| 671 } | 672 } |
| 672 | 673 |
| 673 static void | 674 static void |
| 674 set_dcache_line_size (char *args, int from_tty, | 675 set_dcache_line_size (char *args, int from_tty, |
| 675 struct cmd_list_element *c) | 676 struct cmd_list_element *c) |
| 676 { | 677 { |
| 677 if (dcache_line_size < 2 | 678 if (dcache_line_size < 2 |
| 678 || (dcache_line_size & (dcache_line_size - 1)) != 0) | 679 || (dcache_line_size & (dcache_line_size - 1)) != 0) |
| 679 { | 680 { |
| 680 unsigned d = dcache_line_size; | 681 unsigned d = dcache_line_size; |
| 681 dcache_line_size = DCACHE_DEFAULT_LINE_SIZE; | 682 dcache_line_size = DCACHE_DEFAULT_LINE_SIZE; |
| 682 error (_("Invalid dcache line size: %u (must be power of 2)."), d); | 683 error (_("Invalid dcache line size: %u (must be power of 2)."), d); |
| 683 } | 684 } |
| 684 if (last_cache) | 685 target_dcache_invalidate (); |
| 685 dcache_invalidate (last_cache); | |
| 686 } | 686 } |
| 687 | 687 |
| 688 static void | 688 static void |
| 689 set_dcache_command (char *arg, int from_tty) | 689 set_dcache_command (char *arg, int from_tty) |
| 690 { | 690 { |
| 691 printf_unfiltered ( | 691 printf_unfiltered ( |
| 692 "\"set dcache\" must be followed by the name of a subcommand.\n"); | 692 "\"set dcache\" must be followed by the name of a subcommand.\n"); |
| 693 help_list (dcache_set_list, "set dcache ", -1, gdb_stdout); | 693 help_list (dcache_set_list, "set dcache ", -1, gdb_stdout); |
| 694 } | 694 } |
| 695 | 695 |
| (...skipping 25 matching lines...) Expand all Loading... |
| 721 summary of each line in the cache. Use \"info dcache <lineno> to dump\"\n\ | 721 summary of each line in the cache. Use \"info dcache <lineno> to dump\"\n\ |
| 722 the contents of a given line.")); | 722 the contents of a given line.")); |
| 723 | 723 |
| 724 add_prefix_cmd ("dcache", class_obscure, set_dcache_command, _("\ | 724 add_prefix_cmd ("dcache", class_obscure, set_dcache_command, _("\ |
| 725 Use this command to set number of lines in dcache and line-size."), | 725 Use this command to set number of lines in dcache and line-size."), |
| 726 &dcache_set_list, "set dcache ", /*allow_unknown*/0, &setlist)
; | 726 &dcache_set_list, "set dcache ", /*allow_unknown*/0, &setlist)
; |
| 727 add_prefix_cmd ("dcache", class_obscure, show_dcache_command, _("\ | 727 add_prefix_cmd ("dcache", class_obscure, show_dcache_command, _("\ |
| 728 Show dcachesettings."), | 728 Show dcachesettings."), |
| 729 &dcache_show_list, "show dcache ", /*allow_unknown*/0, &showli
st); | 729 &dcache_show_list, "show dcache ", /*allow_unknown*/0, &showli
st); |
| 730 | 730 |
| 731 add_setshow_uinteger_cmd ("line-size", class_obscure, | 731 add_setshow_zuinteger_cmd ("line-size", class_obscure, |
| 732 » » » &dcache_line_size, _("\ | 732 » » » &dcache_line_size, _("\ |
| 733 Set dcache line size in bytes (must be power of 2)."), _("\ | 733 Set dcache line size in bytes (must be power of 2)."), _("\ |
| 734 Show dcache line size."), | 734 Show dcache line size."), |
| 735 » » » NULL, | 735 » » » NULL, |
| 736 » » » set_dcache_line_size, | 736 » » » set_dcache_line_size, |
| 737 » » » NULL, | 737 » » » NULL, |
| 738 » » » &dcache_set_list, &dcache_show_list); | 738 » » » &dcache_set_list, &dcache_show_list); |
| 739 add_setshow_uinteger_cmd ("size", class_obscure, | 739 add_setshow_zuinteger_cmd ("size", class_obscure, |
| 740 » » » &dcache_size, _("\ | 740 » » » &dcache_size, _("\ |
| 741 Set number of dcache lines."), _("\ | 741 Set number of dcache lines."), _("\ |
| 742 Show number of dcache lines."), | 742 Show number of dcache lines."), |
| 743 » » » NULL, | 743 » » » NULL, |
| 744 » » » set_dcache_size, | 744 » » » set_dcache_size, |
| 745 » » » NULL, | 745 » » » NULL, |
| 746 » » » &dcache_set_list, &dcache_show_list); | 746 » » » &dcache_set_list, &dcache_show_list); |
| 747 } | 747 } |
| OLD | NEW |