Blame SOURCES/gdb-rhbz1085906-coredump_filter-1of2.patch

01917d
commit df8411da087dc05481926f4c4a82deabc5bc3859
01917d
Author: Sergio Durigan Junior <sergiodj@redhat.com>
01917d
Date:   Tue Mar 31 19:32:34 2015 -0400
01917d
01917d
    Implement support for checking /proc/PID/coredump_filter
01917d
    
01917d
    This patch, as the subject says, extends GDB so that it is able to use
01917d
    the contents of the file /proc/PID/coredump_filter when generating a
01917d
    corefile.  This file contains a bit mask that is a representation of
01917d
    the different types of memory mappings in the Linux kernel; the user
01917d
    can choose to dump or not dump a certain type of memory mapping by
01917d
    enabling/disabling the respective bit in the bit mask.  Currently,
01917d
    here is what is supported:
01917d
    
01917d
      bit 0  Dump anonymous private mappings.
01917d
      bit 1  Dump anonymous shared mappings.
01917d
      bit 2  Dump file-backed private mappings.
01917d
      bit 3  Dump file-backed shared mappings.
01917d
      bit 4 (since Linux 2.6.24)
01917d
             Dump ELF headers.
01917d
      bit 5 (since Linux 2.6.28)
01917d
             Dump private huge pages.
01917d
      bit 6 (since Linux 2.6.28)
01917d
             Dump shared huge pages.
01917d
    
01917d
    (This table has been taken from core(5), but you can also read about it
01917d
    on Documentation/filesystems/proc.txt inside the Linux kernel source
01917d
    tree).
01917d
    
01917d
    The default value for this file, used by the Linux kernel, is 0x33,
01917d
    which means that bits 0, 1, 4 and 5 are enabled.  This is also the
01917d
    default for GDB implemented in this patch, FWIW.
01917d
    
01917d
    Well, reading the file is obviously trivial.  The hard part, mind you,
01917d
    is how to determine the types of the memory mappings.  For that, I
01917d
    extended the code of gdb/linux-tdep.c:linux_find_memory_regions_full and
01917d
    made it rely *much more* on the information gathered from
01917d
    /proc/<PID>/smaps.  This file contains a "verbose dump" of the
01917d
    inferior's memory mappings, and we were not using as much information as
01917d
    we could from it.  If you want to read more about this file, take a look
01917d
    at the proc(5) manpage (I will also write a blog post soon about
01917d
    everything I had to learn to get this patch done, and when I it is ready
01917d
    I will post it here).
01917d
    
01917d
    With Oleg Nesterov's help, we could improve the current algorithm for
01917d
    determining whether a memory mapping is anonymous/file-backed,
01917d
    private/shared.  GDB now also respects the MADV_DONTDUMP flag and does
01917d
    not dump the memory mapping marked as so, and will always dump
01917d
    "[vsyscall]" or "[vdso]" mappings (just like the Linux kernel).
01917d
    
01917d
    In a nutshell, what the new code is doing is:
01917d
    
01917d
    - If the mapping is associated to a file whose name ends with
01917d
      " (deleted)", or if the file is "/dev/zero", or if it is "/SYSV%08x"
01917d
      (shared memory), or if there is no file associated with it, or if
01917d
      the AnonHugePages: or the Anonymous: fields in the /proc/PID/smaps
01917d
      have contents, then GDB considers this mapping to be anonymous.
01917d
      There is a special case in this, though: if the memory mapping is a
01917d
      file-backed one, but *also* contains "Anonymous:" or
01917d
      "AnonHugePages:" pages, then GDB considers this mapping to be *both*
01917d
      anonymous and file-backed, just like the Linux kernel does.  What
01917d
      that means is simple: this mapping will be dumped if the user
01917d
      requested anonymous mappings *or* if the user requested file-backed
01917d
      mappings to be present in the corefile.
01917d
    
01917d
      It is worth mentioning that, from all those checks described above,
01917d
      the most fragile is the one to see if the file name ends with
01917d
      " (deleted)".  This does not necessarily mean that the mapping is
01917d
      anonymous, because the deleted file associated with the mapping may
01917d
      have been a hard link to another file, for example.  The Linux
01917d
      kernel checks to see if "i_nlink == 0", but GDB cannot easily do
01917d
      this check (as it has been discussed, GDB would need to run as root,
01917d
      and would need to check the contents of the /proc/PID/map_files/
01917d
      directory in order to determine whether the deleted was a hardlink
01917d
      or not).  Therefore, we made a compromise here, and we assume that
01917d
      if the file name ends with " (deleted)", then the mapping is indeed
01917d
      anonymous.  FWIW, this is something the Linux kernel could do
01917d
      better: expose this information in a more direct way.
01917d
    
01917d
    - If we see the flag "sh" in the VmFlags: field (in /proc/PID/smaps),
01917d
      then certainly the memory mapping is shared (VM_SHARED).  If we have
01917d
      access to the VmFlags, and we don't see the "sh" there, then
01917d
      certainly the mapping is private.  However, older Linux kernels (see
01917d
      the code for more details) do not have the VmFlags field; in that
01917d
      case, we use another heuristic: if we see 'p' in the permission
01917d
      flags, then we assume that the mapping is private, even though the
01917d
      presence of the 's' flag there would mean VM_MAYSHARE, which means
01917d
      the mapping could still be private.  This should work OK enough,
01917d
      however.
01917d
    
01917d
    Finally, it is worth mentioning that I added a new command, 'set
01917d
    use-coredump-filter on/off'.  When it is 'on', it will read the
01917d
    coredump_filter' file (if it exists) and use its value; otherwise, it
01917d
    will use the default value mentioned above (0x33) to decide which memory
01917d
    mappings to dump.
01917d
    
01917d
    gdb/ChangeLog:
01917d
    2015-03-31  Sergio Durigan Junior  <sergiodj@redhat.com>
01917d
    	    Jan Kratochvil  <jan.kratochvil@redhat.com>
01917d
    	    Oleg Nesterov  <oleg@redhat.com>
01917d
    
01917d
    	PR corefiles/16092
01917d
    	* linux-tdep.c: Include 'gdbcmd.h' and 'gdb_regex.h'.
01917d
    	New enum identifying the various options of the coredump_filter
01917d
    	file.
01917d
    	(struct smaps_vmflags): New struct.
01917d
    	(use_coredump_filter): New variable.
01917d
    	(decode_vmflags): New function.
01917d
    	(mapping_is_anonymous_p): Likewise.
01917d
    	(dump_mapping_p): Likewise.
01917d
    	(linux_find_memory_regions_full): New variables
01917d
    	'coredumpfilter_name', 'coredumpfilterdata', 'pid', 'filterflags'.
01917d
    	Removed variable 'modified'.  Read /proc/<PID>/smaps file; improve
01917d
    	parsing of its information.  Implement memory mapping filtering
01917d
    	based on its contents.
01917d
    	(show_use_coredump_filter): New function.
01917d
    	(_initialize_linux_tdep): New command 'set use-coredump-filter'.
01917d
    	* NEWS: Mention the possibility of using the
