diff options
-rw-r--r-- | gdb/ChangeLog | 5 | ||||
-rw-r--r-- | gdb/dcache.c | 7 | ||||
-rw-r--r-- | gdb/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gdb/testsuite/gdb.base/dcache-line-read-error.c | 107 | ||||
-rw-r--r-- | gdb/testsuite/gdb.base/dcache-line-read-error.exp | 68 |
5 files changed, 190 insertions, 2 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 0c87bff..6fe325d 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,8 @@ +2014-05-21 Pedro Alves <palves@redhat.com> + + * dcache.c (dcache_read_memory_partial): If reading the cache line + fails, fallback to reading just the memory the caller wanted. + 2014-05-20 Doug Evans <dje@google.com> * python/py-progspace.c (py_free_pspace): Call target_gdbarch diff --git a/gdb/dcache.c b/gdb/dcache.c index d3b546b..9780f4d 100644 --- a/gdb/dcache.c +++ b/gdb/dcache.c @@ -497,8 +497,11 @@ dcache_read_memory_partial (struct target_ops *ops, DCACHE *dcache, if (i == 0) { - /* FIXME: We lose the real error status. */ - return TARGET_XFER_E_IO; + /* Even though reading the whole line failed, we may be able to + read a piece starting where the caller wanted. */ + return ops->to_xfer_partial (ops, TARGET_OBJECT_MEMORY, NULL, + myaddr, NULL, memaddr, len, + xfered_len); } else { diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index be0bdf3..1e39142 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2014-05-21 Pedro Alves <palves@redhat.com> + + * gdb.base/dcache-line-read-error.c: New. + * gdb.base/dcache-line-read-error.exp: New. + 2014-05-20 Pedro Alves <palves@redhat.com> * gdb.base/compare-sections.c: New file. diff --git a/gdb/testsuite/gdb.base/dcache-line-read-error.c b/gdb/testsuite/gdb.base/dcache-line-read-error.c new file mode 100644 index 0000000..4120593 --- /dev/null +++ b/gdb/testsuite/gdb.base/dcache-line-read-error.c @@ -0,0 +1,107 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2012-2014 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include <stdlib.h> +#include <stdio.h> +#include <sys/mman.h> +#include <unistd.h> +#include <string.h> + +size_t pg_size; +void *first_mapped_page; +void *last_mapped_page; + +void +breakpt (void) +{ + /* Nothing. */ +} + +int +main (void) +{ + void *p; + int pg_count; + size_t i; + + /* Map 6 contiguous pages, and then unmap all second first, and + second last. + + From GDB we will disassemble each of the _mapped_ pages, with a + code-cache (dcache) line size bigger than the page size (twice + bigger). This makes GDB try to read one page before the mapped + page once, and the page after another time. GDB should give no + error in either case. + + That is, depending on where the kernel aligns the pages, we get + either: + + .---.---.---.---.---.---. + | U | M | U | U | M | U | + '---'---'---'---'---'---. + | | | | <- line alignment + ^^^^^^^ ^^^^^^^ + | | + + line1 + line2 + + Or: + + .---.---.---.---.---.---. + | U | M | U | U | M | U | + '---'---'---'---'---'---. + | | | <- line alignment + ^^^^^^^ ^^^^^^^ + | | + line1 + + line2 + + Note we really want to test that dcache behaves correctly when + reading a cache line fails. We're just using unmapped memory as + proxy for any kind of error. */ + + pg_size = getpagesize (); + pg_count = 6; + + p = mmap (0, pg_count * pg_size, PROT_READ|PROT_WRITE, + MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); + if (p == MAP_FAILED) + { + perror ("mmap"); + return EXIT_FAILURE; + } + + /* Leave memory zero-initialized. Disassembling 0s should behave on + all targets. */ + + for (i = 0; i < pg_count; i++) + { + if (i == 1 || i == 4) + continue; + + if (munmap (p + (i * pg_size), pg_size) == -1) + { + perror ("munmap"); + return EXIT_FAILURE; + } + } + + first_mapped_page = p + 1 * pg_size;; + last_mapped_page = p + 4 * pg_size; + + breakpt (); + + return EXIT_SUCCESS; +} diff --git a/gdb/testsuite/gdb.base/dcache-line-read-error.exp b/gdb/testsuite/gdb.base/dcache-line-read-error.exp new file mode 100644 index 0000000..7e75460 --- /dev/null +++ b/gdb/testsuite/gdb.base/dcache-line-read-error.exp @@ -0,0 +1,68 @@ +# Copyright 2014 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# Test that dcache behaves correctly when reading a cache line fails. + +standard_testfile + +if { [prepare_for_testing "failed to prepare" ${testfile}] } { + return -1 +} + +if ![runto breakpt] { + return -1 +} + +# Issue the "delete mem" command. This makes GDB ignore the +# target-provided list, if any. + +proc delete_mem {} { + global gdb_prompt + + set test "delete mem" + gdb_test_multiple $test $test { + -re "Delete all memory regions.*y or n.*$" { + send_gdb "y\n" + exp_continue + } + -re "$gdb_prompt $" { + pass $test + } + } +} + +# Make the dcache line size bigger than the pagesize. +set pagesize [get_integer_valueof "pg_size" -1] +set linesize [expr $pagesize * 2] + +gdb_test_no_output "set dcache line-size $linesize" \ + "set dcache line size to twice the pagesize" + +gdb_test "info dcache" \ + "Dcache 4096 lines of $linesize bytes each.\r\nNo data cache available." + +# Make sure dcache doesn't automatically skip unmapped regions. +delete_mem + +gdb_test "info mem" \ + "Using user-defined memory regions.\r\nThere are no memory regions defined\." + +# Given the line size is bigger than the page size, we have +# alternating mapped and unmapped pages, these make dcache fail to +# fill in the cache line. GDB used to have a bug where that failure +# would end up as user-visible error. The range being disassembled is +# wholly available, so GDB should succeed. +gdb_test "disassemble first_mapped_page, +10" "End of assembler dump\." +gdb_test "disassemble last_mapped_page, +10" "End of assembler dump\." |