--- /dev/null
+# Copyright 2020 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/>.
+
+# Tests of core file memory accesses when mmap() has been used to
+# create a "hole" of zeroes over pre-existing memory regions. See
+# coremaker2.c for details.
+
+# are we on a target board
+if ![isnative] then {
+ return
+}
+
+# Some of these tests will only work on GNU/Linux due to the
+# fact that Linux core files includes a section describing
+# memory address to file mappings. We'll use set_up_xfail for the
+# affected tests. As other targets become supported, the condition
+# can be changed accordingly.
+
+set xfail 0
+if { ![istarget *-linux*] } {
+ set xfail 1
+}
+
+standard_testfile coremaker2.c
+
+if {[build_executable $testfile.exp $testfile $srcfile debug] == -1} {
+ untested "failed to compile"
+ return -1
+}
+
+set corefile [core_find $binfile {}]
+if {$corefile == ""} {
+ return 0
+}
+
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+# Attempt to load the core file.
+
+gdb_test_multiple "core-file $corefile" "core-file command" {
+ -re ".* program is being debugged already.*y or n. $" {
+ # gdb_load may connect us to a gdbserver.
+ send_gdb "y\n"
+ exp_continue
+ }
+ -re "Core was generated by .*corefile.*\r\n\#0 .*\(\).*\r\n$gdb_prompt $" {
+ pass "core-file command"
+ }
+ -re "Core was generated by .*\r\n\#0 .*\(\).*\r\n$gdb_prompt $" {
+ pass "core-file command (with bad program name)"
+ }
+ -re ".*registers from core file: File in wrong format.* $" {
+ fail "core-file command (could not read registers from core file)"
+ }
+}
+
+# Perform the "interesting" tests which check the contents of certain
+# memory regions.
+
+proc do_tests { } {
+ global xfail
+
+ # Check contents of beginning of buf_rw and buf_ro.
+
+ gdb_test {print/x buf_rw[0]@4} {\{0x6b, 0x6b, 0x6b, 0x6b\}}
+ gdb_test {print/x buf_ro[0]@4} {\{0xc5, 0xc5, 0xc5, 0xc5\}}
+
+ # Check for correct contents at beginning of mbuf_rw and mbuf_ro.
+
+ gdb_test {print/x mbuf_rw[0]@4} {\{0x0, 0x0, 0x0, 0x0\}}
+
+ if { $xfail } { setup_xfail "*-*-*" }
+ gdb_test {print/x mbuf_ro[0]@4} {\{0x0, 0x0, 0x0, 0x0\}}
+
+ # Check contents of mbuf_rw and mbuf_ro at the end of these regions.
+
+ gdb_test {print/x mbuf_rw[pagesize-4]@4} {\{0x0, 0x0, 0x0, 0x0\}}
+
+ if { $xfail } { setup_xfail "*-*-*" }
+ gdb_test {print/x mbuf_ro[pagesize-4]@4} {\{0x0, 0x0, 0x0, 0x0\}}
+
+ # Check contents of mbuf_rw and mbuf_ro, right before the hole,
+ # overlapping into the beginning of these mmap'd regions.
+
+ gdb_test {print/x mbuf_rw[-3]@6} {\{0x6b, 0x6b, 0x6b, 0x0, 0x0, 0x0\}}
+
+ if { $xfail } { setup_xfail "*-*-*" }
+ gdb_test {print/x mbuf_ro[-3]@6} {\{0xc5, 0xc5, 0xc5, 0x0, 0x0, 0x0\}}
+
+ # Likewise, at the end of the mbuf_rw and mbuf_ro, with overlap.
+
+ # If this test FAILs, it's probably a genuine bug unrelated to whether
+ # the core file includes a section describing memory address to file
+ # mappings or not. (So don't xfail it!)
+ gdb_test {print/x mbuf_rw[pagesize-3]@6} {\{0x0, 0x0, 0x0, 0x6b, 0x6b, 0x6b\}}
+
+ if { $xfail } { setup_xfail "*-*-*" }
+ gdb_test {print/x mbuf_ro[pagesize-3]@6} {\{0x0, 0x0, 0x0, 0xc5, 0xc5, 0xc5\}}
+
+ # Check contents of (what should be) buf_rw and buf_ro immediately after
+ # mbuf_rw and mbuf_ro holes.
+
+ gdb_test {print/x mbuf_rw[pagesize]@4} {\{0x6b, 0x6b, 0x6b, 0x6b\}}
+ gdb_test {print/x mbuf_ro[pagesize]@4} {\{0xc5, 0xc5, 0xc5, 0xc5\}}
+
+ # Check contents at ends of buf_rw and buf_rw.
+
+ gdb_test {print/x buf_rw[sizeof(buf_rw)-4]@4} {\{0x6b, 0x6b, 0x6b, 0x6b\}}
+ gdb_test {print/x buf_ro[sizeof(buf_ro)-4]@4} {\{0xc5, 0xc5, 0xc5, 0xc5\}}
+}
+
+# Run tests with kernel-produced core file.
+
+with_test_prefix "kernel core" {
+ do_tests
+}
+
+# Verify that "maint print core-file-backed-mappings" exists and does
+# not crash GDB. If it produces any output at all, make sure that
+# that output at least mentions binfile.
+
+set test "maint print core-file-backed-mappings"
+gdb_test_multiple $test "" {
+ -re ".*$binfile.*$gdb_prompt $" {
+ pass $test
+ }
+ -re "^$test\[\r\n\]*$gdb_prompt $" {
+ pass "$test (no output)"
+ }
+}
+
+# Restart and run to the abort call.
+
+clean_restart $binfile
+
+if ![runto_main] then {
+ fail "can't run to main"
+ return
+}
+
+gdb_breakpoint [gdb_get_line_number "abort"]
+gdb_continue_to_breakpoint "at abort"
+
+# Do not execute abort call; instead, invoke gcore command to make a
+# gdb-produced core file.
+
+set corefile [standard_output_file gcore.test]
+set core_supported [gdb_gcore_cmd "$corefile" "save a corefile"]
+if {!$core_supported} {
+ return
+}
+
+# maint print-core-file-backed-mappings shouldn't produce any output
+# when not debugging a core file.
+
+gdb_test_no_output "maint print core-file-backed-mappings" \
+ "maint print core-file-backed-mapping with no core file"
+
+clean_restart $binfile
+
+set core_loaded [gdb_core_cmd "$corefile" "re-load generated corefile"]
+if { $core_loaded == -1 } {
+ # No use proceeding from here.
+ return
+}
+
+# Run tests using gcore-produced core file.
+
+with_test_prefix "gcore core" {
+ do_tests
+}
--- /dev/null
+/* Copyright 1992-2020 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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/>. */
+
+/* This test has two large memory areas buf_rw and buf_ro.
+
+ buf_rw is written to by the program while buf_ro is initialized at
+ compile / load time. Thus, when a core file is created, buf_rw's
+ memory should reside in the core file, but buf_ro probably won't be.
+ Instead, the contents of buf_ro are available from the executable.
+
+ Now, for the wrinkle: We create a one page read-only mapping over
+ both of these areas. This will create a one page "hole" of all
+ zeros in each area.
+
+ Will GDB be able to correctly read memory from each of the four
+ (or six, if you count the regions on the other side of each hole)
+ memory regions? */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+/* These are globals so that we can find them easily when debugging
+ the core file. */
+long pagesize;
+unsigned long long addr;
+char *mbuf_ro;
+char *mbuf_rw;
+
+/* 24 KiB buffer. */
+char buf_rw[24 * 1024];
+
+/* 24 KiB worth of data. For this test case, we can't allocate a
+ buffer and then fill it; we want GDB to have to read this data
+ from the executable; it should NOT find it in the core file. */
+
+#define C5_16 \
+ 0xc5, 0xc5, 0xc5, 0xc5, \
+ 0xc5, 0xc5, 0xc5, 0xc5, \
+ 0xc5, 0xc5, 0xc5, 0xc5, \
+ 0xc5, 0xc5, 0xc5, 0xc5
+
+#define C5_256 \
+ C5_16, C5_16, C5_16, C5_16, \
+ C5_16, C5_16, C5_16, C5_16, \
+ C5_16, C5_16, C5_16, C5_16, \
+ C5_16, C5_16, C5_16, C5_16
+
+#define C5_1k \
+ C5_256, C5_256, C5_256, C5_256
+
+#define C5_24k \
+ C5_1k, C5_1k, C5_1k, C5_1k, \
+ C5_1k, C5_1k, C5_1k, C5_1k, \
+ C5_1k, C5_1k, C5_1k, C5_1k, \
+ C5_1k, C5_1k, C5_1k, C5_1k, \
+ C5_1k, C5_1k, C5_1k, C5_1k, \
+ C5_1k, C5_1k, C5_1k, C5_1k
+
+const char buf_ro[] = { C5_24k };
+
+int
+main (int argc, char **argv)
+{
+ int i, bitcount;
+
+#ifdef _SC_PAGESIZE
+ pagesize = sysconf (_SC_PAGESIZE);
+#else
+ pagesize = 8192;
+#endif
+
+ /* Verify that pagesize is a power of 2. */
+ bitcount = 0;
+ for (i = 0; i < 4 * sizeof (pagesize); i++)
+ if (pagesize & (1 << i))
+ bitcount++;
+
+ if (bitcount != 1)
+ {
+ fprintf (stderr, "pagesize is not a power of 2.\n");
+ exit (1);
+ }
+
+ /* Compute an address that should be within buf_ro. Complain if not. */
+ addr = ((unsigned long long) buf_ro + pagesize) & ~(pagesize - 1);
+
+ if (addr <= (unsigned long long) buf_ro
+ || addr >= (unsigned long long) buf_ro + sizeof (buf_ro))
+ {
+ fprintf (stderr, "Unable to compute a suitable address within buf_ro.\n");
+ exit (1);
+ }
+
+ mbuf_ro = mmap ((void *) addr, pagesize, PROT_READ,
+ MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
+
+ if (mbuf_ro == MAP_FAILED)
+ {
+ fprintf (stderr, "mmap #1 failed: %s.\n", strerror (errno));
+ exit (1);
+ }
+
+ /* Write (and fill) the R/W region. */
+ for (i = 0; i < sizeof (buf_rw); i++)
+ buf_rw[i] = 0x6b;
+
+ /* Compute an mmap address within buf_rw. Complain if it's somewhere
+ else. */
+ addr = ((unsigned long long) buf_rw + pagesize) & ~(pagesize - 1);
+
+ if (addr <= (unsigned long long) buf_rw
+ || addr >= (unsigned long long) buf_rw + sizeof (buf_rw))
+ {
+ fprintf (stderr, "Unable to compute a suitable address within buf_rw.\n");
+ exit (1);
+ }
+
+ mbuf_rw = mmap ((void *) addr, pagesize, PROT_READ,
+ MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
+
+ if (mbuf_rw == MAP_FAILED)
+ {
+ fprintf (stderr, "mmap #2 failed: %s.\n", strerror (errno));
+ exit (1);
+ }
+
+ /* With correct ulimit, etc. this should cause a core dump. */
+ abort ();
+}