01917d
    	'/proc/PID/coredump_filter' file when generating a corefile.
01917d
    	Mention new command 'set use-coredump-filter'.
01917d
    
01917d
    gdb/doc/ChangeLog:
01917d
    2015-03-31  Sergio Durigan Junior  <sergiodj@redhat.com>
01917d
    
01917d
    	PR corefiles/16092
01917d
    	* gdb.texinfo (gcore): Mention new command 'set
01917d
    	use-coredump-filter'.
01917d
    	(set use-coredump-filter): Document new command.
01917d
    
01917d
    gdb/testsuite/ChangeLog:
01917d
    2015-03-31  Sergio Durigan Junior  <sergiodj@redhat.com>
01917d
    
01917d
    	PR corefiles/16092
01917d
    	* gdb.base/coredump-filter.c: New file.
01917d
    	* gdb.base/coredump-filter.exp: Likewise.
01917d
01917d
### a/gdb/ChangeLog
01917d
### b/gdb/ChangeLog
01917d
## -1,4 +1,28 @@
01917d
 2015-03-31  Sergio Durigan Junior  <sergiodj@redhat.com>
01917d
+	    Jan Kratochvil  <jan.kratochvil@redhat.com>
01917d
+	    Oleg Nesterov  <oleg@redhat.com>
01917d
+
01917d
+	PR corefiles/16092
01917d
+	* linux-tdep.c: Include 'gdbcmd.h' and 'gdb_regex.h'.
01917d
+	New enum identifying the various options of the coredump_filter
01917d
+	file.
01917d
+	(struct smaps_vmflags): New struct.
01917d
+	(use_coredump_filter): New variable.
01917d
+	(decode_vmflags): New function.
01917d
+	(mapping_is_anonymous_p): Likewise.
01917d
+	(dump_mapping_p): Likewise.
01917d
+	(linux_find_memory_regions_full): New variables
01917d
+	'coredumpfilter_name', 'coredumpfilterdata', 'pid', 'filterflags'.
01917d
+	Removed variable 'modified'.  Read /proc/<PID>/smaps file; improve
01917d
+	parsing of its information.  Implement memory mapping filtering
01917d
+	based on its contents.
01917d
+	(show_use_coredump_filter): New function.
01917d
+	(_initialize_linux_tdep): New command 'set use-coredump-filter'.
01917d
+	* NEWS: Mention the possibility of using the
01917d
+	'/proc/PID/coredump_filter' file when generating a corefile.
01917d
+	Mention new command 'set use-coredump-filter'.
01917d
+
01917d
+2015-03-31  Sergio Durigan Junior  <sergiodj@redhat.com>
01917d
 
01917d
 	* solib-svr4.c (solib_svr4_r_ldsomap): Catch possible exception by
01917d
 	read_memory_unsigned_integer.
01917d
Index: gdb-7.6.1/gdb/NEWS
01917d
===================================================================
01917d
--- gdb-7.6.1.orig/gdb/NEWS	2015-11-27 22:31:13.965841796 +0100
01917d
+++ gdb-7.6.1/gdb/NEWS	2015-11-27 22:31:13.994841957 +0100
01917d
@@ -18,6 +18,14 @@
01917d
   the program interruption transaction diagnostic block (TDB) is now
01917d
   represented as a number of additional "registers" in GDB.
01917d
 
01917d
+* GDB now honors the content of the file /proc/PID/coredump_filter
01917d
+  (PID is the process ID) on GNU/Linux systems.  This file can be used
01917d
+  to specify the types of memory mappings that will be included in a
01917d
+  corefile.  For more information, please refer to the manual page of
01917d
+  "core(5)".  GDB also has a new command: "set use-coredump-filter
01917d
+  on|off".  It allows to set whether GDB will read the content of the
01917d
+  /proc/PID/coredump_filter file when generating a corefile.
01917d
+
01917d
 * New remote packets
01917d
 
01917d
 qXfer:libraries-svr4:read's annex
01917d
Index: gdb-7.6.1/gdb/doc/gdb.texinfo
01917d
===================================================================
01917d
--- gdb-7.6.1.orig/gdb/doc/gdb.texinfo	2015-11-27 22:31:13.811840941 +0100
01917d
+++ gdb-7.6.1/gdb/doc/gdb.texinfo	2015-11-27 22:31:14.001841996 +0100
01917d
@@ -10315,6 +10315,39 @@
01917d
 
01917d
 Note that this command is implemented only for some systems (as of
01917d
 this writing, @sc{gnu}/Linux, FreeBSD, Solaris, and S390).
01917d
+
01917d
+On @sc{gnu}/Linux, this command can take into account the value of the
01917d
+file @file{/proc/@var{pid}/coredump_filter} when generating the core
01917d
+dump (@pxref{set use-coredump-filter}).
01917d
+
01917d
+@kindex set use-coredump-filter
01917d
+@anchor{set use-coredump-filter}
01917d
+@item set use-coredump-filter on
01917d
+@itemx set use-coredump-filter off
01917d
+Enable or disable the use of the file
01917d
+@file{/proc/@var{pid}/coredump_filter} when generating core dump
01917d
+files.  This file is used by the Linux kernel to decide what types of
01917d
+memory mappings will be dumped or ignored when generating a core dump
01917d
+file.  @var{pid} is the process ID of a currently running process.
01917d
+
01917d
+To make use of this feature, you have to write in the
01917d
+@file{/proc/@var{pid}/coredump_filter} file a value, in hexadecimal,
01917d
+which is a bit mask representing the memory mapping types.  If a bit
01917d
+is set in the bit mask, then the memory mappings of the corresponding
01917d
+types will be dumped; otherwise, they will be ignored.  This
01917d
+configuration is inherited by child processes.  For more information
01917d
+about the bits that can be set in the
01917d
+@file{/proc/@var{pid}/coredump_filter} file, please refer to the
01917d
+manpage of @code{core(5)}.
01917d
+
01917d
+By default, this option is @code{on}.  If this option is turned
01917d
+@code{off}, @value{GDBN} does not read the @file{coredump_filter} file
01917d
+and instead uses the same default value as the Linux kernel in order
01917d
+to decide which pages will be dumped in the core dump file.  This
01917d
+value is currently @code{0x33}, which means that bits @code{0}
01917d
+(anonymous private mappings), @code{1} (anonymous shared mappings),
01917d
+@code{4} (ELF headers) and @code{5} (private huge pages) are active.
01917d
+This will cause these memory mappings to be dumped automatically.
01917d
 @end table
01917d
 
01917d
 @node Character Sets
01917d
Index: gdb-7.6.1/gdb/linux-tdep.c
01917d
===================================================================
01917d
--- gdb-7.6.1.orig/gdb/linux-tdep.c	2013-04-05 21:17:27.000000000 +0200
01917d
+++ gdb-7.6.1/gdb/linux-tdep.c	2015-11-27 22:31:14.002842001 +0100
01917d
@@ -33,9 +33,61 @@
01917d
 #include "arch-utils.h"
01917d
 #include "gdb_obstack.h"
01917d
 #include "cli/cli-utils.h"
