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 |