diff --git a/gdb/corelow.c b/gdb/corelow.c index 2b7a3550fc1..178f9e27898 100644 --- a/gdb/corelow.c +++ b/gdb/corelow.c @@ -160,13 +160,6 @@ class core_target final : public process_stratum_target /* Build m_core_file_mappings. Called from the constructor. */ void build_file_mappings (); - /* Helper method for xfer_partial. */ - enum target_xfer_status xfer_memory_via_mappings (gdb_byte *readbuf, - const gdb_byte *writebuf, - ULONGEST offset, - ULONGEST len, - ULONGEST *xfered_len); - /* FIXME: kettenis/20031023: Eventually this field should disappear. */ struct gdbarch *m_core_gdbarch = NULL; @@ -964,55 +957,6 @@ core_target::files_info () print_section_info (&m_core_section_table, current_program_space->core_bfd ()); } -/* Helper method for core_target::xfer_partial. */ - -enum target_xfer_status -core_target::xfer_memory_via_mappings (gdb_byte *readbuf, - const gdb_byte *writebuf, - ULONGEST offset, ULONGEST len, - ULONGEST *xfered_len) -{ - enum target_xfer_status xfer_status; - - xfer_status = (section_table_xfer_memory_partial - (readbuf, writebuf, - offset, len, xfered_len, - m_core_file_mappings)); - - if (xfer_status == TARGET_XFER_OK || m_core_unavailable_mappings.empty ()) - return xfer_status; - - /* There are instances - e.g. when debugging within a docker - container using the AUFS storage driver - where the pathnames - obtained from the note section are incorrect. Despite the path - being wrong, just knowing the start and end addresses of the - mappings is still useful; we can attempt an access of the file - stratum constrained to the address ranges corresponding to the - unavailable mappings. */ - - ULONGEST memaddr = offset; - ULONGEST memend = offset + len; - - for (const auto &mr : m_core_unavailable_mappings) - { - if (mr.contains (memaddr)) - { - if (!mr.contains (memend)) - len = mr.start + mr.length - memaddr; - - xfer_status = this->beneath ()->xfer_partial (TARGET_OBJECT_MEMORY, - NULL, - readbuf, - writebuf, - offset, - len, - xfered_len); - break; - } - } - - return xfer_status; -} enum target_xfer_status core_target::xfer_partial (enum target_object object, const char *annex, @@ -1040,26 +984,72 @@ core_target::xfer_partial (enum target_object object, const char *annex, if (xfer_status == TARGET_XFER_OK) return TARGET_XFER_OK; - /* Check file backed mappings. If they're available, use - core file provided mappings (e.g. from .note.linuxcore.file - or the like) as this should provide a more accurate - result. If not, check the stratum beneath us, which should - be the file stratum. - - We also check unavailable mappings due to Docker/AUFS driver - issues. */ - if (!m_core_file_mappings.empty () - || !m_core_unavailable_mappings.empty ()) + /* Check file backed mappings. If they're available, use core file + provided mappings (e.g. from .note.linuxcore.file or the like) + as this should provide a more accurate result. */ + if (!m_core_file_mappings.empty ()) { - xfer_status = xfer_memory_via_mappings (readbuf, writebuf, offset, - len, xfered_len); + xfer_status = section_table_xfer_memory_partial + (readbuf, writebuf, offset, len, xfered_len, + m_core_file_mappings); + if (xfer_status == TARGET_XFER_OK) + return xfer_status; + } + + /* If the access is within an unavailable file mapping then we try + to check in the stratum below (the executable stratum). The + thinking here is that if the mapping was read/write then the + contents would have been written into the core file and the + access would have been satisfied by m_core_section_table. + + But if the access has not yet been resolved then we can assume + the access is read-only. If the executable was not found + during the mapped file check then we'll have an unavailable + mapping entry, however, if the user has provided the executable + (maybe in a different location) then we might be able to + resolve the access from there. + + If that fails, but the access is within an unavailable region, + then the access itself should fail. */ + for (const auto &mr : m_core_unavailable_mappings) + { + if (mr.contains (offset)) + { + if (!mr.contains (offset + len)) + len = mr.start + mr.length - offset; + + xfer_status + = this->beneath ()->xfer_partial (TARGET_OBJECT_MEMORY, + nullptr, readbuf, + writebuf, offset, + len, xfered_len); + if (xfer_status == TARGET_XFER_OK) + return TARGET_XFER_OK; + + return TARGET_XFER_E_IO; + } + } + + /* The following is acting as a fallback in case we encounter a + situation where the core file is lacking and mapped file + information. Here we query the exec file stratum to see if it + can resolve the access. Doing this when we are missing mapped + file information might be the best we can do, but there are + certainly cases this will get wrong, e.g. if an inferior created + a zero initialised mapping over the top of some data that exists + within the executable then this will return the executable data + rather than the zero data. Maybe we should just drop this + block? */ + if (m_core_file_mappings.empty () + && m_core_unavailable_mappings.empty ()) + { + xfer_status + = this->beneath ()->xfer_partial (object, annex, readbuf, + writebuf, offset, len, + xfered_len); + if (xfer_status == TARGET_XFER_OK) + return TARGET_XFER_OK; } - else - xfer_status = this->beneath ()->xfer_partial (object, annex, readbuf, - writebuf, offset, len, - xfered_len); - if (xfer_status == TARGET_XFER_OK) - return TARGET_XFER_OK; /* Finally, attempt to access data in core file sections with no contents. These will typically read as all zero. */ diff --git a/gdb/testsuite/gdb.base/corefile.exp b/gdb/testsuite/gdb.base/corefile.exp index 79363c5db53..f4f102a156b 100644 --- a/gdb/testsuite/gdb.base/corefile.exp +++ b/gdb/testsuite/gdb.base/corefile.exp @@ -199,6 +199,45 @@ gdb_test "up" "#\[0-9\]* *(\[0-9xa-fH'\]* in)? .* \\(.*\\).*" "up, reinit" gdb_test "core" "No core file now." +# Temporarily move coremmap.data out of the way and reload the core +# file. We should still be able to read buf2 as the contents of this +# are written into the core file. In contrast buf2ro should no longer +# be readable as the contents of this region are not within the core +# file, GDB relies on reading this from the coremmap.data file, which +# can no longer be found. +set coremmap_data_filename \ + [standard_output_file coredir.[getpid]/coremmap.data] +set coremmap_data_backup_filename \ + [standard_output_file coredir.[getpid]/coremmap.data.backup] +remote_exec host "mv ${coremmap_data_filename} \ + ${coremmap_data_backup_filename}" + +clean_restart $binfile + +# Load the core file and check we get a warning about the +# coremmap.data file being missing. +gdb_test_multiple "core-file $corefile" "warn about coremmap.data missing" { + -re -wrap "warning: Can't open file \[^\r\n\]+/coremmap.data during file-backed mapping note processing\r\n.*" { + pass $gdb_test_name + } +} + +# This xfail was just copied from earlier in the script where we also +# read from buf2. +setup_xfail "*-*-sunos*" "*-*-aix*" +gdb_test "x/8bd buf2" \ + ".*:.*0.*1.*2.*3.*4.*5.*6.*7.*" \ + "accessing mmapped data in core file with coremmap.data removed" + +gdb_test "x/8bd buf2ro" \ + "$hex\[^:\]*:\\s+Cannot access memory at address $hex" \ + "accessing read-only mmapped data in core file with coremmap.data removed" + +# Restore the coremmap.data file so later tests don't give warnings +# when the core file is reloaded. +remote_exec host "mv ${coremmap_data_backup_filename} \ + ${coremmap_data_filename}" + # Test that we can unload the core with the "detach" command. proc_with_prefix corefile_detach {} {