01917d
+#include "gdbcmd.h"
01917d
+#include "gdb_regex.h"
01917d
 
01917d
 #include <ctype.h>
01917d
 
01917d
+/* This enum represents the values that the user can choose when
01917d
+   informing the Linux kernel about which memory mappings will be
01917d
+   dumped in a corefile.  They are described in the file
01917d
+   Documentation/filesystems/proc.txt, inside the Linux kernel
01917d
+   tree.  */
01917d
+
01917d
+enum
01917d
+  {
01917d
+    COREFILTER_ANON_PRIVATE = 1 << 0,
01917d
+    COREFILTER_ANON_SHARED = 1 << 1,
01917d
+    COREFILTER_MAPPED_PRIVATE = 1 << 2,
01917d
+    COREFILTER_MAPPED_SHARED = 1 << 3,
01917d
+    COREFILTER_ELF_HEADERS = 1 << 4,
01917d
+    COREFILTER_HUGETLB_PRIVATE = 1 << 5,
01917d
+    COREFILTER_HUGETLB_SHARED = 1 << 6,
01917d
+  };
01917d
+
01917d
+/* This struct is used to map flags found in the "VmFlags:" field (in
01917d
+   the /proc/<PID>/smaps file).  */
01917d
+
01917d
+struct smaps_vmflags
01917d
+  {
01917d
+    /* Zero if this structure has not been initialized yet.  It
01917d
+       probably means that the Linux kernel being used does not emit
01917d
+       the "VmFlags:" field on "/proc/PID/smaps".  */
01917d
+
01917d
+    unsigned int initialized_p : 1;
01917d
+
01917d
+    /* Memory mapped I/O area (VM_IO, "io").  */
01917d
+
01917d
+    unsigned int io_page : 1;
01917d
+
01917d
+    /* Area uses huge TLB pages (VM_HUGETLB, "ht").  */
01917d
+
01917d
+    unsigned int uses_huge_tlb : 1;
01917d
+
01917d
+    /* Do not include this memory region on the coredump (VM_DONTDUMP, "dd").  */
01917d
+
01917d
+    unsigned int exclude_coredump : 1;
01917d
+
01917d
+    /* Is this a MAP_SHARED mapping (VM_SHARED, "sh").  */
01917d
+
01917d
+    unsigned int shared_mapping : 1;
01917d
+  };
01917d
+
01917d
+/* Whether to take the /proc/PID/coredump_filter into account when
01917d
+   generating a corefile.  */
01917d
+
01917d
+static int use_coredump_filter = 1;
01917d
+
01917d
 static struct gdbarch_data *linux_gdbarch_data_handle;
01917d
 
01917d
 struct linux_gdbarch_data
01917d
@@ -245,6 +297,271 @@
01917d
   *filename = p;
01917d
 }
01917d
 
01917d
+/* Helper function to decode the "VmFlags" field in /proc/PID/smaps.
01917d
+
01917d
+   This function was based on the documentation found on
01917d
+   <Documentation/filesystems/proc.txt>, on the Linux kernel.
01917d
+
01917d
+   Linux kernels before commit
01917d
+   834f82e2aa9a8ede94b17b656329f850c1471514 (3.10) do not have this
01917d
+   field on smaps.  */
01917d
+
01917d
+static void
01917d
+decode_vmflags (char *p, struct smaps_vmflags *v)
01917d
+{
01917d
+  char *saveptr;
01917d
+  const char *s;
01917d
+
01917d
+  v->initialized_p = 1;
01917d
+  p = skip_to_space (p);
01917d
+  p = skip_spaces (p);
01917d
+
01917d
+  for (s = strtok_r (p, " ", &saveptr);
01917d
+       s != NULL;
01917d
+       s = strtok_r (NULL, " ", &saveptr))
01917d
+    {
01917d
+      if (strcmp (s, "io") == 0)
01917d
+	v->io_page = 1;
01917d
+      else if (strcmp (s, "ht") == 0)
01917d
+	v->uses_huge_tlb = 1;
01917d
+      else if (strcmp (s, "dd") == 0)
01917d
+	v->exclude_coredump = 1;
01917d
+      else if (strcmp (s, "sh") == 0)
01917d
+	v->shared_mapping = 1;
01917d
+    }
01917d
+}
01917d
+
01917d
+/* Compile a regexp and throw an exception on error.  This returns a
01917d
+   cleanup to free the resulting pattern on success.  RX must not be
01917d
+   NULL.  */
01917d
+
01917d
+static struct cleanup *
01917d
+compile_rx_or_error (regex_t *pattern, const char *rx, const char *message)
01917d
+{
01917d
+  int code;
01917d
+
01917d
+  gdb_assert (rx != NULL);
01917d
+
01917d
+  code = regcomp (pattern, rx, REG_NOSUB);
01917d
+  if (code != 0)
01917d
+    {
01917d
+      char *err = get_regcomp_error (code, pattern);
01917d
+
01917d
+      make_cleanup (xfree, err);
01917d
+      error (("%s: %s"), message, err);
01917d
+    }
01917d
+
01917d
+  return make_regfree_cleanup (pattern);
01917d
+}
01917d
+
01917d
+/* Return 1 if the memory mapping is anonymous, 0 otherwise.
01917d
+
01917d
+   FILENAME is the name of the file present in the first line of the
01917d
+   memory mapping, in the "/proc/PID/smaps" output.  For example, if
01917d
+   the first line is:
01917d
+
01917d
+   7fd0ca877000-7fd0d0da0000 r--p 00000000 fd:02 2100770   /path/to/file
01917d
+
01917d
+   Then FILENAME will be "/path/to/file".  */
01917d
+
01917d
+static int
01917d
+mapping_is_anonymous_p (const char *filename)
01917d
+{
01917d
+  static regex_t dev_zero_regex, shmem_file_regex, file_deleted_regex;
01917d
+  static int init_regex_p = 0;
01917d
+
01917d
+  if (!init_regex_p)
01917d
+    {
01917d
+      struct cleanup *c = make_cleanup (null_cleanup, NULL);
01917d
+
01917d
+      /* Let's be pessimistic and assume there will be an error while
01917d
+	 compiling the regex'es.  */
01917d
+      init_regex_p = -1;
01917d
+
01917d
+      /* DEV_ZERO_REGEX matches "/dev/zero" filenames (with or
01917d
+	 without the "(deleted)" string in the end).  We know for
01917d
+	 sure, based on the Linux kernel code, that memory mappings
01917d
+	 whose associated filename is "/dev/zero" are guaranteed to be
01917d
+	 MAP_ANONYMOUS.  */
01917d
+      compile_rx_or_error (&dev_zero_regex, "^/dev/zero\\( (deleted)\\)\\?$",
01917d
+			   _("Could not compile regex to match /dev/zero "
01917d
+			     "filename"));
01917d
+      /* SHMEM_FILE_REGEX matches "/SYSV%08x" filenames (with or
01917d
+	 without the "(deleted)" string in the end).  These filenames
01917d
+	 refer to shared memory (shmem), and memory mappings
01917d
+	 associated with them are MAP_ANONYMOUS as well.  */
01917d
+      compile_rx_or_error (&shmem_file_regex,
01917d
+			   "^/\\?SYSV[0-9a-fA-F]\\{8\\}\\( (deleted)\\)\\?$",
01917d
+			   _("Could not compile regex to match shmem "
01917d
+			     "filenames"));
01917d
+      /* FILE_DELETED_REGEX is a heuristic we use to try to mimic the
01917d
+	 Linux kernel's 'n_link == 0' code, which is responsible to
01917d
+	 decide if it is dealing with a 'MAP_SHARED | MAP_ANONYMOUS'
01917d
+	 mapping.  In other words, if FILE_DELETED_REGEX matches, it
01917d
+	 does not necessarily mean that we are dealing with an
01917d
+	 anonymous shared mapping.  However, there is no easy way to
01917d
+	 detect this currently, so this is the best approximation we
01917d
+	 have.
01917d
+
01917d
+	 As a result, GDB will dump readonly pages of deleted
01917d
+	 executables when using the default value of coredump_filter
01917d
+	 (0x33), while the Linux kernel will not dump those pages.
01917d
+	 But we can live with that.  */
01917d
+      compile_rx_or_error (&file_deleted_regex, " (deleted)$",
01917d
+			   _("Could not compile regex to match "
01917d
+			     "'<file> (deleted)'"));
01917d
+      /* We will never release these regexes, so just discard the
01917d
+	 cleanups.  */
01917d
+      discard_cleanups (c);
01917d
+
01917d
+      /* If we reached this point, then everything succeeded.  */
01917d
+      init_regex_p = 1;
01917d
+    }
01917d
+
01917d
+  if (init_regex_p == -1)
01917d
+    {
01917d
+      const char deleted[] = " (deleted)";
01917d
+      size_t del_len = sizeof (deleted) - 1;
01917d
+      size_t filename_len = strlen (filename);
01917d
+
01917d
+      /* There was an error while compiling the regex'es above.  In
01917d
+	 order to try to give some reliable information to the caller,
01917d
+	 we just try to find the string " (deleted)" in the filename.
01917d
+	 If we managed to find it, then we assume the mapping is
01917d
+	 anonymous.  */
01917d
+      return (filename_len >= del_len
01917d
+	      && strcmp (filename + filename_len - del_len, deleted) == 0);
01917d
+    }
01917d
+
01917d
+  if (*filename == '\0'
01917d
+      || regexec (&dev_zero_regex, filename, 0, NULL, 0) == 0
01917d
+      || regexec (&shmem_file_regex, filename, 0, NULL, 0) == 0
01917d
+      || regexec (&file_deleted_regex, filename, 0, NULL, 0) == 0)
01917d
+    return 1;
01917d
+
01917d
+  return 0;
01917d
+}
01917d
+
01917d
+/* Return 0 if the memory mapping (which is related to FILTERFLAGS, V,
01917d
+   MAYBE_PRIVATE_P, and MAPPING_ANONYMOUS_P) should not be dumped, or
01917d
+   greater than 0 if it should.
01917d
+
01917d
+   In a nutshell, this is the logic that we follow in order to decide
01917d
+   if a mapping should be dumped or not.
01917d
+
01917d
+   - If the mapping is associated to a file whose name ends with
01917d
+     " (deleted)", or if the file is "/dev/zero", or if it is
01917d
+     "/SYSV%08x" (shared memory), or if there is no file associated
01917d
+     with it, or if the AnonHugePages: or the Anonymous: fields in the
01917d
+     /proc/PID/smaps have contents, then GDB considers this mapping to
01917d
+     be anonymous.  Otherwise, GDB considers this mapping to be a
01917d
+     file-backed mapping (because there will be a file associated with
01917d
+     it).
01917d
+ 
01917d
+     It is worth mentioning that, from all those checks described
01917d
+     above, the most fragile is the one to see if the file name ends
01917d
+     with " (deleted)".  This does not necessarily mean that the
01917d
+     mapping is anonymous, because the deleted file associated with
01917d
+     the mapping may have been a hard link to another file, for
01917d
+     example.  The Linux kernel checks to see if "i_nlink == 0", but
01917d
+     GDB cannot easily (and normally) do this check (iff running as
01917d
+     root, it could find the mapping in /proc/PID/map_files/ and
01917d
+     determine whether there still are other hard links to the
01917d
+     inode/file).  Therefore, we made a compromise here, and we assume
01917d
+     that if the file name ends with " (deleted)", then the mapping is
01917d
+     indeed anonymous.  FWIW, this is something the Linux kernel could
01917d
+     do better: expose this information in a more direct way.
01917d
+ 
01917d
+   - If we see the flag "sh" in the "VmFlags:" field (in
01917d
+     /proc/PID/smaps), then certainly the memory mapping is shared
01917d
+     (VM_SHARED).  If we have access to the VmFlags, and we don't see
01917d
+     the "sh" there, then certainly the mapping is private.  However,
01917d
+     Linux kernels before commit
01917d
+     834f82e2aa9a8ede94b17b656329f850c1471514 (3.10) do not have the
01917d
+     "VmFlags:" field; in that case, we use another heuristic: if we
01917d
+     see 'p' in the permission flags, then we assume that the mapping
01917d
+     is private, even though the presence of the 's' flag there would
01917d
+     mean VM_MAYSHARE, which means the mapping could still be private.
01917d
+     This should work OK enough, however.  */
01917d
+
01917d
+static int
01917d
+dump_mapping_p (unsigned int filterflags, const struct smaps_vmflags *v,
01917d
+		int maybe_private_p, int mapping_anon_p, int mapping_file_p,
01917d
+		const char *filename)
01917d
+{
01917d
+  /* Initially, we trust in what we received from our caller.  This
01917d
+     value may not be very precise (i.e., it was probably gathered
01917d
+     from the permission line in the /proc/PID/smaps list, which
01917d
+     actually refers to VM_MAYSHARE, and not VM_SHARED), but it is
01917d
+     what we have until we take a look at the "VmFlags:" field
01917d
+     (assuming that the version of the Linux kernel being used
01917d
+     supports it, of course).  */
01917d
+  int private_p = maybe_private_p;
01917d
+
01917d
+  /* We always dump vDSO and vsyscall mappings, because it's likely that
01917d
+     there'll be no file to read the contents from at core load time.
01917d
+     The kernel does the same.  */
01917d
+  if (strcmp ("[vdso]", filename) == 0
01917d
+      || strcmp ("[vsyscall]", filename) == 0)
01917d
+    return 1;
01917d
+
01917d
+  if (v->initialized_p)
01917d
+    {
01917d
+      /* We never dump I/O mappings.  */
01917d
+      if (v->io_page)
01917d
+	return 0;
01917d
+
01917d
+      /* Check if we should exclude this mapping.  */
01917d
+      if (v->exclude_coredump)
01917d
+	return 0;
01917d
+
01917d
+      /* Update our notion of whether this mapping is shared or
01917d
+	 private based on a trustworthy value.  */
01917d
+      private_p = !v->shared_mapping;
01917d
+
01917d
+      /* HugeTLB checking.  */
01917d
+      if (v->uses_huge_tlb)
01917d
+	{
01917d
+	  if ((private_p && (filterflags & COREFILTER_HUGETLB_PRIVATE))
01917d
+	      || (!private_p && (filterflags & COREFILTER_HUGETLB_SHARED)))
01917d
+	    return 1;
01917d
+
01917d
+	  return 0;
01917d
+	}
01917d
+    }
01917d
+
01917d
+  if (private_p)
01917d
+    {
01917d
+      if (mapping_anon_p && mapping_file_p)
01917d
+	{
01917d
+	  /* This is a special situation.  It can happen when we see a
01917d
+	     mapping that is file-backed, but that contains anonymous
01917d
+	     pages.  */
01917d
+	  return ((filterflags & COREFILTER_ANON_PRIVATE) != 0
01917d
+		  || (filterflags & COREFILTER_MAPPED_PRIVATE) != 0);
01917d
+	}
01917d
+      else if (mapping_anon_p)
01917d
+	return (filterflags & COREFILTER_ANON_PRIVATE) != 0;
01917d
+      else
01917d
+	return (filterflags & COREFILTER_MAPPED_PRIVATE) != 0;
01917d
+    }
01917d
+  else
01917d
+    {
01917d
+      if (mapping_anon_p && mapping_file_p)
01917d
+	{
01917d
+	  /* This is a special situation.  It can happen when we see a
01917d
+	     mapping that is file-backed, but that contains anonymous
01917d
+	     pages.  */
01917d
+	  return ((filterflags & COREFILTER_ANON_SHARED) != 0
01917d
+		  || (filterflags & COREFILTER_MAPPED_SHARED) != 0);
01917d
+	}
01917d
+      else if (mapping_anon_p)
01917d
+	return (filterflags & COREFILTER_ANON_SHARED) != 0;
01917d
+      else
01917d
+	return (filterflags & COREFILTER_MAPPED_SHARED) != 0;
01917d
+    }
01917d
+}
01917d
+
01917d
 /* Implement the "info proc" command.  */
01917d
 
01917d
 static void
01917d
@@ -676,48 +993,97 @@
01917d
 				void *obfd)
01917d
 {
01917d
   char mapsfilename[100];
01917d
-  gdb_byte *data;
01917d
+  char coredumpfilter_name[100];
01917d
+  char *data, *coredumpfilterdata;
01917d
+  pid_t pid;
01917d
+  /* Default dump behavior of coredump_filter (0x33), according to
01917d
+     Documentation/filesystems/proc.txt from the Linux kernel
01917d
+     tree.  */
01917d
+  unsigned int filterflags = (COREFILTER_ANON_PRIVATE
01917d
+			      | COREFILTER_ANON_SHARED
01917d
+			      | COREFILTER_ELF_HEADERS
01917d
+			      | COREFILTER_HUGETLB_PRIVATE);
01917d
 
01917d
   /* We need to know the real target PID to access /proc.  */
01917d
   if (current_inferior ()->fake_pid_p)
01917d
     return 1;
01917d
 
01917d
-  xsnprintf (mapsfilename, sizeof mapsfilename,
01917d
-	     "/proc/%d/smaps", current_inferior ()->pid);
01917d
+  pid = current_inferior ()->pid;
01917d
+
01917d
+  if (use_coredump_filter)
01917d
+    {
01917d
+      xsnprintf (coredumpfilter_name, sizeof (coredumpfilter_name),
01917d
+		 "/proc/%d/coredump_filter", pid);
01917d
+      coredumpfilterdata = target_fileio_read_stralloc (coredumpfilter_name);
01917d
+      if (coredumpfilterdata != NULL)
01917d
+	{
01917d
+	  sscanf (coredumpfilterdata, "%x", &filterflags);
01917d
+	  xfree (coredumpfilterdata);
01917d
+	}
01917d
+    }
01917d
+
01917d
+  xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/smaps", pid);
01917d
   data = target_fileio_read_stralloc (mapsfilename);
01917d
   if (data == NULL)
01917d
     {
01917d
       /* Older Linux kernels did not support /proc/PID/smaps.  */
01917d
-      xsnprintf (mapsfilename, sizeof mapsfilename,
01917d
-		 "/proc/%d/maps", current_inferior ()->pid);
01917d
+      xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/maps", pid);
01917d
       data = target_fileio_read_stralloc (mapsfilename);
01917d
     }
01917d
-  if (data)
01917d
+
01917d
+  if (data != NULL)
01917d
     {
01917d
       struct cleanup *cleanup = make_cleanup (xfree, data);
01917d
-      char *line;
01917d
+      char *line, *t;
01917d
 
01917d
-      line = strtok (data, "\n");
01917d
-      while (line)
01917d
+      line = strtok_r (data, "\n", &t);
01917d
+      while (line != NULL)
01917d
 	{
01917d
 	  ULONGEST addr, endaddr, offset, inode;
01917d
 	  const char *permissions, *device, *filename;
01917d
+	  struct smaps_vmflags v;
01917d
 	  size_t permissions_len, device_len;
01917d
-	  int read, write, exec;
01917d
-	  int modified = 0, has_anonymous = 0;
01917d
+	  int read, write, exec, private;
01917d
+	  int has_anonymous = 0;
01917d
+	  int should_dump_p = 0;
01917d
+	  int mapping_anon_p;
01917d
+	  int mapping_file_p;
01917d
 
01917d
+	  memset (&v, 0, sizeof (v));
01917d
 	  read_mapping (line, &addr, &endaddr, &permissions, &permissions_len,
01917d
 			&offset, &device, &device_len, &inode, &filename);
01917d
+	  mapping_anon_p = mapping_is_anonymous_p (filename);
01917d
+	  /* If the mapping is not anonymous, then we can consider it
01917d
+	     to be file-backed.  These two states (anonymous or
01917d
+	     file-backed) seem to be exclusive, but they can actually
01917d
+	     coexist.  For example, if a file-backed mapping has
01917d
+	     "Anonymous:" pages (see more below), then the Linux
01917d
+	     kernel will dump this mapping when the user specified
01917d
+	     that she only wants anonymous mappings in the corefile
01917d
+	     (*even* when she explicitly disabled the dumping of
01917d
+	     file-backed mappings).  */
01917d
+	  mapping_file_p = !mapping_anon_p;
01917d
 
01917d
 	  /* Decode permissions.  */
01917d
 	  read = (memchr (permissions, 'r', permissions_len) != 0);
01917d
 	  write = (memchr (permissions, 'w', permissions_len) != 0);
01917d
 	  exec = (memchr (permissions, 'x', permissions_len) != 0);
01917d
-
01917d
-	  /* Try to detect if region was modified by parsing smaps counters.  */
01917d
-	  for (line = strtok (NULL, "\n");
01917d
-	       line && line[0] >= 'A' && line[0] <= 'Z';
01917d
-	       line = strtok (NULL, "\n"))
01917d
+	  /* 'private' here actually means VM_MAYSHARE, and not
01917d
+	     VM_SHARED.  In order to know if a mapping is really
01917d
+	     private or not, we must check the flag "sh" in the
01917d
+	     VmFlags field.  This is done by decode_vmflags.  However,
01917d
+	     if we are using a Linux kernel released before the commit
01917d
+	     834f82e2aa9a8ede94b17b656329f850c1471514 (3.10), we will
01917d
+	     not have the VmFlags there.  In this case, there is
01917d
+	     really no way to know if we are dealing with VM_SHARED,
01917d
+	     so we just assume that VM_MAYSHARE is enough.  */
01917d
+	  private = memchr (permissions, 'p', permissions_len) != 0;
01917d
+
01917d
+	  /* Try to detect if region should be dumped by parsing smaps
01917d
+	     counters.  */
01917d
+	  for (line = strtok_r (NULL, "\n", &t);
01917d
+	       line != NULL && line[0] >= 'A' && line[0] <= 'Z';
01917d
+	       line = strtok_r (NULL, "\n", &t))
01917d
 	    {
01917d
 	      char keyword[64 + 1];
01917d
 
01917d
@@ -726,11 +1092,17 @@
01917d
 		  warning (_("Error parsing {s,}maps file '%s'"), mapsfilename);
01917d
 		  break;
01917d
 		}
01917d
+
01917d
 	      if (strcmp (keyword, "Anonymous:") == 0)
01917d
-		has_anonymous = 1;
01917d
-	      if (strcmp (keyword, "Shared_Dirty:") == 0
01917d
-		  || strcmp (keyword, "Private_Dirty:") == 0
01917d
-		  || strcmp (keyword, "Swap:") == 0
01917d
+		{
01917d
+		  /* Older Linux kernels did not support the
01917d
+		     "Anonymous:" counter.  Check it here.  */
01917d
+		  has_anonymous = 1;
01917d
+		}
01917d
+	      else if (strcmp (keyword, "VmFlags:") == 0)
01917d
+		decode_vmflags (line, &v);
01917d
+
01917d
+	      if (strcmp (keyword, "AnonHugePages:") == 0
01917d
 		  || strcmp (keyword, "Anonymous:") == 0)
01917d
 		{
01917d
 		  unsigned long number;
01917d
@@ -741,19 +1113,46 @@
01917d
 			       mapsfilename);
01917d
 		      break;
01917d
 		    }
01917d
-		  if (number != 0)
01917d
-		    modified = 1;
01917d
+		  if (number > 0)
01917d
+		    {
01917d
+		      /* Even if we are dealing with a file-backed
01917d
+			 mapping, if it contains anonymous pages we
01917d
+			 consider it to be *also* an anonymous
01917d
+			 mapping, because this is what the Linux
01917d
+			 kernel does:
01917d
+
01917d
+			 // Dump segments that have been written to.
01917d
+			 if (vma->anon_vma && FILTER(ANON_PRIVATE))
01917d
+			 	goto whole;
01917d
+
01917d
+			 Note that if the mapping is already marked as
01917d
+			 file-backed (i.e., mapping_file_p is
01917d
+			 non-zero), then this is a special case, and
01917d
+			 this mapping will be dumped either when the
01917d
+			 user wants to dump file-backed *or* anonymous
01917d
+			 mappings.  */
01917d
+		      mapping_anon_p = 1;
01917d
+		    }
01917d
 		}
01917d
 	    }
01917d
 
01917d
-	  /* Older Linux kernels did not support the "Anonymous:" counter.
01917d
-	     If it is missing, we can't be sure - dump all the pages.  */
01917d
-	  if (!has_anonymous)
01917d
-	    modified = 1;
01917d
+	  if (has_anonymous)
01917d
+	    should_dump_p = dump_mapping_p (filterflags, &v, private,
01917d
+					    mapping_anon_p, mapping_file_p,
01917d
+					    filename);
01917d
+	  else
01917d
+	    {
01917d
+	      /* Older Linux kernels did not support the "Anonymous:" counter.
01917d
+		 If it is missing, we can't be sure - dump all the pages.  */
01917d
+	      should_dump_p = 1;
01917d
+	    }
01917d
 
01917d
 	  /* Invoke the callback function to create the corefile segment.  */
01917d
-	  func (addr, endaddr - addr, offset, inode,
01917d
-		read, write, exec, modified, filename, obfd);
01917d
+	  if (should_dump_p)
01917d
+	    func (addr, endaddr - addr, offset, inode,
01917d
+		  read, write, exec, 1, /* MODIFIED is true because we
01917d
+					   want to dump the mapping.  */
01917d
+		  filename, obfd);
01917d
 	}
01917d
 
01917d
       do_cleanups (cleanup);
01917d
@@ -1447,6 +1846,17 @@
01917d
 				      linux_collect_thread_registers);
01917d
 }
01917d
 
01917d
+/* Display whether the gcore command is using the
01917d
+   /proc/PID/coredump_filter file.  */
01917d
+
01917d
+static void
01917d
+show_use_coredump_filter (struct ui_file *file, int from_tty,
01917d
+			  struct cmd_list_element *c, const char *value)
01917d
+{
01917d
+  fprintf_filtered (file, _("Use of /proc/PID/coredump_filter file to generate"
01917d
+			    " corefiles is %s.\n"), value);
01917d
+}
01917d
+
01917d
 /* To be called from the various GDB_OSABI_LINUX handlers for the
01917d
    various GNU/Linux architectures and machine types.  */
01917d
 
01917d
@@ -1470,4 +1880,16 @@
01917d
 {
01917d
   linux_gdbarch_data_handle =
01917d
     gdbarch_data_register_post_init (init_linux_gdbarch_data);
01917d
+
01917d
+  add_setshow_boolean_cmd ("use-coredump-filter", class_files,
01917d
+			   &use_coredump_filter, _("\
01917d
+Set whether gcore should consider /proc/PID/coredump_filter."),
01917d
+			   _("\
01917d
+Show whether gcore should consider /proc/PID/coredump_filter."),
01917d
+			   _("\
01917d
+Use this command to set whether gcore should consider the contents\n\
01917d
+of /proc/PID/coredump_filter when generating the corefile.  For more information\n\
01917d
+about this file, refer to the manpage of core(5)."),
01917d
+			   NULL, show_use_coredump_filter,
01917d
+			   &setlist, &showlist);
01917d
 }
01917d
Index: gdb-7.6.1/gdb/testsuite/gdb.base/coredump-filter.c
01917d
===================================================================
01917d
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
01917d
+++ gdb-7.6.1/gdb/testsuite/gdb.base/coredump-filter.c	2015-11-27 22:31:14.002842001 +0100
01917d
@@ -0,0 +1,61 @@
01917d
+/* Copyright 2015 Free Software Foundation, Inc.
01917d
+
01917d
+   This file is part of GDB.
01917d
+
01917d
+   This program is free software; you can redistribute it and/or modify
01917d
+   it under the terms of the GNU General Public License as published by
01917d
+   the Free Software Foundation; either version 3 of the License, or
01917d
+   (at your option) any later version.
01917d
+
01917d
+   This program is distributed in the hope that it will be useful,
01917d
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
01917d
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
01917d
+   GNU General Public License for more details.
01917d
+
01917d
+   You should have received a copy of the GNU General Public License
01917d
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
01917d
+
01917d
+#define _GNU_SOURCE
01917d
+#include <stdlib.h>
01917d
+#include <assert.h>
01917d
+#include <unistd.h>
01917d
+#include <stdio.h>
01917d
+#include <sys/mman.h>
01917d
+#include <errno.h>
01917d
+#include <string.h>
01917d
+
01917d
+static void *
01917d
+do_mmap (void *addr, size_t size, int prot, int flags, int fd, off_t offset)
01917d
+{
01917d
+  void *ret = mmap (addr, size, prot, flags, fd, offset);
01917d
+
01917d
+  assert (ret != NULL);
01917d
+  return ret;
01917d
+}
01917d
+
01917d
+int
01917d
+main (int argc, char *argv[])
01917d
+{
01917d
+  const size_t size = 10;
01917d
+  const int default_prot = PROT_READ | PROT_WRITE;
01917d
+  char *private_anon, *shared_anon;
01917d
+  char *dont_dump;
01917d
+  int i;
01917d
+
01917d
+  private_anon = do_mmap (NULL, size, default_prot,
01917d
+			  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
01917d
+  memset (private_anon, 0x11, size);
01917d
+
01917d
+  shared_anon = do_mmap (NULL, size, default_prot,
01917d
+			 MAP_SHARED | MAP_ANONYMOUS, -1, 0);
01917d
+  memset (shared_anon, 0x22, size);
01917d
+
01917d
+  dont_dump = do_mmap (NULL, size, default_prot,
01917d
+		       MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
01917d
+  memset (dont_dump, 0x55, size);
01917d
+  i = madvise (dont_dump, size, MADV_DONTDUMP);
01917d
+  assert_perror (errno);
01917d
+  assert (i == 0);
01917d
+
01917d
+  return 0; /* break-here */
01917d
+}
01917d
Index: gdb-7.6.1/gdb/testsuite/gdb.base/coredump-filter.exp
01917d
===================================================================
01917d
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
01917d
+++ gdb-7.6.1/gdb/testsuite/gdb.base/coredump-filter.exp	2015-11-27 22:37:28.816872494 +0100
01917d
@@ -0,0 +1,265 @@
01917d
+# Copyright 2015 Free Software Foundation, Inc.
01917d
+
01917d
+# This program is free software; you can redistribute it and/or modify
01917d
+# it under the terms of the GNU General Public License as published by
01917d
+# the Free Software Foundation; either version 3 of the License, or
01917d
+# (at your option) any later version.
01917d
+#
01917d
+# This program is distributed in the hope that it will be useful,
01917d
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
01917d
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
01917d
+# GNU General Public License for more details.
01917d
+#
01917d
+# You should have received a copy of the GNU General Public License
01917d
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
01917d
+
01917d
+standard_testfile
01917d
+
01917d
+if { [prepare_for_testing "failed to prepare" $testfile $srcfile debug] } {
01917d
+    untested "could not compile test program"
01917d
+    return -1
01917d
+}
01917d
+
01917d
+if { ![runto_main] } {
01917d
+    untested "could not run to main"
01917d
+    return -1
01917d
+}
01917d
+
01917d
+gdb_breakpoint [gdb_get_line_number "break-here"]
01917d
+gdb_continue_to_breakpoint "break-here" ".* break-here .*"
01917d
+
01917d
+# Invoke "gcore".  CORE is the name of the core file to write.  TEST
01917d
+# is the name of the test case.  This will return 1 if the core file
01917d
+# was created, 0 otherwise.  If this fails to make a core file because
01917d
+# this configuration of gdb does not support making core files, it
01917d
+# will call "unsupported", not "fail".  However, if this fails to make
01917d
+# a core file for some other reason, then it will call "fail".
01917d
+
01917d
+proc gdb_gcore_cmd {core test} {
01917d
+    global gdb_prompt
01917d
+
01917d
+    set result 0
01917d
+    gdb_test_multiple "gcore $core" $test {
01917d
+	-re "Saved corefile .*\[\r\n\]+$gdb_prompt $" {
01917d
+	    pass $test
01917d
+	    set result 1
01917d
+	}
01917d
+	-re "(?:Can't create a corefile|Target does not support core file generation\\.)\[\r\n\]+$gdb_prompt $" {
01917d
+	    unsupported $test
01917d
+	}
01917d
+    }
01917d
+
01917d
+    return $result
01917d
+}
01917d
+
01917d
+# Load core file CORE.  TEST is the name of the test case.
01917d
+# This will record a pass/fail for loading the core file.
01917d
+# Returns:
01917d
+#  1 - core file is successfully loaded
01917d
+#  0 - core file loaded but has a non fatal error
01917d
+# -1 - core file failed to load
01917d
+
01917d
+proc gdb_core_cmd { core test } {
01917d
+    global gdb_prompt
01917d
+
01917d
+    gdb_test_multiple "core $core" "$test" {
01917d
+	-re "\\\[Thread debugging using \[^ \r\n\]* enabled\\\]\r\n" {
01917d
+	    exp_continue
01917d
+	}
01917d
+	-re " is not a core dump:.*\r\n$gdb_prompt $" {
01917d
+	    fail "$test (bad file format)"
01917d
+	    return -1
01917d
+	}
01917d
+	-re ": No such file or directory.*\r\n$gdb_prompt $" {
01917d
+	    fail "$test (file not found)"
01917d
+	    return -1
01917d
+	}
01917d
+	-re "Couldn't find .* registers in core file.*\r\n$gdb_prompt $" {
01917d
+	    fail "$test (incomplete note section)"
01917d
+	    return 0
01917d
+	}
01917d
+	-re "Core was generated by .*\r\n$gdb_prompt $" {
01917d
+	    pass "$test"
01917d
+	    return 1
01917d
+	}
01917d
+	-re ".*$gdb_prompt $" {
01917d
+	    fail "$test"
01917d
+	    return -1
01917d
+	}
01917d
+	timeout {
01917d
+	    fail "$test (timeout)"
01917d
+	    return -1
01917d
+	}
01917d
+    }
01917d
+    fail "unsupported output from 'core' command"
01917d
+    return -1
01917d
+}
01917d
+
01917d
+proc do_save_core { filter_flag core ipid } {
01917d
+    verbose -log "writing $filter_flag to /proc/$ipid/coredump_filter"
01917d
+
01917d
+    remote_exec target "sh -c \"echo $filter_flag > /proc/$ipid/coredump_filter\""
01917d
+
01917d
+    # Generate a corefile.
01917d
+    gdb_gcore_cmd "$core" "save corefile"
01917d
+}
01917d
+
01917d
+proc do_load_and_test_core { core var working_var working_value } {
01917d
+    global hex decimal addr
01917d
+
01917d
+    set core_loaded [gdb_core_cmd "$core" "load core"]
01917d
+    if { $core_loaded == -1 } {
01917d
+	fail "loading $core"
01917d
+	return
01917d
+    }
01917d
+
01917d
+    # Access the memory the addresses point to.
01917d
+    gdb_test "print/x *(char *) $addr($var)" "\(\\\$$decimal = <error: \)?Cannot access memory at address $hex\(>\)?" \
01917d
+	"printing $var when core is loaded (should not work)"
01917d
+    gdb_test "print/x *(char *) $addr($working_var)" " = $working_value.*" \
01917d
+	"print/x *$working_var ( = $working_value)"
01917d
+}
01917d
+
01917d
+# We do not do file-backed mappings in the test program, but it is
01917d
+# important to test this anyway.  One way of performing the test is to
01917d
+# load GDB with a corefile but without a binary, and then ask for the
01917d
+# disassemble of a function (i.e., the binary's .text section).  GDB
01917d
+# should fail in this case.  However, it must succeed if the binary is
01917d
+# provided along with the corefile.  This is what we test here.
01917d
+
01917d
+proc test_disasm { core address should_fail } {
01917d
+    global testfile hex
01917d
+
01917d
+    # Restart GDB without loading the binary.
01917d
+    with_test_prefix "no binary" {
01917d
+	gdb_exit
01917d
+	gdb_start
01917d
+
01917d
+	set core_loaded [gdb_core_cmd "$core" "load core"]
01917d
+	if { $core_loaded == -1 } {
01917d
+	    fail "loading $core"
01917d
+	    return
01917d
+	}
01917d
+
01917d
+	if { $should_fail == 1 } {
01917d
+	    gdb_test "x/i \$pc" "=> $hex:\tCannot access memory at address $hex" \
01917d
+		"disassemble function with corefile and without a binary"
01917d
+	} else {
01917d
+	    gdb_test "x/i \$pc" "=> $hex:\t\[^C\].*" \
01917d
+		"disassemble function with corefile and without a binary"
01917d
+	}
01917d
+    }
01917d
+
01917d
+    with_test_prefix "with binary" {
01917d
+	clean_restart $testfile
01917d
+
01917d
+	set core_loaded [gdb_core_cmd "$core" "load core"]
01917d
+	if { $core_loaded == -1 } {
01917d
+	    fail "loading $core"
01917d
+	    return
01917d
+	}
01917d
+
01917d
+	gdb_test "disassemble $address" "Dump of assembler code for function.*" \
01917d
+	    "disassemble function with corefile and with a binary"
01917d
+    }
01917d
+}
01917d
+
01917d
+set non_private_anon_core [standard_output_file non-private-anon.gcore]
01917d
+set non_shared_anon_core [standard_output_file non-shared-anon.gcore]
01917d
+# A corefile without {private,shared} {anonymous,file-backed} pages
01917d
+set non_private_shared_anon_file_core [standard_output_file non-private-shared-anon-file.gcore]
01917d
+set dont_dump_core [standard_output_file dont-dump.gcore]
01917d
+
01917d
+# We will generate a few corefiles.
01917d
+#
01917d
+# This list is composed by sub-lists, and their elements are (in
01917d
+# order):
01917d
+#
01917d
+# - name of the test
01917d
+# - hexadecimal value to be put in the /proc/PID/coredump_filter file
01917d
+# - name of the variable that contains the name of the corefile to be
01917d
+#   generated (including the initial $).
01917d
+# - name of the variable in the C source code that points to the
01917d
+#   memory mapping that will NOT be present in the corefile.
01917d
+# - name of a variable in the C source code that points to a memory
01917d
+#   mapping that WILL be present in the corefile
01917d
+# - corresponding value expected for the above variable
01917d
+#
01917d
+# This list refers to the corefiles generated by MAP_ANONYMOUS in the
01917d
+# test program.
01917d
+
01917d
+set all_anon_corefiles { { "non-Private-Anonymous" "0x7e" \
01917d
+			       $non_private_anon_core \
01917d
+			       "private_anon" \
01917d
+			       "shared_anon" "0x22" }
01917d
+    { "non-Shared-Anonymous" "0x7d" \
01917d
+	  $non_shared_anon_core "shared_anon" \
01917d
+	  "private_anon" "0x11" }
01917d
+    { "DoNotDump" "0x33" \
01917d
+	  $dont_dump_core "dont_dump" \
01917d
+	  "shared_anon" "0x22" } }
01917d
+
01917d
+# If corefile loading is not supported, we do not even try to run the
01917d
+# tests.
01917d
+set core_supported [gdb_gcore_cmd "$non_private_anon_core" "save a corefile"]
01917d
+if { !$core_supported } {
01917d
+    untested "corefile generation is not supported"
01917d
+    return -1
01917d
+}
01917d
+
01917d
+# Get the inferior's PID.
01917d
+set infpid ""
01917d
+gdb_test_multiple "info inferiors" "getting inferior pid" {
01917d
+    -re "process \($decimal\).*\r\n$gdb_prompt $" {
01917d
+	set infpid $expect_out(1,string)
01917d
+    }
01917d
+}
01917d
+
01917d
+# Get the main function's address.
01917d
+set main_addr ""
01917d
+gdb_test_multiple "print/x &main" "getting main's address" {
01917d
+    -re "$decimal = \($hex\)\r\n$gdb_prompt $" {
01917d
+	set main_addr $expect_out(1,string)
01917d
+    }
01917d
+}
01917d
+
01917d
+# Obtain the address of each variable that will be checked on each
01917d
+# case.
01917d
+foreach item $all_anon_corefiles {
01917d
+    foreach name [list [lindex $item 3] [lindex $item 4]] {
01917d
+	set test "print/x $name"
01917d
+	gdb_test_multiple $test $test {
01917d
+	    -re " = \($hex\)\r\n$gdb_prompt $" {
01917d
+		set addr($name) $expect_out(1,string)
01917d
+	    }
01917d
+	}
01917d
+    }
01917d
+}
01917d
+
01917d
+# Generate corefiles for the "anon" case.
01917d
+foreach item $all_anon_corefiles {
01917d
+    with_test_prefix "saving corefile for [lindex $item 0]" {
01917d
+	do_save_core [lindex $item 1] [subst [lindex $item 2]] $infpid
01917d
+    }
01917d
+}
01917d
+
01917d
+with_test_prefix "saving corefile for non-Private-Shared-Anon-File" {
01917d
+    do_save_core "0x60" $non_private_shared_anon_file_core $infpid
01917d
+}
01917d
+
01917d
+clean_restart $testfile
01917d
+
01917d
+foreach item $all_anon_corefiles {
01917d
+    with_test_prefix "loading and testing corefile for [lindex $item 0]" {
01917d
+	do_load_and_test_core [subst [lindex $item 2]] [lindex $item 3] \
01917d
+	    [lindex $item 4] [lindex $item 5]
01917d
+    }
01917d
+
01917d
+    with_test_prefix "disassembling function main for [lindex $item 0]" {
01917d
+	test_disasm [subst [lindex $item 2]] $main_addr 0
01917d
+    }
01917d
+}
01917d
+
01917d
+with_test_prefix "loading and testing corefile for non-Private-Shared-Anon-File" {
01917d
+    test_disasm $non_private_shared_anon_file_core $main_addr 1
01917d
+}