public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH v4 0/2] Improve corefile generation by using /proc/PID/coredump_filter (PR corefile/16902)
@ 2015-03-24 23:57 Sergio Durigan Junior
  2015-03-24 23:57 ` [PATCH 1/2] Implement support for checking /proc/PID/coredump_filter Sergio Durigan Junior
  2015-03-24 23:57 ` [PATCH 2/2] Documentation and testcase Sergio Durigan Junior
  0 siblings, 2 replies; 21+ messages in thread
From: Sergio Durigan Junior @ 2015-03-24 23:57 UTC (permalink / raw)
  To: GDB Patches; +Cc: Pedro Alves, Sergio Durigan Junior

Hello,

This is the fifth version of this patch series.  It basically includes
fixes to make GDB mimic the Linux kernel's behavior when dealing with
"file-backed mappings with anonymous pages".  As explained on:

  <https://sourceware.org/ml/gdb-patches/2015-03/msg00814.html>

in this situation, the Linux kernel dumps this "special" mapping both
when the user has requested file-backed or anonymous mappings to be
included in the corefile.  Now, GDB does the same thing.

The patch also extends the testcase in order to make sure that,
depending on the type of the corefile we are dealing with, we can or
cannot disassemble a section of the code without loading a binary.  The
approach I took for this is:

  - For corefiles that include the file-backed mappings, GDB should be
    able to disassemble.

  - For corefiles that do not include file-backed nor anonymous
    mappings, GDB should not be able to disassemble.

It was necessary to "relax" the second test because, as explained in the
message linked above, when you load a binary inside GDB its .text
segment contains anonymous pages, so if you ask for a corefile without
file-backed mappings (which, in theory, should exclude the .text
segment), GDB will still include the .text segment because this kind of
mapping is *also* considered an anonymous mapping (the Linux kernel does
the same thing here).

Other than that, the code is the same.  The documentation has been
approved already, but I am including a NEWS entry this time (I wasn't
sure if it was worth it or not, so I decided to go ahead and do it).

OK to apply?

Sergio Durigan Junior (2):
  Implement support for checking /proc/PID/coredump_filter
  Documentation and testcase

 gdb/doc/gdb.texinfo                        |  33 +++
 gdb/linux-tdep.c                           | 455 +++++++++++++++++++++++++++--
 gdb/testsuite/gdb.base/coredump-filter.c   |  61 ++++
 gdb/testsuite/gdb.base/coredump-filter.exp | 198 +++++++++++++
 4 files changed, 719 insertions(+), 28 deletions(-)
 create mode 100644 gdb/testsuite/gdb.base/coredump-filter.c
 create mode 100644 gdb/testsuite/gdb.base/coredump-filter.exp

-- 
1.9.3

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH 2/2] Documentation and testcase
  2015-03-24 23:57 [PATCH v4 0/2] Improve corefile generation by using /proc/PID/coredump_filter (PR corefile/16902) Sergio Durigan Junior
  2015-03-24 23:57 ` [PATCH 1/2] Implement support for checking /proc/PID/coredump_filter Sergio Durigan Junior
@ 2015-03-24 23:57 ` Sergio Durigan Junior
  2015-03-27  9:53   ` Pedro Alves
  1 sibling, 1 reply; 21+ messages in thread
From: Sergio Durigan Junior @ 2015-03-24 23:57 UTC (permalink / raw)
  To: GDB Patches; +Cc: Pedro Alves, Sergio Durigan Junior

This patch implements the testcase and the documentation bits for the
feature.  It will be merged with the first patch when everything is
approved, and I will push a single commit with the whole feature.

The testcase makes sure that, based on different types of corefiles,
we can or cannot access certain memory regions.  There is also a test
to make sure that we can or cannot disassemble the main function, also
depending on which pages a corefile contains.

The documentation, which has already been approved by Eli, explains
how to use the new feature.  However, I included a NEWS entry this
time, because I think it is worth mentioning this feature there.

Changes from v4:

  - Added tests to make sure that, when loading a corefile without a
    binary on GDB, disassembling the main function works or not
    depending on the type of corefile used.

gdb/ChangeLog:
2015-03-24  Sergio Durigan Junior  <sergiodj@redhat.com>

	* NEWS: Mention the possibility of using the
	'/proc/PID/coredump_filter' file when generating a corefile.
	Mention new command 'set use-coredump-filter'.

gdb/doc/ChangeLog:
2015-03-24  Sergio Durigan Junior  <sergiodj@redhat.com>

	PR corefiles/16092
	* gdb.texinfo (gcore): Mention new command 'set
	use-coredump-filter'.
	(set use-coredump-filter): Document new command.

gdb/testsuite/ChangeLog:
2015-03-24  Sergio Durigan Junior  <sergiodj@redhat.com>

	PR corefiles/16092
	* gdb.base/coredump-filter.c: New file.
	* gdb.base/coredump-filter.exp: Likewise.
---
 gdb/NEWS                                   |   8 ++
 gdb/doc/gdb.texinfo                        |  33 +++++
 gdb/testsuite/gdb.base/coredump-filter.c   |  61 +++++++++
 gdb/testsuite/gdb.base/coredump-filter.exp | 198 +++++++++++++++++++++++++++++
 4 files changed, 300 insertions(+)
 create mode 100644 gdb/testsuite/gdb.base/coredump-filter.c
 create mode 100644 gdb/testsuite/gdb.base/coredump-filter.exp

diff --git a/gdb/NEWS b/gdb/NEWS
index 3fa33c9..96fb85c 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,14 @@
 
 *** Changes since GDB 7.9
 
+* GDB now honors the content of the file /proc/PID/coredump_filter
+  (PID is the process ID) on GNU/Linux systems.  This file can be used
+  to specify the types of memory mappings that will be included in a
+  corefile.  For more information, please refer to the manual page of
+  "core(5)".  GDB also has a new command: "set use-coredump-filter
+  on|off".  It allows to set whether GDB will read the content of the
+  /proc/PID/coredump_filter file when generating a corefile.
+
 * GDB has two new commands: "set serial parity odd|even|none" and
   "show serial parity".  These allows to set or show parity for the
   remote serial I/O.
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index c03ecb0..f750ed5 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -10951,6 +10951,39 @@ specified, the file name defaults to @file{core.@var{pid}}, where
 
 Note that this command is implemented only for some systems (as of
 this writing, @sc{gnu}/Linux, FreeBSD, Solaris, and S390).
+
+On @sc{gnu}/Linux, this command can take into account the value of the
+file @file{/proc/@var{pid}/coredump_filter} when generating the core
+dump (@pxref{set use-coredump-filter}).
+
+@kindex set use-coredump-filter
+@anchor{set use-coredump-filter}
+@item set use-coredump-filter on
+@itemx set use-coredump-filter off
+Enable or disable the use of the file
+@file{/proc/@var{pid}/coredump_filter} when generating core dump
+files.  This file is used by the Linux kernel to decide what types of
+memory mappings will be dumped or ignored when generating a core dump
+file.  @var{pid} is the process ID of a currently running process.
+
+To make use of this feature, you have to write in the
+@file{/proc/@var{pid}/coredump_filter} file a value, in hexadecimal,
+which is a bit mask representing the memory mapping types.  If a bit
+is set in the bit mask, then the memory mappings of the corresponding
+types will be dumped; otherwise, they will be ignored.  This
+configuration is inherited by child processes.  For more information
+about the bits that can be set in the
+@file{/proc/@var{pid}/coredump_filter} file, please refer to the
+manpage of @code{core(5)}.
+
+By default, this option is @code{on}.  If this option is turned
+@code{off}, @value{GDBN} does not read the @file{coredump_filter} file
+and instead uses the same default value as the Linux kernel in order
+to decide which pages will be dumped in the core dump file.  This
+value is currently @code{0x33}, which means that bits @code{0}
+(anonymous private mappings), @code{1} (anonymous shared mappings),
+@code{4} (ELF headers) and @code{5} (private huge pages) are active.
+This will cause these memory mappings to be dumped automatically.
 @end table
 
 @node Character Sets
diff --git a/gdb/testsuite/gdb.base/coredump-filter.c b/gdb/testsuite/gdb.base/coredump-filter.c
new file mode 100644
index 0000000..192c469
--- /dev/null
+++ b/gdb/testsuite/gdb.base/coredump-filter.c
@@ -0,0 +1,61 @@
+/* Copyright 2015 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/>.  */
+
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <assert.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <string.h>
+
+static void *
+do_mmap (void *addr, size_t size, int prot, int flags, int fd, off_t offset)
+{
+  void *ret = mmap (addr, size, prot, flags, fd, offset);
+
+  assert (ret != NULL);
+  return ret;
+}
+
+int
+main (int argc, char *argv[])
+{
+  const size_t size = 10;
+  const int default_prot = PROT_READ | PROT_WRITE;
+  char *private_anon, *shared_anon;
+  char *dont_dump;
+  int i;
+
+  private_anon = do_mmap (NULL, size, default_prot,
+			  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  memset (private_anon, 0x11, size);
+
+  shared_anon = do_mmap (NULL, size, default_prot,
+			 MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+  memset (shared_anon, 0x22, size);
+
+  dont_dump = do_mmap (NULL, size, default_prot,
+		       MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  memset (dont_dump, 0x55, size);
+  i = madvise (dont_dump, size, MADV_DONTDUMP);
+  assert_perror (errno);
+  assert (i == 0);
+
+  return 0; /* break-here */
+}
diff --git a/gdb/testsuite/gdb.base/coredump-filter.exp b/gdb/testsuite/gdb.base/coredump-filter.exp
new file mode 100644
index 0000000..f3203be
--- /dev/null
+++ b/gdb/testsuite/gdb.base/coredump-filter.exp
@@ -0,0 +1,198 @@
+# Copyright 2015 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/>.
+
+standard_testfile
+
+if { [prepare_for_testing "failed to prepare" $testfile $srcfile debug] } {
+    untested "could not compile test program"
+    return -1
+}
+
+if { ![runto_main] } {
+    untested "could not run to main"
+    return -1
+}
+
+gdb_breakpoint [gdb_get_line_number "break-here"]
+gdb_continue_to_breakpoint "break-here" ".* break-here .*"
+
+proc do_save_core { filter_flag core ipid } {
+    verbose -log "writing $filter_flag to /proc/$ipid/coredump_filter"
+
+    remote_exec target "sh -c \"echo $filter_flag > /proc/$ipid/coredump_filter\""
+
+    # Generate a corefile.
+    gdb_gcore_cmd "$core" "save corefile"
+}
+
+proc do_load_and_test_core { core var working_var working_value } {
+    global hex decimal addr
+
+    set core_loaded [gdb_core_cmd "$core" "load core"]
+    if { $core_loaded == -1 } {
+	fail "loading $core"
+	return
+    }
+
+    # Access the memory the addresses point to.
+    gdb_test "print/x *(char *) $addr($var)" "\(\\\$$decimal = <error: \)?Cannot access memory at address $hex\(>\)?" \
+	"printing $var when core is loaded (should not work)"
+    gdb_test "print/x *(char *) $addr($working_var)" " = $working_value.*" \
+	"print/x *$working_var ( = $working_value)"
+}
+
+# We do not do file-backed mappings in the test program, but it is
+# important to test this anyway.  One way of performing the test is to
+# load GDB with a corefile but without a binary, and then ask for the
+# disassemble of a function (i.e., the binary's .text section).  GDB
+# should fail in this case.  However, it must succeed if the binary is
+# provided along with the corefile.  This is what we test here.
+
+proc test_disasm { core address should_fail } {
+    global testfile hex
+
+    # Restart GDB without loading the binary.
+    with_test_prefix "no binary" {
+	gdb_exit
+	gdb_start
+
+	set core_loaded [gdb_core_cmd "$core" "load core"]
+	if { $core_loaded == -1 } {
+	    fail "loading $core"
+	    return
+	}
+
+	if { $should_fail == 1 } {
+	    gdb_test "x/i \$pc" "=> $hex:\tCannot access memory at address $hex" \
+		"disassemble function with corefile and without a binary"
+	} else {
+	    gdb_test "x/i \$pc" "=> $hex:\t\[^C\].*" \
+		"disassemble function with corefile and without a binary"
+	}
+    }
+
+    with_test_prefix "with binary" {
+	clean_restart $testfile
+
+	set core_loaded [gdb_core_cmd "$core" "load core"]
+	if { $core_loaded == -1 } {
+	    fail "loading $core"
+	    return
+	}
+
+	gdb_test "disassemble $address" "Dump of assembler code for function.*" \
+	    "disassemble function with corefile and with a binary"
+    }
+}
+
+set non_private_anon_core [standard_output_file non-private-anon.gcore]
+set non_shared_anon_core [standard_output_file non-shared-anon.gcore]
+# A corefile without {private,shared} {anonymous,file-backed} pages
+set non_private_shared_anon_file_core [standard_output_file non-private-shared-anon-file.gcore]
+set dont_dump_core [standard_output_file dont-dump.gcore]
+
+# We will generate a few corefiles.
+#
+# This list is composed by sub-lists, and their elements are (in
+# order):
+#
+# - name of the test
+# - hexadecimal value to be put in the /proc/PID/coredump_filter file
+# - name of the variable that contains the name of the corefile to be
+#   generated (including the initial $).
+# - name of the variable in the C source code that points to the
+#   memory mapping that will NOT be present in the corefile.
+# - name of a variable in the C source code that points to a memory
+#   mapping that WILL be present in the corefile
+# - corresponding value expected for the above variable
+#
+# This list refers to the corefiles generated by MAP_ANONYMOUS in the
+# test program.
+
+set all_anon_corefiles { { "non-Private-Anonymous" "0x7e" \
+			       $non_private_anon_core \
+			       "private_anon" \
+			       "shared_anon" "0x22" }
+    { "non-Shared-Anonymous" "0x7d" \
+	  $non_shared_anon_core "shared_anon" \
+	  "private_anon" "0x11" }
+    { "DoNotDump" "0x33" \
+	  $dont_dump_core "dont_dump" \
+	  "shared_anon" "0x22" } }
+
+# If corefile loading is not supported, we do not even try to run the
+# tests.
+set core_supported [gdb_gcore_cmd "$non_private_anon_core" "save a corefile"]
+if { !$core_supported } {
+    untested "corefile generation is not supported"
+    return -1
+}
+
+# Get the inferior's PID.
+set infpid ""
+gdb_test_multiple "info inferiors" "getting inferior pid" {
+    -re "process \($decimal\).*\r\n$gdb_prompt $" {
+	set infpid $expect_out(1,string)
+    }
+}
+
+# Get the main function's address.
+set main_addr ""
+gdb_test_multiple "print/x &main" "getting main's address" {
+    -re "$decimal = \($hex\)\r\n$gdb_prompt $" {
+	set main_addr $expect_out(1,string)
+    }
+}
+
+# Obtain the address of each variable that will be checked on each
+# case.
+foreach item $all_anon_corefiles {
+    foreach name [list [lindex $item 3] [lindex $item 4]] {
+	set test "print/x $name"
+	gdb_test_multiple $test $test {
+	    -re " = \($hex\)\r\n$gdb_prompt $" {
+		set addr($name) $expect_out(1,string)
+	    }
+	}
+    }
+}
+
+# Generate corefiles for the "anon" case.
+foreach item $all_anon_corefiles {
+    with_test_prefix "saving corefile for [lindex $item 0]" {
+	do_save_core [lindex $item 1] [subst [lindex $item 2]] $infpid
+    }
+}
+
+with_test_prefix "saving corefile for non-Private-Shared-Anon-File" {
+    do_save_core "0x60" $non_private_shared_anon_file_core $infpid
+}
+
+clean_restart $testfile
+
+foreach item $all_anon_corefiles {
+    with_test_prefix "loading and testing corefile for [lindex $item 0]" {
+	do_load_and_test_core [subst [lindex $item 2]] [lindex $item 3] \
+	    [lindex $item 4] [lindex $item 5]
+    }
+
+    with_test_prefix "disassembling function main for [lindex $item 0]" {
+	test_disasm [subst [lindex $item 2]] $main_addr 0
+    }
+}
+
+with_test_prefix "loading and testing corefile for non-Private-Shared-Anon-File" {
+    test_disasm $non_private_shared_anon_file_core $main_addr 1
+}
-- 
1.9.3

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH 1/2] Implement support for checking /proc/PID/coredump_filter
  2015-03-24 23:57 [PATCH v4 0/2] Improve corefile generation by using /proc/PID/coredump_filter (PR corefile/16902) Sergio Durigan Junior
@ 2015-03-24 23:57 ` Sergio Durigan Junior
  2015-03-27  9:53   ` Pedro Alves
  2015-03-24 23:57 ` [PATCH 2/2] Documentation and testcase Sergio Durigan Junior
  1 sibling, 1 reply; 21+ messages in thread
From: Sergio Durigan Junior @ 2015-03-24 23:57 UTC (permalink / raw)
  To: GDB Patches; +Cc: Pedro Alves, Sergio Durigan Junior

This patch, as the subject says, extends GDB so that it is able to use
the contents of the file /proc/PID/coredump_filter when generating a
corefile.  This file contains a bit mask that is a representation of
the different types of memory mappings in the Linux kernel; the user
can choose to dump or not dump a certain type of memory mapping by
enabling/disabling the respective bit in the bit mask.  Currently,
here is what is supported:

  bit 0  Dump anonymous private mappings.
  bit 1  Dump anonymous shared mappings.
  bit 2  Dump file-backed private mappings.
  bit 3  Dump file-backed shared mappings.
  bit 4 (since Linux 2.6.24)
         Dump ELF headers.
  bit 5 (since Linux 2.6.28)
         Dump private huge pages.
  bit 6 (since Linux 2.6.28)
         Dump shared huge pages.

(This table has been taken from core(5), but you can also read about it
on Documentation/filesystems/proc.txt inside the Linux kernel source
tree).

The default value for this file, used by the Linux kernel, is 0x33,
which means that bits 0, 1, 4 and 5 are enabled.  This is also the
default for GDB implemented in this patch, FWIW.

Well, reading the file is obviously trivial.  The hard part, mind you,
is how to determine the types of the memory mappings.  For that, I
extended the code of gdb/linux-tdep.c:linux_find_memory_regions_full and
made it rely *much more* on the information gathered from
/proc/<PID>/smaps.  This file contains a "verbose dump" of the
inferior's memory mappings, and we were not using as much information as
we could from it.  If you want to read more about this file, take a look
at the proc(5) manpage (I will also write a blog post soon about
everything I had to learn to get this patch done, and when I it is ready
I will post it here).

With Oleg Nesterov's help, we could improve the current algorithm for
determining whether a memory mapping is anonymous/file-backed,
private/shared.  GDB now also respects the MADV_DONTDUMP flag and does
not dump the memory mapping marked as so, and will always dump
"[vsyscall]" or "[vdso]" mappings (just like the Linux kernel).

In a nutshell, what the new code is doing is:

- If the mapping is associated to a file whose name ends with
  " (deleted)", or if the file is "/dev/zero", or if it is "/SYSV%08x"
  (shared memory), or if there is no file associated with it, or if
  the AnonHugePages: or the Anonymous: fields in the /proc/PID/smaps
  have contents, then GDB considers this mapping to be anonymous.
  There is a special case in this, though: if the memory mapping is a
  file-backed one, but *also* contains "Anonymous:" or
  "AnonHugePages:" pages, then GDB considers this mapping to be *both*
  anonymous and file-backed, just like the Linux kernel does.  What
  that means is simple: this mapping will be dumped if the user
  requested anonymous mappings *or* if the user requested file-backed
  mappings to be present in the corefile.

  It is worth mentioning that, from all those checks described above,
  the most fragile is the one to see if the file name ends with
  " (deleted)".  This does not necessarily mean that the mapping is
  anonymous, because the deleted file associated with the mapping may
  have been a hard link to another file, for example.  The Linux
  kernel checks to see if "i_nlink == 0", but GDB cannot easily do
  this check (as it has been discussed, GDB would need to run as root,
  and would need to check the contents of the /proc/PID/map_files/
  directory in order to determine whether the deleted was a hardlink
  or not).  Therefore, we made a compromise here, and we assume that
  if the file name ends with " (deleted)", then the mapping is indeed
  anonymous.  FWIW, this is something the Linux kernel could do
  better: expose this information in a more direct way.

- If we see the flag "sh" in the VmFlags: field (in /proc/PID/smaps),
  then certainly the memory mapping is shared (VM_SHARED).  If we have
  access to the VmFlags, and we don't see the "sh" there, then
  certainly the mapping is private.  However, older Linux kernels (see
  the code for more details) do not have the VmFlags field; in that
  case, we use another heuristic: if we see 'p' in the permission
  flags, then we assume that the mapping is private, even though the
  presence of the 's' flag there would mean VM_MAYSHARE, which means
  the mapping could still be private.  This should work OK enough,
  however.

Finally, it is worth mentioning that I added a new command, 'set
use-coredump-filter on/off'.  When it is 'on', it will read the
coredump_filter' file (if it exists) and use its value; otherwise, it
will use the default value mentioned above (0x33) to decide which memory
mappings to dump.

Changes from v4:

  - GDB is now handling the "file-backed mapping with anonymous pages"
    case just like the Linux kernel.

gdb/ChangeLog:
2015-03-24  Sergio Durigan Junior  <sergiodj@redhat.com>
	    Jan Kratochvil  <jan.kratochvil@redhat.com>
	    Oleg Nesterov  <oleg@redhat.com>

	PR corefiles/16092
	* linux-tdep.c: Include 'gdbcmd.h' and 'gdb_regex.h'.
	New enum identifying the various options of the coredump_filter
	file.
	(struct smaps_vmflags): New struct.
	(use_coredump_filter): New variable.
	(decode_vmflags): New function.
	(mapping_is_anonymous_p): Likewise.
	(dump_mapping_p): Likewise.
	(linux_find_memory_regions_full): New variables
	'coredumpfilter_name', 'coredumpfilterdata', 'pid', 'filterflags'.
	Removed variable 'modified'.  Read /proc/<PID>/smaps file; improve
	parsing of its information.  Implement memory mapping filtering
	based on its contents.
	(show_use_coredump_filter): New function.
	(_initialize_linux_tdep): New command 'set use-coredump-filter'.
---
 gdb/linux-tdep.c | 455 +++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 427 insertions(+), 28 deletions(-)

diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index ea0d4cd..4af1d01 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -35,9 +35,61 @@
 #include "observer.h"
 #include "objfiles.h"
 #include "infcall.h"
+#include "gdbcmd.h"
+#include "gdb_regex.h"
 
 #include <ctype.h>
 
+/* This enum represents the values that the user can choose when
+   informing the Linux kernel about which memory mappings will be
+   dumped in a corefile.  They are described in the file
+   Documentation/filesystems/proc.txt, inside the Linux kernel
+   tree.  */
+
+enum
+  {
+    COREFILTER_ANON_PRIVATE = 1 << 0,
+    COREFILTER_ANON_SHARED = 1 << 1,
+    COREFILTER_MAPPED_PRIVATE = 1 << 2,
+    COREFILTER_MAPPED_SHARED = 1 << 3,
+    COREFILTER_ELF_HEADERS = 1 << 4,
+    COREFILTER_HUGETLB_PRIVATE = 1 << 5,
+    COREFILTER_HUGETLB_SHARED = 1 << 6,
+  };
+
+/* This struct is used to map flags found in the "VmFlags:" field (in
+   the /proc/<PID>/smaps file).  */
+
+struct smaps_vmflags
+  {
+    /* Zero if this structure has not been initialized yet.  It
+       probably means that the Linux kernel being used does not emit
+       the "VmFlags:" field on "/proc/PID/smaps".  */
+
+    unsigned int initialized_p : 1;
+
+    /* Memory mapped I/O area (VM_IO, "io").  */
+
+    unsigned int io_page : 1;
+
+    /* Area uses huge TLB pages (VM_HUGETLB, "ht").  */
+
+    unsigned int uses_huge_tlb : 1;
+
+    /* Do not include this memory region on the coredump (VM_DONTDUMP, "dd").  */
+
+    unsigned int exclude_coredump : 1;
+
+    /* Is this a MAP_SHARED mapping (VM_SHARED, "sh").  */
+
+    unsigned int shared_mapping : 1;
+  };
+
+/* Whether to take the /proc/PID/coredump_filter into account when
+   generating a corefile.  */
+
+static int use_coredump_filter = 1;
+
 /* This enum represents the signals' numbers on a generic architecture
    running the Linux kernel.  The definition of "generic" comes from
    the file <include/uapi/asm-generic/signal.h>, from the Linux kernel
@@ -381,6 +433,248 @@ read_mapping (const char *line,
   *filename = p;
 }
 
+/* Helper function to decode the "VmFlags" field in /proc/PID/smaps.
+
+   This function was based on the documentation found on
+   <Documentation/filesystems/proc.txt>, on the Linux kernel.
+
+   Linux kernels before commit
+   834f82e2aa9a8ede94b17b656329f850c1471514 (3.10) do not have this
+   field on smaps.  */
+
+static void
+decode_vmflags (char *p, struct smaps_vmflags *v)
+{
+  char *saveptr;
+  const char *s;
+
+  v->initialized_p = 1;
+  p = skip_to_space (p);
+  p = skip_spaces (p);
+
+  for (s = strtok_r (p, " ", &saveptr);
+       s != NULL;
+       s = strtok_r (NULL, " ", &saveptr))
+    {
+      if (strcmp (s, "io") == 0)
+	v->io_page = 1;
+      else if (strcmp (s, "ht") == 0)
+	v->uses_huge_tlb = 1;
+      else if (strcmp (s, "dd") == 0)
+	v->exclude_coredump = 1;
+      else if (strcmp (s, "sh") == 0)
+	v->shared_mapping = 1;
+    }
+}
+
+/* Return 1 if the memory mapping is anonymous, 0 otherwise.
+
+   FILENAME is the name of the file present in the first line of the
+   memory mapping, in the "/proc/PID/smaps" output.  For example, if
+   the first line is:
+
+   7fd0ca877000-7fd0d0da0000 r--p 00000000 fd:02 2100770   /path/to/file
+
+   Then FILENAME will be "/path/to/file".  */
+
+static int
+mapping_is_anonymous_p (const char *filename)
+{
+  static regex_t dev_zero_regex, shmem_file_regex, file_deleted_regex;
+  static int init_regex_p = 0;
+
+  if (!init_regex_p)
+    {
+      struct cleanup *c = make_cleanup (null_cleanup, NULL);
+
+      /* Let's be pessimistic and assume there will be an error while
+	 compiling the regex'es.  */
+      init_regex_p = -1;
+
+      /* DEV_ZERO_REGEX matches "/dev/zero" filenames (with or
+	 without the "(deleted)" string in the end).  We know for
+	 sure, based on the Linux kernel code, that memory mappings
+	 whose associated filename is "/dev/zero" are guaranteed to be
+	 MAP_ANONYMOUS.  */
+      compile_rx_or_error (&dev_zero_regex, "^/dev/zero\\( (deleted)\\)\\?$",
+			   _("Could not compile regex to match /dev/zero "
+			     "filename"));
+      /* SHMEM_FILE_REGEX matches "/SYSV%08x" filenames (with or
+	 without the "(deleted)" string in the end).  These filenames
+	 refer to shared memory (shmem), and memory mappings
+	 associated with them are MAP_ANONYMOUS as well.  */
+      compile_rx_or_error (&shmem_file_regex,
+			   "^/\\?SYSV[0-9a-fA-F]\\{8\\}\\( (deleted)\\)\\?$",
+			   _("Could not compile regex to match shmem "
+			     "filenames"));
+      /* FILE_DELETED_REGEX is a heuristic we use to try to mimic the
+	 Linux kernel's 'n_link == 0' code, which is responsible to
+	 decide if it is dealing with a 'MAP_SHARED | MAP_ANONYMOUS'
+	 mapping.  In other words, if FILE_DELETED_REGEX matches, it
+	 does not necessarily mean that we are dealing with an
+	 anonymous shared mapping.  However, there is no easy way to
+	 detect this currently, so this is the best approximation we
+	 have.
+
+	 As a result, GDB will dump readonly pages of deleted
+	 executables when using the default value of coredump_filter
+	 (0x33), while the Linux kernel will not dump those pages.
+	 But we can live with that.  */
+      compile_rx_or_error (&file_deleted_regex, " (deleted)$",
+			   _("Could not compile regex to match "
+			     "'<file> (deleted)'"));
+      /* We will never release these regexes, so just discard the
+	 cleanups.  */
+      discard_cleanups (c);
+
+      /* If we reached this point, then everything succeeded.  */
+      init_regex_p = 1;
+    }
+
+  if (init_regex_p == -1)
+    {
+      const char deleted[] = " (deleted)";
+      size_t del_len = sizeof (deleted) - 1;
+      size_t filename_len = strlen (filename);
+
+      /* There was an error while compiling the regex'es above.  In
+	 order to try to give some reliable information to the caller,
+	 we just try to find the string " (deleted)" in the filename.
+	 If we managed to find it, then we assume the mapping is
+	 anonymous.  */
+      return (filename_len >= del_len
+	      && strcmp (filename + filename_len - del_len, deleted) == 0);
+    }
+
+  if (*filename == '\0'
+      || regexec (&dev_zero_regex, filename, 0, NULL, 0) == 0
+      || regexec (&shmem_file_regex, filename, 0, NULL, 0) == 0
+      || regexec (&file_deleted_regex, filename, 0, NULL, 0) == 0)
+    return 1;
+
+  return 0;
+}
+
+/* Return 0 if the memory mapping (which is related to FILTERFLAGS, V,
+   MAYBE_PRIVATE_P, and MAPPING_ANONYMOUS_P) should not be dumped, or
+   greater than 0 if it should.
+
+   In a nutshell, this is the logic that we follow in order to decide
+   if a mapping should be dumped or not.
+
+   - If the mapping is associated to a file whose name ends with
+     " (deleted)", or if the file is "/dev/zero", or if it is
+     "/SYSV%08x" (shared memory), or if there is no file associated
+     with it, or if the AnonHugePages: or the Anonymous: fields in the
+     /proc/PID/smaps have contents, then GDB considers this mapping to
+     be anonymous.  Otherwise, GDB considers this mapping to be a
+     file-backed mapping (because there will be a file associated with
+     it).
+ 
+     It is worth mentioning that, from all those checks described
+     above, the most fragile is the one to see if the file name ends
+     with " (deleted)".  This does not necessarily mean that the
+     mapping is anonymous, because the deleted file associated with
+     the mapping may have been a hard link to another file, for
+     example.  The Linux kernel checks to see if "i_nlink == 0", but
+     GDB cannot easily (and normally) do this check (iff running as
+     root, it could find the mapping in /proc/PID/map_files/ and
+     determine whether there still are other hard links to the
+     inode/file).  Therefore, we made a compromise here, and we assume
+     that if the file name ends with " (deleted)", then the mapping is
+     indeed anonymous.  FWIW, this is something the Linux kernel could
+     do better: expose this information in a more direct way.
+ 
+   - If we see the flag "sh" in the "VmFlags:" field (in
+     /proc/PID/smaps), then certainly the memory mapping is shared
+     (VM_SHARED).  If we have access to the VmFlags, and we don't see
+     the "sh" there, then certainly the mapping is private.  However,
+     Linux kernels before commit
+     834f82e2aa9a8ede94b17b656329f850c1471514 (3.10) do not have the
+     "VmFlags:" field; in that case, we use another heuristic: if we
+     see 'p' in the permission flags, then we assume that the mapping
+     is private, even though the presence of the 's' flag there would
+     mean VM_MAYSHARE, which means the mapping could still be private.
+     This should work OK enough, however.  */
+
+static int
+dump_mapping_p (unsigned int filterflags, const struct smaps_vmflags *v,
+		int maybe_private_p, int mapping_anon_p, int mapping_file_p,
+		const char *filename)
+{
+  /* Initially, we trust in what we received from our caller.  This
+     value may not be very precise (i.e., it was probably gathered
+     from the permission line in the /proc/PID/smaps list, which
+     actually refers to VM_MAYSHARE, and not VM_SHARED), but it is
+     what we have until we take a look at the "VmFlags:" field
+     (assuming that the version of the Linux kernel being used
+     supports it, of course).  */
+  int private_p = maybe_private_p;
+
+  /* We always dump vDSO and vsyscall mappings, because it's likely that
+     there'll be no file to read the contents from at core load time.
+     The kernel does the same.  */
+  if (strcmp ("[vdso]", filename) == 0
+      || strcmp ("[vsyscall]", filename) == 0)
+    return 1;
+
+  if (v->initialized_p)
+    {
+      /* We never dump I/O mappings.  */
+      if (v->io_page)
+	return 0;
+
+      /* Check if we should exclude this mapping.  */
+      if (v->exclude_coredump)
+	return 0;
+
+      /* Update our notion of whether this mapping is shared or
+	 private based on a trustworthy value.  */
+      private_p = !v->shared_mapping;
+
+      /* HugeTLB checking.  */
+      if (v->uses_huge_tlb)
+	{
+	  if ((private_p && (filterflags & COREFILTER_HUGETLB_PRIVATE))
+	      || (!private_p && (filterflags & COREFILTER_HUGETLB_SHARED)))
+	    return 1;
+
+	  return 0;
+	}
+    }
+
+  if (private_p)
+    {
+      if (mapping_anon_p && mapping_file_p)
+	{
+	  /* This is a special situation.  It can happen when we see a
+	     mapping that is file-backed, but that contains anonymous
+	     pages.  */
+	  return ((filterflags & COREFILTER_ANON_PRIVATE) != 0
+		  || (filterflags & COREFILTER_MAPPED_PRIVATE) != 0);
+	}
+      else if (mapping_anon_p)
+	return (filterflags & COREFILTER_ANON_PRIVATE) != 0;
+      else
+	return (filterflags & COREFILTER_MAPPED_PRIVATE) != 0;
+    }
+  else
+    {
+      if (mapping_anon_p && mapping_file_p)
+	{
+	  /* This is a special situation.  It can happen when we see a
+	     mapping that is file-backed, but that contains anonymous
+	     pages.  */
+	  return ((filterflags & COREFILTER_ANON_SHARED) != 0
+		  || (filterflags & COREFILTER_MAPPED_SHARED) != 0);
+	}
+      else if (mapping_anon_p)
+	return (filterflags & COREFILTER_ANON_SHARED) != 0;
+      else
+	return (filterflags & COREFILTER_MAPPED_SHARED) != 0;
+    }
+}
+
 /* Implement the "info proc" command.  */
 
 static void
@@ -819,48 +1113,97 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
 				void *obfd)
 {
   char mapsfilename[100];
-  char *data;
+  char coredumpfilter_name[100];
+  char *data, *coredumpfilterdata;
+  pid_t pid;
+  /* Default dump behavior of coredump_filter (0x33), according to
+     Documentation/filesystems/proc.txt from the Linux kernel
+     tree.  */
+  unsigned int filterflags = (COREFILTER_ANON_PRIVATE
+			      | COREFILTER_ANON_SHARED
+			      | COREFILTER_ELF_HEADERS
+			      | COREFILTER_HUGETLB_PRIVATE);
 
   /* We need to know the real target PID to access /proc.  */
   if (current_inferior ()->fake_pid_p)
     return 1;
 
-  xsnprintf (mapsfilename, sizeof mapsfilename,
-	     "/proc/%d/smaps", current_inferior ()->pid);
+  pid = current_inferior ()->pid;
+
+  if (use_coredump_filter)
+    {
+      xsnprintf (coredumpfilter_name, sizeof (coredumpfilter_name),
+		 "/proc/%d/coredump_filter", pid);
+      coredumpfilterdata = target_fileio_read_stralloc (coredumpfilter_name);
+      if (coredumpfilterdata != NULL)
+	{
+	  sscanf (coredumpfilterdata, "%x", &filterflags);
+	  xfree (coredumpfilterdata);
+	}
+    }
+
+  xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/smaps", pid);
   data = target_fileio_read_stralloc (mapsfilename);
   if (data == NULL)
     {
       /* Older Linux kernels did not support /proc/PID/smaps.  */
-      xsnprintf (mapsfilename, sizeof mapsfilename,
-		 "/proc/%d/maps", current_inferior ()->pid);
+      xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/maps", pid);
       data = target_fileio_read_stralloc (mapsfilename);
     }
-  if (data)
+
+  if (data != NULL)
     {
       struct cleanup *cleanup = make_cleanup (xfree, data);
-      char *line;
+      char *line, *t;
 
-      line = strtok (data, "\n");
-      while (line)
+      line = strtok_r (data, "\n", &t);
+      while (line != NULL)
 	{
 	  ULONGEST addr, endaddr, offset, inode;
 	  const char *permissions, *device, *filename;
+	  struct smaps_vmflags v;
 	  size_t permissions_len, device_len;
-	  int read, write, exec;
-	  int modified = 0, has_anonymous = 0;
+	  int read, write, exec, private;
+	  int has_anonymous = 0;
+	  int should_dump_p = 0;
+	  int mapping_anon_p;
+	  int mapping_file_p;
 
+	  memset (&v, 0, sizeof (v));
 	  read_mapping (line, &addr, &endaddr, &permissions, &permissions_len,
 			&offset, &device, &device_len, &inode, &filename);
+	  mapping_anon_p = mapping_is_anonymous_p (filename);
+	  /* If the mapping is not anonymous, then we can consider it
+	     to be file-backed.  These two states (anonymous or
+	     file-backed) seem to be exclusive, but they can actually
+	     coexist.  For example, if a file-backed mapping has
+	     "Anonymous:" pages (see more below), then the Linux
+	     kernel will dump this mapping when the user specified
+	     that she only wants anonymous mappings in the corefile
+	     (*even* when she explicitly disabled the dumping of
+	     file-backed mappings).  */
+	  mapping_file_p = !mapping_anon_p;
 
 	  /* Decode permissions.  */
 	  read = (memchr (permissions, 'r', permissions_len) != 0);
 	  write = (memchr (permissions, 'w', permissions_len) != 0);
 	  exec = (memchr (permissions, 'x', permissions_len) != 0);
-
-	  /* Try to detect if region was modified by parsing smaps counters.  */
-	  for (line = strtok (NULL, "\n");
-	       line && line[0] >= 'A' && line[0] <= 'Z';
-	       line = strtok (NULL, "\n"))
+	  /* 'private' here actually means VM_MAYSHARE, and not
+	     VM_SHARED.  In order to know if a mapping is really
+	     private or not, we must check the flag "sh" in the
+	     VmFlags field.  This is done by decode_vmflags.  However,
+	     if we are using a Linux kernel released before the commit
+	     834f82e2aa9a8ede94b17b656329f850c1471514 (3.10), we will
+	     not have the VmFlags there.  In this case, there is
+	     really no way to know if we are dealing with VM_SHARED,
+	     so we just assume that VM_MAYSHARE is enough.  */
+	  private = memchr (permissions, 'p', permissions_len) != 0;
+
+	  /* Try to detect if region should be dumped by parsing smaps
+	     counters.  */
+	  for (line = strtok_r (NULL, "\n", &t);
+	       line != NULL && line[0] >= 'A' && line[0] <= 'Z';
+	       line = strtok_r (NULL, "\n", &t))
 	    {
 	      char keyword[64 + 1];
 
@@ -869,11 +1212,17 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
 		  warning (_("Error parsing {s,}maps file '%s'"), mapsfilename);
 		  break;
 		}
+
 	      if (strcmp (keyword, "Anonymous:") == 0)
-		has_anonymous = 1;
-	      if (strcmp (keyword, "Shared_Dirty:") == 0
-		  || strcmp (keyword, "Private_Dirty:") == 0
-		  || strcmp (keyword, "Swap:") == 0
+		{
+		  /* Older Linux kernels did not support the
+		     "Anonymous:" counter.  Check it here.  */
+		  has_anonymous = 1;
+		}
+	      else if (strcmp (keyword, "VmFlags:") == 0)
+		decode_vmflags (line, &v);
+
+	      if (strcmp (keyword, "AnonHugePages:") == 0
 		  || strcmp (keyword, "Anonymous:") == 0)
 		{
 		  unsigned long number;
@@ -884,19 +1233,46 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
 			       mapsfilename);
 		      break;
 		    }
-		  if (number != 0)
-		    modified = 1;
+		  if (number > 0)
+		    {
+		      /* Even if we are dealing with a file-backed
+			 mapping, if it contains anonymous pages we
+			 consider it to be *also* an anonymous
+			 mapping, because this is what the Linux
+			 kernel does:
+
+			 // Dump segments that have been written to.
+			 if (vma->anon_vma && FILTER(ANON_PRIVATE))
+			 	goto whole;
+
+			 Note that if the mapping is already marked as
+			 file-backed (i.e., mapping_file_p is
+			 non-zero), then this is a special case, and
+			 this mapping will be dumped either when the
+			 user wants to dump file-backed *or* anonymous
+			 mappings.  */
+		      mapping_anon_p = 1;
+		    }
 		}
 	    }
 
-	  /* Older Linux kernels did not support the "Anonymous:" counter.
-	     If it is missing, we can't be sure - dump all the pages.  */
-	  if (!has_anonymous)
-	    modified = 1;
+	  if (has_anonymous)
+	    should_dump_p = dump_mapping_p (filterflags, &v, private,
+					    mapping_anon_p, mapping_file_p,
+					    filename);
+	  else
+	    {
+	      /* Older Linux kernels did not support the "Anonymous:" counter.
+		 If it is missing, we can't be sure - dump all the pages.  */
+	      should_dump_p = 1;
+	    }
 
 	  /* Invoke the callback function to create the corefile segment.  */
-	  func (addr, endaddr - addr, offset, inode,
-		read, write, exec, modified, filename, obfd);
+	  if (should_dump_p)
+	    func (addr, endaddr - addr, offset, inode,
+		  read, write, exec, 1, /* MODIFIED is true because we
+					   want to dump the mapping.  */
+		  filename, obfd);
 	}
 
       do_cleanups (cleanup);
@@ -1972,6 +2348,17 @@ linux_infcall_mmap (CORE_ADDR size, unsigned prot)
   return retval;
 }
 
+/* Display whether the gcore command is using the
+   /proc/PID/coredump_filter file.  */
+
+static void
+show_use_coredump_filter (struct ui_file *file, int from_tty,
+			  struct cmd_list_element *c, const char *value)
+{
+  fprintf_filtered (file, _("Use of /proc/PID/coredump_filter file to generate"
+			    " corefiles is %s.\n"), value);
+}
+
 /* To be called from the various GDB_OSABI_LINUX handlers for the
    various GNU/Linux architectures and machine types.  */
 
@@ -2008,4 +2395,16 @@ _initialize_linux_tdep (void)
   /* Observers used to invalidate the cache when needed.  */
   observer_attach_inferior_exit (invalidate_linux_cache_inf);
   observer_attach_inferior_appeared (invalidate_linux_cache_inf);
+
+  add_setshow_boolean_cmd ("use-coredump-filter", class_files,
+			   &use_coredump_filter, _("\
+Set whether gcore should consider /proc/PID/coredump_filter."),
+			   _("\
+Show whether gcore should consider /proc/PID/coredump_filter."),
+			   _("\
+Use this command to set whether gcore should consider the contents\n\
+of /proc/PID/coredump_filter when generating the corefile.  For more information\n\
+about this file, refer to the manpage of core(5)."),
+			   NULL, show_use_coredump_filter,
+			   &setlist, &showlist);
 }
-- 
1.9.3

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 2/2] Documentation and testcase
  2015-03-24 23:57 ` [PATCH 2/2] Documentation and testcase Sergio Durigan Junior
@ 2015-03-27  9:53   ` Pedro Alves
  0 siblings, 0 replies; 21+ messages in thread
From: Pedro Alves @ 2015-03-27  9:53 UTC (permalink / raw)
  To: Sergio Durigan Junior, GDB Patches

OK.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/2] Implement support for checking /proc/PID/coredump_filter
  2015-03-24 23:57 ` [PATCH 1/2] Implement support for checking /proc/PID/coredump_filter Sergio Durigan Junior
@ 2015-03-27  9:53   ` Pedro Alves
  2015-03-31 23:40     ` Sergio Durigan Junior
  0 siblings, 1 reply; 21+ messages in thread
From: Pedro Alves @ 2015-03-27  9:53 UTC (permalink / raw)
  To: Sergio Durigan Junior, GDB Patches

OK.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/2] Implement support for checking /proc/PID/coredump_filter
  2015-03-27  9:53   ` Pedro Alves
@ 2015-03-31 23:40     ` Sergio Durigan Junior
  2015-04-08 14:08       ` Build failure following: Implement support for checking /proc/PID/coredump_filter commit Pierre Muller
  0 siblings, 1 reply; 21+ messages in thread
From: Sergio Durigan Junior @ 2015-03-31 23:40 UTC (permalink / raw)
  To: Pedro Alves; +Cc: GDB Patches

On Friday, March 27 2015, Pedro Alves wrote:

> OK.

Thanks, pushed both patches:

  <https://sourceware.org/ml/gdb-cvs/2015-03/msg00275.html>
  df8411da087dc05481926f4c4a82deabc5bc3859

-- 
Sergio
GPG key ID: 0x65FC5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Build failure following: Implement support for checking /proc/PID/coredump_filter commit
  2015-03-31 23:40     ` Sergio Durigan Junior
@ 2015-04-08 14:08       ` Pierre Muller
  2015-04-08 14:43         ` Pedro Alves
  0 siblings, 1 reply; 21+ messages in thread
From: Pierre Muller @ 2015-04-08 14:08 UTC (permalink / raw)
  To: 'Sergio Durigan Junior', 'Pedro Alves'
  Cc: 'GDB Patches'

  Hi all,

The approved patch "Implement support for checking /proc/PID/coredump_filter
commit"
committed April 1. 2015:
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=commitdiff;h=df84
11da087dc05481926f4c4a82deabc5bc3859

breaks mingw64 with --enable-targets=all configure option.

The reason is the introduction of strtok_r function in gdb/linux-tdep.c
source.
This function is not present in my version of x86_64-w64-mingw32
cross-system (on a Cygwin system).

The function is found in string.h header on native Cygwin, but inside a
conditional:

/usr/include/string.h-46-#if __POSIX_VISIBLE
/usr/include/string.h:47:char   *_EXFUN(strtok_r,(char *__restrict, const
char *__restrict, char **__restrict));
/usr/include/string.h-48-#endif

I did not find any explicit inclusion of string header inside linux-tdep.c
source...

There is a workaround in mingw64 pthread.h:
/usr/x86_64-w64-mingw32/sys-root/mingw/include/pthread.h:455:#ifndef
strtok_r
/usr/x86_64-w64-mingw32/sys-root/mingw/include/pthread.h:456:#define
strtok_r(__s, __sep, __last)  (*(__last) = strtok((__s), (__sep)))
/usr/x86_64-w64-mingw32/sys-root/mingw/include/pthread.h-457-#endif

Does this suggest that strtok_r is not a required string.h function?
If yes, should this function be tested by configure...

Or maybe we should use the gnulib version of strtok_r?
I don't really know how to do this, but if someone can tell me,
I can test the patch.


Pierre Muller



> -----Message d'origine-----
> De : gdb-patches-owner@sourceware.org [mailto:gdb-patches-
> owner@sourceware.org] De la part de Sergio Durigan Junior
> Envoyé : mercredi 1 avril 2015 01:40
> À : Pedro Alves
> Cc : GDB Patches
> Objet : Re: [PATCH 1/2] Implement support for checking
> /proc/PID/coredump_filter
> 
> On Friday, March 27 2015, Pedro Alves wrote:
> 
> > OK.
> 
> Thanks, pushed both patches:
> 
>   <https://sourceware.org/ml/gdb-cvs/2015-03/msg00275.html>
>   df8411da087dc05481926f4c4a82deabc5bc3859
> 
> --
> Sergio
> GPG key ID: 0x65FC5E36
> Please send encrypted e-mail if possible
> http://sergiodj.net/

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: Build failure following: Implement support for checking /proc/PID/coredump_filter commit
  2015-04-08 14:08       ` Build failure following: Implement support for checking /proc/PID/coredump_filter commit Pierre Muller
@ 2015-04-08 14:43         ` Pedro Alves
  2015-04-08 15:14           ` Pedro Alves
  2015-04-08 16:27           ` Yao Qi
  0 siblings, 2 replies; 21+ messages in thread
From: Pedro Alves @ 2015-04-08 14:43 UTC (permalink / raw)
  To: Pierre Muller, 'Sergio Durigan Junior'; +Cc: 'GDB Patches'

On 04/08/2015 03:07 PM, Pierre Muller wrote:

> Or maybe we should use the gnulib version of strtok_r?

Yes.

> I don't really know how to do this, but if someone can tell me,
> I can test the patch.

Let me give that a try, and I'll post a branch for you to test.

There's also the "users/palves/gnulib-update" branch that
updates gdb's copy of gnulib to recent gnulib master.  It'd
be great if someone confirmed that a gdb build of that branch
actually works on Windows, so we can move forward with that.
(the branch predates Sergio's patch, so isn't affected by the strtok_r
issue).  I'd be nice to update our gnulib copy before we pull in
more modules, to avoid tripping on bugs that have meanwhile already
been fixed upstream, or avoid module dependencies that may
have been reduced upstream...

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: Build failure following: Implement support for checking /proc/PID/coredump_filter commit
  2015-04-08 14:43         ` Pedro Alves
@ 2015-04-08 15:14           ` Pedro Alves
  2015-04-08 16:08             ` Sergio Durigan Junior
  2015-04-08 16:28             ` Pierre Muller
  2015-04-08 16:27           ` Yao Qi
  1 sibling, 2 replies; 21+ messages in thread
From: Pedro Alves @ 2015-04-08 15:14 UTC (permalink / raw)
  To: Pierre Muller, 'Sergio Durigan Junior'; +Cc: 'GDB Patches'

On 04/08/2015 03:43 PM, Pedro Alves wrote:
> On 04/08/2015 03:07 PM, Pierre Muller wrote:
> 
>> Or maybe we should use the gnulib version of strtok_r?
> 
> Yes.
> 
>> I don't really know how to do this, but if someone can tell me,
>> I can test the patch.
> 
> Let me give that a try, and I'll post a branch for you to test.

Please try the users/palves/gnulib-strtok_r branch.

A nice thing is that the strtok_r module didn't pull in any
other new module.

> There's also the "users/palves/gnulib-update" branch that
> updates gdb's copy of gnulib to recent gnulib master.  It'd
> be great if someone confirmed that a gdb build of that branch
> actually works on Windows, so we can move forward with that.
> (the branch predates Sergio's patch, so isn't affected by the strtok_r
> issue).  I'd be nice to update our gnulib copy before we pull in
> more modules, to avoid tripping on bugs that have meanwhile already
> been fixed upstream, or avoid module dependencies that may
> have been reduced upstream...

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: Build failure following: Implement support for checking /proc/PID/coredump_filter commit
  2015-04-08 15:14           ` Pedro Alves
@ 2015-04-08 16:08             ` Sergio Durigan Junior
  2015-04-08 16:28             ` Pierre Muller
  1 sibling, 0 replies; 21+ messages in thread
From: Sergio Durigan Junior @ 2015-04-08 16:08 UTC (permalink / raw)
  To: Pedro Alves; +Cc: Pierre Muller, 'GDB Patches'

On Wednesday, April 08 2015, Pedro Alves wrote:

> On 04/08/2015 03:43 PM, Pedro Alves wrote:
>> On 04/08/2015 03:07 PM, Pierre Muller wrote:
>> 
>>> Or maybe we should use the gnulib version of strtok_r?
>> 
>> Yes.
>> 
>>> I don't really know how to do this, but if someone can tell me,
>>> I can test the patch.
>> 
>> Let me give that a try, and I'll post a branch for you to test.
>
> Please try the users/palves/gnulib-strtok_r branch.
>
> A nice thing is that the strtok_r module didn't pull in any
> other new module.

Sorry about the breakage, Pierre.  And thanks for taking care of that,
Pedro.

It seems that if this gnulib import succeed everything will be fine, so
I won't do anything for now.  But I will keep an eye on the discussion.

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: Build failure following: Implement support for checking /proc/PID/coredump_filter commit
  2015-04-08 14:43         ` Pedro Alves
  2015-04-08 15:14           ` Pedro Alves
@ 2015-04-08 16:27           ` Yao Qi
  2015-04-08 16:47             ` Pedro Alves
  1 sibling, 1 reply; 21+ messages in thread
From: Yao Qi @ 2015-04-08 16:27 UTC (permalink / raw)
  To: Pedro Alves
  Cc: Pierre Muller, 'Sergio Durigan Junior', 'GDB Patches'

Pedro Alves <palves@redhat.com> writes:

> There's also the "users/palves/gnulib-update" branch that
> updates gdb's copy of gnulib to recent gnulib master.  It'd
> be great if someone confirmed that a gdb build of that branch
> actually works on Windows, so we can move forward with that.
> (the branch predates Sergio's patch, so isn't affected by the strtok_r
> issue).  I'd be nice to update our gnulib copy before we pull in
> more modules, to avoid tripping on bugs that have meanwhile already
> been fixed upstream, or avoid module dependencies that may
> have been reduced upstream...

On the other hand, updating our gnulib copy from upstream may introduce
new bugs.  strtok_r exists in the gnulib
8d5bd1402003bd0153984b138735adf537d960b0 commit we are using, I don't
see why we need to update our gnulib copy, unless there are some known
bug fixes in gnulib upstream.

-- 
Yao (齐尧)

^ permalink raw reply	[flat|nested] 21+ messages in thread

* RE: Build failure following: Implement support for checking /proc/PID/coredump_filter commit
  2015-04-08 15:14           ` Pedro Alves
  2015-04-08 16:08             ` Sergio Durigan Junior
@ 2015-04-08 16:28             ` Pierre Muller
  2015-04-08 16:47               ` Sergio Durigan Junior
  1 sibling, 1 reply; 21+ messages in thread
From: Pierre Muller @ 2015-04-08 16:28 UTC (permalink / raw)
  To: 'Pedro Alves', 'Sergio Durigan Junior'
  Cc: 'GDB Patches'



> -----Message d'origine-----
> De : gdb-patches-owner@sourceware.org [mailto:gdb-patches-
> owner@sourceware.org] De la part de Pedro Alves
> Envoyé : mercredi 8 avril 2015 17:14
> À : Pierre Muller; 'Sergio Durigan Junior'
> Cc : 'GDB Patches'
> Objet : Re: Build failure following: Implement support for checking
> /proc/PID/coredump_filter commit
> 
> On 04/08/2015 03:43 PM, Pedro Alves wrote:
> > On 04/08/2015 03:07 PM, Pierre Muller wrote:
> >
> >> Or maybe we should use the gnulib version of strtok_r?
> >
> > Yes.
> >
> >> I don't really know how to do this, but if someone can tell me,
> >> I can test the patch.
> >
> > Let me give that a try, and I'll post a branch for you to test.
> 
> Please try the users/palves/gnulib-strtok_r branch.

I can confirm that I am able to build mingw32 64bit gdb.exe executable,
and it contains gnulib/import/strtok_r.c source.

  I am not really able to test that the code works OK,
as I don't really know how to trigger that code...

  I have no idea what we should do now...

Pierre Muller

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: Build failure following: Implement support for checking /proc/PID/coredump_filter commit
  2015-04-08 16:27           ` Yao Qi
@ 2015-04-08 16:47             ` Pedro Alves
  0 siblings, 0 replies; 21+ messages in thread
From: Pedro Alves @ 2015-04-08 16:47 UTC (permalink / raw)
  To: Yao Qi
  Cc: Pierre Muller, 'Sergio Durigan Junior', 'GDB Patches'

On 04/08/2015 05:27 PM, Yao Qi wrote:
> Pedro Alves <palves@redhat.com> writes:
> 
>> There's also the "users/palves/gnulib-update" branch that
>> updates gdb's copy of gnulib to recent gnulib master.  It'd
>> be great if someone confirmed that a gdb build of that branch
>> actually works on Windows, so we can move forward with that.
>> (the branch predates Sergio's patch, so isn't affected by the strtok_r
>> issue).  I'd be nice to update our gnulib copy before we pull in
>> more modules, to avoid tripping on bugs that have meanwhile already
>> been fixed upstream, or avoid module dependencies that may
>> have been reduced upstream...
> 
> On the other hand, updating our gnulib copy from upstream may introduce
> new bugs.

Sure.  And we can report and fix them, or downgrade a few revisions to
before when the bug was introduced.

> strtok_r exists in the gnulib
> 8d5bd1402003bd0153984b138735adf537d960b0 commit we are using, I don't

That's actually what I did in the branch I pointed Pierre at.

> see why we need to update our gnulib copy, unless there are some known
> bug fixes in gnulib upstream.

Why risk stumbling on bugs that might have been fixed in the 3
years since the last import?  The more modules we import off the older
copy, the wider the potential-bugs surface.  And then what to do if we
need to patch gnulib?  If the requirement is to send the fix upstream
first, and then refresh our import, it'll be much easier if the
re-import is just a small incremental update, rather than pulling in
multiple years of gnulib work.  The further apart our update is, the
harder it is to update.  If we keep our copy reasonably up to date, we
have a better chance of whoever introduced the bug upstream to still have
the issue fresh in mind and provide a prompt fix.  If we wait 3 years
to report a bug, then the chances are good that we get to fix
it ourselves.

I currently want to update gnulib for at least 3 reasons:

 - GDB-in-C++ on mingw:

   https://sourceware.org/ml/gdb-patches/2015-03/msg00447.html

   That will have to be fixed on gnulib.  Haven't checked if
   already fixed there, but most probably it is.

 - Antoine's use of canonicalize:

   https://sourceware.org/ml/gdb-patches/2015-03/msg00917.html

   That pulls in a truck load of modules.  I'd hope the dependencies
   are fewer in a newer gnulib, or at least, if the dependencies are the
   same, I'd much prefer importing up-to-date versions.  Otherwise, the
   poor soul that next updates gnulib is likely to have a "fun" time.

 - Pull in the fts module to get rid of the "system" call in compile/,
   as discussed a while ago.

I think now's the best time, as we still have time till the next
gdb release.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: Build failure following: Implement support for checking /proc/PID/coredump_filter commit
  2015-04-08 16:28             ` Pierre Muller
@ 2015-04-08 16:47               ` Sergio Durigan Junior
  2015-04-08 17:21                 ` Pedro Alves
  0 siblings, 1 reply; 21+ messages in thread
From: Sergio Durigan Junior @ 2015-04-08 16:47 UTC (permalink / raw)
  To: Pierre Muller; +Cc: 'Pedro Alves', 'GDB Patches'

On Wednesday, April 08 2015, Pierre Muller wrote:

>> Please try the users/palves/gnulib-strtok_r branch.
>
> I can confirm that I am able to build mingw32 64bit gdb.exe executable,
> and it contains gnulib/import/strtok_r.c source.

That is great, thanks Pierre.

>   I am not really able to test that the code works OK,
> as I don't really know how to trigger that code...

The code will not work on native Windows debugging, so there is nothing
to test there.  If you debug a remote GNU/Linux target, you should be
able to tweak the value of /proc/PID/coredump_filter on the target and
generate different kinds of corefiles based on it.  But I don't know how
hard it would be for you to test this.

>   I have no idea what we should do now...

IMO the easiest and safest thing to do now would be to just import the
strtok_r module from gnulib (without updating it).

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: Build failure following: Implement support for checking /proc/PID/coredump_filter commit
  2015-04-08 16:47               ` Sergio Durigan Junior
@ 2015-04-08 17:21                 ` Pedro Alves
  0 siblings, 0 replies; 21+ messages in thread
From: Pedro Alves @ 2015-04-08 17:21 UTC (permalink / raw)
  To: Sergio Durigan Junior, Pierre Muller; +Cc: 'GDB Patches'

On 04/08/2015 05:46 PM, Sergio Durigan Junior wrote:
>> >   I have no idea what we should do now...
> IMO the easiest and safest thing to do now would be to just import the
> strtok_r module from gnulib (without updating it).

Yeah.  I posted the branch as proper patch series now.

 https://sourceware.org/ml/gdb-patches/2015-04/msg00288.html

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/2] Implement support for checking /proc/PID/coredump_filter
  2015-03-23 18:40         ` Sergio Durigan Junior
@ 2015-03-23 20:36           ` Pedro Alves
  0 siblings, 0 replies; 21+ messages in thread
From: Pedro Alves @ 2015-03-23 20:36 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: GDB Patches

On 03/23/2015 06:40 PM, Sergio Durigan Junior wrote:
> Done.  Patch attached.  I will wait until you look at the second patch
> (and approve it) in order to commit everything together.

Thanks.  FAOD, this version is OK.

On 03/23/2015 06:40 PM, Sergio Durigan Junior wrote:
> Jan has provided a good example of it before.  When you use stat -L, you
> can see if the 'Links' count is zero (which means the real file has been
> really deleted).  For example:
> 
>   lrw-------. 1 sergio sergio 64 Mar 23 14:34 7f2c5911b000-7f2c5911c000 -> /tmp/t2 (deleted)
>   [root@bla map_files]# stat -L 7f2c5911b000-7f2c5911c000 
>     File: ‘7f2c5911b000-7f2c5911c000’
>     Size: 0               Blocks: 0          IO Block: 4096   regular empty file
>   Device: 23h/35d         Inode: 217633770   Links: 1
> 
> The 'Links' is 1 because, despite the fact that 't2' has been deleted,
> the original file 't1' still exists.  However, if I remove 't1':
> 
>   [root@bla map_files]# stat -L 7f2c5911b000-7f2c5911c000 
>     File: ‘7f2c5911b000-7f2c5911c000’
>     Size: 0               Blocks: 0          IO Block: 4096   regular empty file
>   Device: 23h/35d         Inode: 217633770   Links: 0
> 
> Therefore, it should be possible to use stat even in this case.  But
> anyway, this was just FYI, we're not doing that.

Ah, yes, these files really work as symlinks, so ls -l was just
showing the symlink's own link count.  "ls -l -L" works too.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/2] Implement support for checking /proc/PID/coredump_filter
  2015-03-20 22:02       ` Pedro Alves
@ 2015-03-23 18:40         ` Sergio Durigan Junior
  2015-03-23 20:36           ` Pedro Alves
  0 siblings, 1 reply; 21+ messages in thread
From: Sergio Durigan Junior @ 2015-03-23 18:40 UTC (permalink / raw)
  To: Pedro Alves; +Cc: GDB Patches

On Friday, March 20 2015, Pedro Alves wrote:

> On 03/20/2015 08:02 PM, Sergio Durigan Junior wrote:
>>>> >> +     It is worth mentioning that, from all those checks described
>>>> >> +     above, the most fragile is the one to see if the file name ends
>>>> >> +     with " (deleted)".  This does not necessarily mean that the
>>>> >> +     mapping is anonymous, because the deleted file associated with
>>>> >> +     the mapping may have been a hard link to another file, for
>>>> >> +     example.  The Linux kernel checks to see if "i_nlink == 0", but
>>>> >> +     GDB cannot easily do this check.  Therefore, we made a compromise
>>> >
>>> > Cannot do it easily, or cannot do it at all?
>> It cannot do it easily.  If GDB is run by root, then it could (in
>> theory) inspect the contents of /proc/PID/map_files and determine
>> whether the " (deleted)" file was a hard link or not.
>
> Ah, could you include that in the comment please?
> Otherwise every time I read that I'll wonder what wasn't easy.  :-)
>
> Like:
>
> "(..) example.  The Linux kernel checks to see if "i_nlink == 0", but
> GDB cannot easily (and normally) do this check (iff running as root,
> it could find the mapping in /proc/PID/map_files/ and determine
> whether there still are other hard links to the inode/file).
> Therefore, we made a compromise (...)"

Done.  Patch attached.  I will wait until you look at the second patch
(and approve it) in order to commit everything together.

> I quickly tried something like that with "/proc/pid/fd/*", and
> unfortunately the link count is always 1, at least on F20's kernel:
>
> $ tail > a&
> [1] 12343
>
> [1]+  Stopped                 tail > a
> $ ls -l a
> -rw-rw-r--. 1 pedro pedro 0 Mar 20 21:29 a
> $ ln a b
> $ ls -l a
> -rw-rw-r--. 2 pedro pedro 0 Mar 20 21:29 a
> $ ls -l /proc/12343/fd/1
> l-wx------. 1 pedro pedro 64 Mar 20 21:30 /proc/12343/fd/1 -> /tmp/a
>
> If map_files/ works the same, I think we'd have to get the
> file's inode number, and look over the whole filesystem for
> other files with that inode number (the equivalent
> of 'ls -i' 'find / -inum').  Urgh!

Jan has provided a good example of it before.  When you use stat -L, you
can see if the 'Links' count is zero (which means the real file has been
really deleted).  For example:

  lrw-------. 1 sergio sergio 64 Mar 23 14:34 7f2c5911b000-7f2c5911c000 -> /tmp/t2 (deleted)
  [root@bla map_files]# stat -L 7f2c5911b000-7f2c5911c000 
    File: ‘7f2c5911b000-7f2c5911c000’
    Size: 0               Blocks: 0          IO Block: 4096   regular empty file
  Device: 23h/35d         Inode: 217633770   Links: 1

The 'Links' is 1 because, despite the fact that 't2' has been deleted,
the original file 't1' still exists.  However, if I remove 't1':

  [root@bla map_files]# stat -L 7f2c5911b000-7f2c5911c000 
    File: ‘7f2c5911b000-7f2c5911c000’
    Size: 0               Blocks: 0          IO Block: 4096   regular empty file
  Device: 23h/35d         Inode: 217633770   Links: 0

Therefore, it should be possible to use stat even in this case.  But
anyway, this was just FYI, we're not doing that.

-- 
Sergio
GPG key ID: 0x65FC5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index ea0d4cd..26edd5d 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -35,9 +35,61 @@
 #include "observer.h"
 #include "objfiles.h"
 #include "infcall.h"
+#include "gdbcmd.h"
+#include "gdb_regex.h"
 
 #include <ctype.h>
 
+/* This enum represents the values that the user can choose when
+   informing the Linux kernel about which memory mappings will be
+   dumped in a corefile.  They are described in the file
+   Documentation/filesystems/proc.txt, inside the Linux kernel
+   tree.  */
+
+enum
+  {
+    COREFILTER_ANON_PRIVATE = 1 << 0,
+    COREFILTER_ANON_SHARED = 1 << 1,
+    COREFILTER_MAPPED_PRIVATE = 1 << 2,
+    COREFILTER_MAPPED_SHARED = 1 << 3,
+    COREFILTER_ELF_HEADERS = 1 << 4,
+    COREFILTER_HUGETLB_PRIVATE = 1 << 5,
+    COREFILTER_HUGETLB_SHARED = 1 << 6,
+  };
+
+/* This struct is used to map flags found in the "VmFlags:" field (in
+   the /proc/<PID>/smaps file).  */
+
+struct smaps_vmflags
+  {
+    /* Zero if this structure has not been initialized yet.  It
+       probably means that the Linux kernel being used does not emit
+       the "VmFlags:" field on "/proc/PID/smaps".  */
+
+    unsigned int initialized_p : 1;
+
+    /* Memory mapped I/O area (VM_IO, "io").  */
+
+    unsigned int io_page : 1;
+
+    /* Area uses huge TLB pages (VM_HUGETLB, "ht").  */
+
+    unsigned int uses_huge_tlb : 1;
+
+    /* Do not include this memory region on the coredump (VM_DONTDUMP, "dd").  */
+
+    unsigned int exclude_coredump : 1;
+
+    /* Is this a MAP_SHARED mapping (VM_SHARED, "sh").  */
+
+    unsigned int shared_mapping : 1;
+  };
+
+/* Whether to take the /proc/PID/coredump_filter into account when
+   generating a corefile.  */
+
+static int use_coredump_filter = 1;
+
 /* This enum represents the signals' numbers on a generic architecture
    running the Linux kernel.  The definition of "generic" comes from
    the file <include/uapi/asm-generic/signal.h>, from the Linux kernel
@@ -381,6 +433,231 @@ read_mapping (const char *line,
   *filename = p;
 }
 
+/* Helper function to decode the "VmFlags" field in /proc/PID/smaps.
+
+   This function was based on the documentation found on
+   <Documentation/filesystems/proc.txt>, on the Linux kernel.
+
+   Linux kernels before commit
+   834f82e2aa9a8ede94b17b656329f850c1471514 (3.10) do not have this
+   field on smaps.  */
+
+static void
+decode_vmflags (char *p, struct smaps_vmflags *v)
+{
+  char *saveptr;
+  const char *s;
+
+  v->initialized_p = 1;
+  p = skip_to_space (p);
+  p = skip_spaces (p);
+
+  for (s = strtok_r (p, " ", &saveptr);
+       s != NULL;
+       s = strtok_r (NULL, " ", &saveptr))
+    {
+      if (strcmp (s, "io") == 0)
+	v->io_page = 1;
+      else if (strcmp (s, "ht") == 0)
+	v->uses_huge_tlb = 1;
+      else if (strcmp (s, "dd") == 0)
+	v->exclude_coredump = 1;
+      else if (strcmp (s, "sh") == 0)
+	v->shared_mapping = 1;
+    }
+}
+
+/* Return 1 if the memory mapping is anonymous, 0 otherwise.
+
+   FILENAME is the name of the file present in the first line of the
+   memory mapping, in the "/proc/PID/smaps" output.  For example, if
+   the first line is:
+
+   7fd0ca877000-7fd0d0da0000 r--p 00000000 fd:02 2100770   /path/to/file
+
+   Then FILENAME will be "/path/to/file".  */
+
+static int
+mapping_is_anonymous_p (const char *filename)
+{
+  static regex_t dev_zero_regex, shmem_file_regex, file_deleted_regex;
+  static int init_regex_p = 0;
+
+  if (!init_regex_p)
+    {
+      struct cleanup *c = make_cleanup (null_cleanup, NULL);
+
+      /* Let's be pessimistic and assume there will be an error while
+	 compiling the regex'es.  */
+      init_regex_p = -1;
+
+      /* DEV_ZERO_REGEX matches "/dev/zero" filenames (with or
+	 without the "(deleted)" string in the end).  We know for
+	 sure, based on the Linux kernel code, that memory mappings
+	 whose associated filename is "/dev/zero" are guaranteed to be
+	 MAP_ANONYMOUS.  */
+      compile_rx_or_error (&dev_zero_regex, "^/dev/zero\\( (deleted)\\)\\?$",
+			   _("Could not compile regex to match /dev/zero "
+			     "filename"));
+      /* SHMEM_FILE_REGEX matches "/SYSV%08x" filenames (with or
+	 without the "(deleted)" string in the end).  These filenames
+	 refer to shared memory (shmem), and memory mappings
+	 associated with them are MAP_ANONYMOUS as well.  */
+      compile_rx_or_error (&shmem_file_regex,
+			   "^/\\?SYSV[0-9a-fA-F]\\{8\\}\\( (deleted)\\)\\?$",
+			   _("Could not compile regex to match shmem "
+			     "filenames"));
+      /* FILE_DELETED_REGEX is a heuristic we use to try to mimic the
+	 Linux kernel's 'n_link == 0' code, which is responsible to
+	 decide if it is dealing with a 'MAP_SHARED | MAP_ANONYMOUS'
+	 mapping.  In other words, if FILE_DELETED_REGEX matches, it
+	 does not necessarily mean that we are dealing with an
+	 anonymous shared mapping.  However, there is no easy way to
+	 detect this currently, so this is the best approximation we
+	 have.
+
+	 As a result, GDB will dump readonly pages of deleted
+	 executables when using the default value of coredump_filter
+	 (0x33), while the Linux kernel will not dump those pages.
+	 But we can live with that.  */
+      compile_rx_or_error (&file_deleted_regex, " (deleted)$",
+			   _("Could not compile regex to match "
+			     "'<file> (deleted)'"));
+      /* We will never release these regexes, so just discard the
+	 cleanups.  */
+      discard_cleanups (c);
+
+      /* If we reached this point, then everything succeeded.  */
+      init_regex_p = 1;
+    }
+
+  if (init_regex_p == -1)
+    {
+      const char deleted[] = " (deleted)";
+      size_t del_len = sizeof (deleted) - 1;
+      size_t filename_len = strlen (filename);
+
+      /* There was an error while compiling the regex'es above.  In
+	 order to try to give some reliable information to the caller,
+	 we just try to find the string " (deleted)" in the filename.
+	 If we managed to find it, then we assume the mapping is
+	 anonymous.  */
+      return (filename_len >= del_len
+	      && strcmp (filename + filename_len - del_len, deleted) == 0);
+    }
+
+  if (*filename == '\0'
+      || regexec (&dev_zero_regex, filename, 0, NULL, 0) == 0
+      || regexec (&shmem_file_regex, filename, 0, NULL, 0) == 0
+      || regexec (&file_deleted_regex, filename, 0, NULL, 0) == 0)
+    return 1;
+
+  return 0;
+}
+
+/* Return 0 if the memory mapping (which is related to FILTERFLAGS, V,
+   MAYBE_PRIVATE_P, and MAPPING_ANONYMOUS_P) should not be dumped, or
+   greater than 0 if it should.
+
+   In a nutshell, this is the logic that we follow in order to decide
+   if a mapping should be dumped or not.
+
+   - If the mapping is associated to a file whose name ends with
+     " (deleted)", or if the file is "/dev/zero", or if it is
+     "/SYSV%08x" (shared memory), or if there is no file associated
+     with it, or if the AnonHugePages: or the Anonymous: fields in the
+     /proc/PID/smaps have contents, then GDB considers this mapping to
+     be anonymous.  Otherwise, GDB considers this mapping to be a
+     file-backed mapping (because there will be a file associated with
+     it).
+ 
+     It is worth mentioning that, from all those checks described
+     above, the most fragile is the one to see if the file name ends
+     with " (deleted)".  This does not necessarily mean that the
+     mapping is anonymous, because the deleted file associated with
+     the mapping may have been a hard link to another file, for
+     example.  The Linux kernel checks to see if "i_nlink == 0", but
+     GDB cannot easily (and normally) do this check (iff running as
+     root, it could find the mapping in /proc/PID/map_files/ and
+     determine whether there still are other hard links to the
+     inode/file).  Therefore, we made a compromise here, and we assume
+     that if the file name ends with " (deleted)", then the mapping is
+     indeed anonymous.  FWIW, this is something the Linux kernel could
+     do better: expose this information in a more direct way.
+ 
+   - If we see the flag "sh" in the "VmFlags:" field (in
+     /proc/PID/smaps), then certainly the memory mapping is shared
+     (VM_SHARED).  If we have access to the VmFlags, and we don't see
+     the "sh" there, then certainly the mapping is private.  However,
+     Linux kernels before commit
+     834f82e2aa9a8ede94b17b656329f850c1471514 (3.10) do not have the
+     "VmFlags:" field; in that case, we use another heuristic: if we
+     see 'p' in the permission flags, then we assume that the mapping
+     is private, even though the presence of the 's' flag there would
+     mean VM_MAYSHARE, which means the mapping could still be private.
+     This should work OK enough, however.  */
+
+static int
+dump_mapping_p (unsigned int filterflags, const struct smaps_vmflags *v,
+		int maybe_private_p, int mapping_anon_p, const char *filename)
+{
+  /* Initially, we trust in what we received from our caller.  This
+     value may not be very precise (i.e., it was probably gathered
+     from the permission line in the /proc/PID/smaps list, which
+     actually refers to VM_MAYSHARE, and not VM_SHARED), but it is
+     what we have until we take a look at the "VmFlags:" field
+     (assuming that the version of the Linux kernel being used
+     supports it, of course).  */
+  int private_p = maybe_private_p;
+
+  /* We always dump vDSO and vsyscall mappings, because it's likely that
+     there'll be no file to read the contents from at core load time.
+     The kernel does the same.  */
+  if (strcmp ("[vdso]", filename) == 0
+      || strcmp ("[vsyscall]", filename) == 0)
+    return 1;
+
+  if (v->initialized_p)
+    {
+      /* We never dump I/O mappings.  */
+      if (v->io_page)
+	return 0;
+
+      /* Check if we should exclude this mapping.  */
+      if (v->exclude_coredump)
+	return 0;
+
+      /* Update our notion of whether this mapping is shared or
+	 private based on a trustworthy value.  */
+      private_p = !v->shared_mapping;
+
+      /* HugeTLB checking.  */
+      if (v->uses_huge_tlb)
+	{
+	  if ((private_p && (filterflags & COREFILTER_HUGETLB_PRIVATE))
+	      || (!private_p && (filterflags & COREFILTER_HUGETLB_SHARED)))
+	    return 1;
+
+	  return 0;
+	}
+    }
+
+  if (private_p)
+    {
+      if (mapping_anon_p)
+	return (filterflags & COREFILTER_ANON_PRIVATE) != 0;
+      else
+	return (filterflags & COREFILTER_MAPPED_PRIVATE) != 0;
+    }
+  else
+    {
+      if (mapping_anon_p)
+	return (filterflags & COREFILTER_ANON_SHARED) != 0;
+      else
+	return (filterflags & COREFILTER_MAPPED_SHARED) != 0;
+    }
+}
+
 /* Implement the "info proc" command.  */
 
 static void
@@ -819,48 +1096,86 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
 				void *obfd)
 {
   char mapsfilename[100];
-  char *data;
+  char coredumpfilter_name[100];
+  char *data, *coredumpfilterdata;
+  pid_t pid;
+  /* Default dump behavior of coredump_filter (0x33), according to
+     Documentation/filesystems/proc.txt from the Linux kernel
+     tree.  */
+  unsigned int filterflags = (COREFILTER_ANON_PRIVATE
+			      | COREFILTER_ANON_SHARED
+			      | COREFILTER_ELF_HEADERS
+			      | COREFILTER_HUGETLB_PRIVATE);
 
   /* We need to know the real target PID to access /proc.  */
   if (current_inferior ()->fake_pid_p)
     return 1;
 
-  xsnprintf (mapsfilename, sizeof mapsfilename,
-	     "/proc/%d/smaps", current_inferior ()->pid);
+  pid = current_inferior ()->pid;
+
+  if (use_coredump_filter)
+    {
+      xsnprintf (coredumpfilter_name, sizeof (coredumpfilter_name),
+		 "/proc/%d/coredump_filter", pid);
+      coredumpfilterdata = target_fileio_read_stralloc (coredumpfilter_name);
+      if (coredumpfilterdata != NULL)
+	{
+	  sscanf (coredumpfilterdata, "%x", &filterflags);
+	  xfree (coredumpfilterdata);
+	}
+    }
+
+  xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/smaps", pid);
   data = target_fileio_read_stralloc (mapsfilename);
   if (data == NULL)
     {
       /* Older Linux kernels did not support /proc/PID/smaps.  */
-      xsnprintf (mapsfilename, sizeof mapsfilename,
-		 "/proc/%d/maps", current_inferior ()->pid);
+      xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/maps", pid);
       data = target_fileio_read_stralloc (mapsfilename);
     }
-  if (data)
+
+  if (data != NULL)
     {
       struct cleanup *cleanup = make_cleanup (xfree, data);
-      char *line;
+      char *line, *t;
 
-      line = strtok (data, "\n");
-      while (line)
+      line = strtok_r (data, "\n", &t);
+      while (line != NULL)
 	{
 	  ULONGEST addr, endaddr, offset, inode;
 	  const char *permissions, *device, *filename;
+	  struct smaps_vmflags v;
 	  size_t permissions_len, device_len;
-	  int read, write, exec;
-	  int modified = 0, has_anonymous = 0;
+	  int read, write, exec, private;
+	  int has_anonymous = 0;
+	  int should_dump_p = 0;
+	  int mapping_anon_p;
 
+	  memset (&v, 0, sizeof (v));
 	  read_mapping (line, &addr, &endaddr, &permissions, &permissions_len,
 			&offset, &device, &device_len, &inode, &filename);
+	  mapping_anon_p = mapping_is_anonymous_p (filename);
 
 	  /* Decode permissions.  */
 	  read = (memchr (permissions, 'r', permissions_len) != 0);
 	  write = (memchr (permissions, 'w', permissions_len) != 0);
 	  exec = (memchr (permissions, 'x', permissions_len) != 0);
-
-	  /* Try to detect if region was modified by parsing smaps counters.  */
-	  for (line = strtok (NULL, "\n");
-	       line && line[0] >= 'A' && line[0] <= 'Z';
-	       line = strtok (NULL, "\n"))
+	  /* 'private' here actually means VM_MAYSHARE, and not
+	     VM_SHARED.  In order to know if a mapping is really
+	     private or not, we must check the flag "sh" in the
+	     VmFlags field.  This is done by decode_vmflags.  However,
+	     if we are using a Linux kernel released before the commit
+	     834f82e2aa9a8ede94b17b656329f850c1471514 (3.10), we will
+	     not have the VmFlags there.  In this case, there is
+	     really no way to know if we are dealing with VM_SHARED,
+	     so we just assume that VM_MAYSHARE is enough.  */
+	  private = memchr (permissions, 'p', permissions_len) != 0;
+
+	  /* Try to detect if region should be dumped by parsing smaps
+	     counters.  */
+	  for (line = strtok_r (NULL, "\n", &t);
+	       line != NULL && line[0] >= 'A' && line[0] <= 'Z';
+	       line = strtok_r (NULL, "\n", &t))
 	    {
 	      char keyword[64 + 1];
 
@@ -869,11 +1184,17 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
 		  warning (_("Error parsing {s,}maps file '%s'"), mapsfilename);
 		  break;
 		}
+
 	      if (strcmp (keyword, "Anonymous:") == 0)
-		has_anonymous = 1;
-	      if (strcmp (keyword, "Shared_Dirty:") == 0
-		  || strcmp (keyword, "Private_Dirty:") == 0
-		  || strcmp (keyword, "Swap:") == 0
+		{
+		  /* Older Linux kernels did not support the
+		     "Anonymous:" counter.  Check it here.  */
+		  has_anonymous = 1;
+		}
+	      else if (strcmp (keyword, "VmFlags:") == 0)
+		decode_vmflags (line, &v);
+
+	      if (strcmp (keyword, "AnonHugePages:") == 0
 		  || strcmp (keyword, "Anonymous:") == 0)
 		{
 		  unsigned long number;
@@ -884,19 +1205,38 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
 			       mapsfilename);
 		      break;
 		    }
-		  if (number != 0)
-		    modified = 1;
+		  if (number > 0)
+		    {
+		      /* Even if we are dealing with a file-backed
+			 mapping, if it contains anonymous pages we
+			 consider it to be an anonymous mapping,
+			 because this is what the Linux kernel does:
+
+			 // Dump segments that have been written to.
+			 if (vma->anon_vma && FILTER(ANON_PRIVATE))
+			 	goto whole;
+		      */
+		      mapping_anon_p = 1;
+		    }
 		}
 	    }
 
-	  /* Older Linux kernels did not support the "Anonymous:" counter.
-	     If it is missing, we can't be sure - dump all the pages.  */
-	  if (!has_anonymous)
-	    modified = 1;
+	  if (has_anonymous)
+	    should_dump_p = dump_mapping_p (filterflags, &v, private,
+					    mapping_anon_p, filename);
+	  else
+	    {
+	      /* Older Linux kernels did not support the "Anonymous:" counter.
+		 If it is missing, we can't be sure - dump all the pages.  */
+	      should_dump_p = 1;
+	    }
 
 	  /* Invoke the callback function to create the corefile segment.  */
-	  func (addr, endaddr - addr, offset, inode,
-		read, write, exec, modified, filename, obfd);
+	  if (should_dump_p)
+	    func (addr, endaddr - addr, offset, inode,
+		  read, write, exec, 1, /* MODIFIED is true because we
+					   want to dump the mapping.  */
+		  filename, obfd);
 	}
 
       do_cleanups (cleanup);
@@ -1972,6 +2312,17 @@ linux_infcall_mmap (CORE_ADDR size, unsigned prot)
   return retval;
 }
 
+/* Display whether the gcore command is using the
+   /proc/PID/coredump_filter file.  */
+
+static void
+show_use_coredump_filter (struct ui_file *file, int from_tty,
+			  struct cmd_list_element *c, const char *value)
+{
+  fprintf_filtered (file, _("Use of /proc/PID/coredump_filter file to generate"
+			    " corefiles is %s.\n"), value);
+}
+
 /* To be called from the various GDB_OSABI_LINUX handlers for the
    various GNU/Linux architectures and machine types.  */
 
@@ -2008,4 +2359,16 @@ _initialize_linux_tdep (void)
   /* Observers used to invalidate the cache when needed.  */
   observer_attach_inferior_exit (invalidate_linux_cache_inf);
   observer_attach_inferior_appeared (invalidate_linux_cache_inf);
+
+  add_setshow_boolean_cmd ("use-coredump-filter", class_files,
+			   &use_coredump_filter, _("\
+Set whether gcore should consider /proc/PID/coredump_filter."),
+			   _("\
+Show whether gcore should consider /proc/PID/coredump_filter."),
+			   _("\
+Use this command to set whether gcore should consider the contents\n\
+of /proc/PID/coredump_filter when generating the corefile.  For more information\n\
+about this file, refer to the manpage of core(5)."),
+			   NULL, show_use_coredump_filter,
+			   &setlist, &showlist);
 }

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/2] Implement support for checking /proc/PID/coredump_filter
  2015-03-20 20:02     ` Sergio Durigan Junior
@ 2015-03-20 22:02       ` Pedro Alves
  2015-03-23 18:40         ` Sergio Durigan Junior
  0 siblings, 1 reply; 21+ messages in thread
From: Pedro Alves @ 2015-03-20 22:02 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: GDB Patches

On 03/20/2015 08:02 PM, Sergio Durigan Junior wrote:
>>> >> +     It is worth mentioning that, from all those checks described
>>> >> +     above, the most fragile is the one to see if the file name ends
>>> >> +     with " (deleted)".  This does not necessarily mean that the
>>> >> +     mapping is anonymous, because the deleted file associated with
>>> >> +     the mapping may have been a hard link to another file, for
>>> >> +     example.  The Linux kernel checks to see if "i_nlink == 0", but
>>> >> +     GDB cannot easily do this check.  Therefore, we made a compromise
>> >
>> > Cannot do it easily, or cannot do it at all?
> It cannot do it easily.  If GDB is run by root, then it could (in
> theory) inspect the contents of /proc/PID/map_files and determine
> whether the " (deleted)" file was a hard link or not.

Ah, could you include that in the comment please?
Otherwise every time I read that I'll wonder what wasn't easy.  :-)

Like:

"(..) example.  The Linux kernel checks to see if "i_nlink == 0", but
GDB cannot easily (and normally) do this check (iff running as root,
it could find the mapping in /proc/PID/map_files/ and determine
whether there still are other hard links to the inode/file).
Therefore, we made a compromise (...)"


I quickly tried something like that with "/proc/pid/fd/*", and
unfortunately the link count is always 1, at least on F20's kernel:

$ tail > a&
[1] 12343

[1]+  Stopped                 tail > a
$ ls -l a
-rw-rw-r--. 1 pedro pedro 0 Mar 20 21:29 a
$ ln a b
$ ls -l a
-rw-rw-r--. 2 pedro pedro 0 Mar 20 21:29 a
$ ls -l /proc/12343/fd/1
l-wx------. 1 pedro pedro 64 Mar 20 21:30 /proc/12343/fd/1 -> /tmp/a

If map_files/ works the same, I think we'd have to get the
file's inode number, and look over the whole filesystem for
other files with that inode number (the equivalent
of 'ls -i' 'find / -inum').  Urgh!

Anyway, with the comment tweak, the patch looks good to me.  Thanks
again for doing this.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/2] Implement support for checking /proc/PID/coredump_filter
  2015-03-20 19:12   ` Pedro Alves
@ 2015-03-20 20:02     ` Sergio Durigan Junior
  2015-03-20 22:02       ` Pedro Alves
  0 siblings, 1 reply; 21+ messages in thread
From: Sergio Durigan Junior @ 2015-03-20 20:02 UTC (permalink / raw)
  To: Pedro Alves; +Cc: GDB Patches

On Friday, March 20 2015, Pedro Alves wrote:

> Thanks, this looks good to me now, just a few minor nits.

Thanks for the review again!

> On 03/19/2015 11:22 PM, Sergio Durigan Junior wrote:
>
>> +/* Helper function to decode the "VmFlags" field in /proc/PID/smaps.
>> +
>> +   This function was based on the documentation found on
>> +   <Documentation/filesystems/proc.txt>, on the Linux kernel.
>> +
>> +   Linux kernels before commit
>> +   834f82e2aa9a8ede94b17b656329f850c1471514 do not have this field on
>> +   smaps.  */
>
> Thanks for the version info.  Ideally, what I'd like with these version notes
> is at any point in the time in the future being able to look at the code
> and easily identify whether we're working around an old enough kernel that
> we potentially can stop worrying about backwards compatibility with
> such kernel.  If easy, could you also add the kernel version, like
> e.g., "$hash (x.y.z)"?

Yeah.  'git tag --contains 834f82e2aa9a8ede94b17b656329f850c1471514'
shows me that the first release to contain this commit was 3.10.  So I'm
putting it there.

>> +  if (init_regex_p == -1)
>> +    {
>> +      /* There was an error while compiling the regex'es above.  In
>> +	 order to try to give some reliable information to the caller,
>> +	 we just try to find the string "(deleted)" in the filename.
>> +	 If we managed to find it, then we assume the mapping is
>> +	 anonymous.  */
>> +      return strstr (filename, "(deleted)") != NULL;
>
> Might as well add the space before parens, and match tail
> end only, like e.g.,:
>
>    const char deleted[] = " (deleted)";
>    size_t del_len = strlen (deleted);
>    size_t filename_len = strlen (filename);
>
>    return (filename_len >= del_len
>            && strcmp (filename + filename_len - del_len, deleted) == 0);

Done.

>> +
>> +/* Return 0 if the memory mapping (which is related to FILTERFLAGS, V,
>> +   MAYBE_PRIVATE_P, and MAPPING_ANONYMOUS_P) should not be dumped, or
>> +   greater than 0 if it should.
>> +
>> +   In a nutshell, this is the logic that we follow in order to decide
>> +   if a mapping should be dumped or not.
>> +
>> +   - If the mapping is associated to a file whose name ends with "
>> +     (deleted)"
>
> Nit: it'd be good to avoid breaking " (deleted)" over two lines.

Fixed.

>         > , or if the file is "/dev/zero", or if it is
>> +     "/SYSV%08x" (shared memory), or if there is no file associated
>> +     with it, or if the AnonHugePages: or the Anonymous: fields in the
>> +     /proc/PID/smaps have contents, then GDB considers this mapping to
>> +     be anonymous.  Otherwise, GDB considers this mapping to be a
>> +     file-backed mapping (because there will be a file associated with
>> +     it).
>> + 
>> +     It is worth mentioning that, from all those checks described
>> +     above, the most fragile is the one to see if the file name ends
>> +     with " (deleted)".  This does not necessarily mean that the
>> +     mapping is anonymous, because the deleted file associated with
>> +     the mapping may have been a hard link to another file, for
>> +     example.  The Linux kernel checks to see if "i_nlink == 0", but
>> +     GDB cannot easily do this check.  Therefore, we made a compromise
>
> Cannot do it easily, or cannot do it at all?

It cannot do it easily.  If GDB is run by root, then it could (in
theory) inspect the contents of /proc/PID/map_files and determine
whether the " (deleted)" file was a hard link or not.

>> +     here, and we assume that if the file name ends with " (deleted)",
>> +     then the mapping is indeed anonymous.  FWIW, this is something
>> +     the Linux kernel could do better: expose this information in a
>> +     more direct way.
>> + 
>> +   - If we see the flag "sh" in the "VmFlags:" field (in
>> +     /proc/PID/smaps), then certainly the memory mapping is shared
>> +     (VM_SHARED).  If we have access to the VmFlags, and we don't see
>> +     the "sh" there, then certainly the mapping is private.  However,
>> +     Linux kernels before commit
>> +     834f82e2aa9a8ede94b17b656329f850c1471514 do not have the
>> +     "VmFlags:" field; in that case, we use another heuristic: if we
>> +     see 'p' in the permission flags, then we assume that the mapping
>> +     is private, even though the presence of the 's' flag there would
>> +     mean VM_MAYSHARE, which means the mapping could still be private.
>> +     This should work OK enough, however.  */
>> +
>> +static int
>> +dump_mapping_p (unsigned int filterflags, const struct smaps_vmflags *v,
>> +		int maybe_private_p, int mapping_anon_p, const char *filename)
>> +{
>> +  /* Initially, we trust in what we received from outside.  This value
>
> outside == the caller?  or the kernel?  The former, right?

Yes, the former.  I improved the comment.

>> +     may not be very precise (i.e., it was probably gathered from the
>> +     permission line in the /proc/PID/smaps list, which actually
>> +     refers to VM_MAYSHARE, and not VM_SHARED), but it is what we have
>> +     for now.  */
>
> "for now" refers to the flag being updated further down, or future
> kernel versions?

The former.  I improved the comment.

>> +  int private_p = maybe_private_p;
>> +
>> +  /* We always dump vDSO and vsyscall mappings.  */
>
> Suggest:
>
>    /* We always dump vDSO and vsyscall mappings, because it's likely that
>       there'll be no file to read the contents from at core load time.
>       The kernel does the same.  */

Right, improved the comment with you suggestion.

> Thanks,
> Pedro Alves

-- 
Sergio
GPG key ID: 0x65FC5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

gdb/ChangeLog:
2015-03-20  Sergio Durigan Junior  <sergiodj@redhat.com>
	    Jan Kratochvil  <jan.kratochvil@redhat.com>
	    Oleg Nesterov  <oleg@redhat.com>

	PR corefiles/16092
	* linux-tdep.c: Include 'gdbcmd.h' and 'gdb_regex.h'.
	New enum identifying the various options of the coredump_filter
	file.
	(struct smaps_vmflags): New struct.
	(use_coredump_filter): New variable.
	(decode_vmflags): New function.
	(mapping_is_anonymous_p): Likewise.
	(dump_mapping_p): Likewise.
	(linux_find_memory_regions_full): New variables
	'coredumpfilter_name', 'coredumpfilterdata', 'pid', 'filterflags',
	'should_dump_p'.  Removed variable 'modified'.  Read
	/proc/<PID>/smaps file; improve parsing of its information.
	Implement memory mapping filtering based on its contents.
	(show_use_coredump_filter): New function.
	(_initialize_linux_tdep): New command 'set use-coredump-filter'.

diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index ea0d4cd..908c42c 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -35,9 +35,61 @@
 #include "observer.h"
 #include "objfiles.h"
 #include "infcall.h"
+#include "gdbcmd.h"
+#include "gdb_regex.h"
 
 #include <ctype.h>
 
+/* This enum represents the values that the user can choose when
+   informing the Linux kernel about which memory mappings will be
+   dumped in a corefile.  They are described in the file
+   Documentation/filesystems/proc.txt, inside the Linux kernel
+   tree.  */
+
+enum
+  {
+    COREFILTER_ANON_PRIVATE = 1 << 0,
+    COREFILTER_ANON_SHARED = 1 << 1,
+    COREFILTER_MAPPED_PRIVATE = 1 << 2,
+    COREFILTER_MAPPED_SHARED = 1 << 3,
+    COREFILTER_ELF_HEADERS = 1 << 4,
+    COREFILTER_HUGETLB_PRIVATE = 1 << 5,
+    COREFILTER_HUGETLB_SHARED = 1 << 6,
+  };
+
+/* This struct is used to map flags found in the "VmFlags:" field (in
+   the /proc/<PID>/smaps file).  */
+
+struct smaps_vmflags
+  {
+    /* Zero if this structure has not been initialized yet.  It
+       probably means that the Linux kernel being used does not emit
+       the "VmFlags:" field on "/proc/PID/smaps".  */
+
+    unsigned int initialized_p : 1;
+
+    /* Memory mapped I/O area (VM_IO, "io").  */
+
+    unsigned int io_page : 1;
+
+    /* Area uses huge TLB pages (VM_HUGETLB, "ht").  */
+
+    unsigned int uses_huge_tlb : 1;
+
+    /* Do not include this memory region on the coredump (VM_DONTDUMP, "dd").  */
+
+    unsigned int exclude_coredump : 1;
+
+    /* Is this a MAP_SHARED mapping (VM_SHARED, "sh").  */
+
+    unsigned int shared_mapping : 1;
+  };
+
+/* Whether to take the /proc/PID/coredump_filter into account when
+   generating a corefile.  */
+
+static int use_coredump_filter = 1;
+
 /* This enum represents the signals' numbers on a generic architecture
    running the Linux kernel.  The definition of "generic" comes from
    the file <include/uapi/asm-generic/signal.h>, from the Linux kernel
@@ -381,6 +433,229 @@ read_mapping (const char *line,
   *filename = p;
 }
 
+/* Helper function to decode the "VmFlags" field in /proc/PID/smaps.
+
+   This function was based on the documentation found on
+   <Documentation/filesystems/proc.txt>, on the Linux kernel.
+
+   Linux kernels before commit
+   834f82e2aa9a8ede94b17b656329f850c1471514 (3.10) do not have this
+   field on smaps.  */
+
+static void
+decode_vmflags (char *p, struct smaps_vmflags *v)
+{
+  char *saveptr;
+  const char *s;
+
+  v->initialized_p = 1;
+  p = skip_to_space (p);
+  p = skip_spaces (p);
+
+  for (s = strtok_r (p, " ", &saveptr);
+       s != NULL;
+       s = strtok_r (NULL, " ", &saveptr))
+    {
+      if (strcmp (s, "io") == 0)
+	v->io_page = 1;
+      else if (strcmp (s, "ht") == 0)
+	v->uses_huge_tlb = 1;
+      else if (strcmp (s, "dd") == 0)
+	v->exclude_coredump = 1;
+      else if (strcmp (s, "sh") == 0)
+	v->shared_mapping = 1;
+    }
+}
+
+/* Return 1 if the memory mapping is anonymous, 0 otherwise.
+
+   FILENAME is the name of the file present in the first line of the
+   memory mapping, in the "/proc/PID/smaps" output.  For example, if
+   the first line is:
+
+   7fd0ca877000-7fd0d0da0000 r--p 00000000 fd:02 2100770   /path/to/file
+
+   Then FILENAME will be "/path/to/file".  */
+
+static int
+mapping_is_anonymous_p (const char *filename)
+{
+  static regex_t dev_zero_regex, shmem_file_regex, file_deleted_regex;
+  static int init_regex_p = 0;
+
+  if (!init_regex_p)
+    {
+      struct cleanup *c = make_cleanup (null_cleanup, NULL);
+
+      /* Let's be pessimistic and assume there will be an error while
+	 compiling the regex'es.  */
+      init_regex_p = -1;
+
+      /* DEV_ZERO_REGEX matches "/dev/zero" filenames (with or
+	 without the "(deleted)" string in the end).  We know for
+	 sure, based on the Linux kernel code, that memory mappings
+	 whose associated filename is "/dev/zero" are guaranteed to be
+	 MAP_ANONYMOUS.  */
+      compile_rx_or_error (&dev_zero_regex, "^/dev/zero\\( (deleted)\\)\\?$",
+			   _("Could not compile regex to match /dev/zero "
+			     "filename"));
+      /* SHMEM_FILE_REGEX matches "/SYSV%08x" filenames (with or
+	 without the "(deleted)" string in the end).  These filenames
+	 refer to shared memory (shmem), and memory mappings
+	 associated with them are MAP_ANONYMOUS as well.  */
+      compile_rx_or_error (&shmem_file_regex,
+			   "^/\\?SYSV[0-9a-fA-F]\\{8\\}\\( (deleted)\\)\\?$",
+			   _("Could not compile regex to match shmem "
+			     "filenames"));
+      /* FILE_DELETED_REGEX is a heuristic we use to try to mimic the
+	 Linux kernel's 'n_link == 0' code, which is responsible to
+	 decide if it is dealing with a 'MAP_SHARED | MAP_ANONYMOUS'
+	 mapping.  In other words, if FILE_DELETED_REGEX matches, it
+	 does not necessarily mean that we are dealing with an
+	 anonymous shared mapping.  However, there is no easy way to
+	 detect this currently, so this is the best approximation we
+	 have.
+
+	 As a result, GDB will dump readonly pages of deleted
+	 executables when using the default value of coredump_filter
+	 (0x33), while the Linux kernel will not dump those pages.
+	 But we can live with that.  */
+      compile_rx_or_error (&file_deleted_regex, " (deleted)$",
+			   _("Could not compile regex to match "
+			     "'<file> (deleted)'"));
+      /* We will never release these regexes, so just discard the
+	 cleanups.  */
+      discard_cleanups (c);
+
+      /* If we reached this point, then everything succeeded.  */
+      init_regex_p = 1;
+    }
+
+  if (init_regex_p == -1)
+    {
+      const char deleted[] = " (deleted)";
+      size_t del_len = sizeof (deleted) - 1;
+      size_t filename_len = strlen (filename);
+
+      /* There was an error while compiling the regex'es above.  In
+	 order to try to give some reliable information to the caller,
+	 we just try to find the string " (deleted)" in the filename.
+	 If we managed to find it, then we assume the mapping is
+	 anonymous.  */
+      return (filename_len >= del_len
+	      && strcmp (filename + filename_len - del_len, deleted) == 0);
+    }
+
+  if (*filename == '\0'
+      || regexec (&dev_zero_regex, filename, 0, NULL, 0) == 0
+      || regexec (&shmem_file_regex, filename, 0, NULL, 0) == 0
+      || regexec (&file_deleted_regex, filename, 0, NULL, 0) == 0)
+    return 1;
+
+  return 0;
+}
+
+/* Return 0 if the memory mapping (which is related to FILTERFLAGS, V,
+   MAYBE_PRIVATE_P, and MAPPING_ANONYMOUS_P) should not be dumped, or
+   greater than 0 if it should.
+
+   In a nutshell, this is the logic that we follow in order to decide
+   if a mapping should be dumped or not.
+
+   - If the mapping is associated to a file whose name ends with
+     " (deleted)", or if the file is "/dev/zero", or if it is
+     "/SYSV%08x" (shared memory), or if there is no file associated
+     with it, or if the AnonHugePages: or the Anonymous: fields in the
+     /proc/PID/smaps have contents, then GDB considers this mapping to
+     be anonymous.  Otherwise, GDB considers this mapping to be a
+     file-backed mapping (because there will be a file associated with
+     it).
+ 
+     It is worth mentioning that, from all those checks described
+     above, the most fragile is the one to see if the file name ends
+     with " (deleted)".  This does not necessarily mean that the
+     mapping is anonymous, because the deleted file associated with
+     the mapping may have been a hard link to another file, for
+     example.  The Linux kernel checks to see if "i_nlink == 0", but
+     GDB cannot easily do this check.  Therefore, we made a compromise
+     here, and we assume that if the file name ends with " (deleted)",
+     then the mapping is indeed anonymous.  FWIW, this is something
+     the Linux kernel could do better: expose this information in a
+     more direct way.
+ 
+   - If we see the flag "sh" in the "VmFlags:" field (in
+     /proc/PID/smaps), then certainly the memory mapping is shared
+     (VM_SHARED).  If we have access to the VmFlags, and we don't see
+     the "sh" there, then certainly the mapping is private.  However,
+     Linux kernels before commit
+     834f82e2aa9a8ede94b17b656329f850c1471514 (3.10) do not have the
+     "VmFlags:" field; in that case, we use another heuristic: if we
+     see 'p' in the permission flags, then we assume that the mapping
+     is private, even though the presence of the 's' flag there would
+     mean VM_MAYSHARE, which means the mapping could still be private.
+     This should work OK enough, however.  */
+
+static int
+dump_mapping_p (unsigned int filterflags, const struct smaps_vmflags *v,
+		int maybe_private_p, int mapping_anon_p, const char *filename)
+{
+  /* Initially, we trust in what we received from our caller.  This
+     value may not be very precise (i.e., it was probably gathered
+     from the permission line in the /proc/PID/smaps list, which
+     actually refers to VM_MAYSHARE, and not VM_SHARED), but it is
+     what we have until we take a look at the "VmFlags:" field
+     (assuming that the version of the Linux kernel being used
+     supports it, of course).  */
+  int private_p = maybe_private_p;
+
+  /* We always dump vDSO and vsyscall mappings, because it's likely that
+     there'll be no file to read the contents from at core load time.
+     The kernel does the same.  */
+  if (strcmp ("[vdso]", filename) == 0
+      || strcmp ("[vsyscall]", filename) == 0)
+    return 1;
+
+  if (v->initialized_p)
+    {
+      /* We never dump I/O mappings.  */
+      if (v->io_page)
+	return 0;
+
+      /* Check if we should exclude this mapping.  */
+      if (v->exclude_coredump)
+	return 0;
+
+      /* Update our notion of whether this mapping is shared or
+	 private based on a trustworthy value.  */
+      private_p = !v->shared_mapping;
+
+      /* HugeTLB checking.  */
+      if (v->uses_huge_tlb)
+	{
+	  if ((private_p && (filterflags & COREFILTER_HUGETLB_PRIVATE))
+	      || (!private_p && (filterflags & COREFILTER_HUGETLB_SHARED)))
+	    return 1;
+
+	  return 0;
+	}
+    }
+
+  if (private_p)
+    {
+      if (mapping_anon_p)
+	return (filterflags & COREFILTER_ANON_PRIVATE) != 0;
+      else
+	return (filterflags & COREFILTER_MAPPED_PRIVATE) != 0;
+    }
+  else
+    {
+      if (mapping_anon_p)
+	return (filterflags & COREFILTER_ANON_SHARED) != 0;
+      else
+	return (filterflags & COREFILTER_MAPPED_SHARED) != 0;
+    }
+}
+
 /* Implement the "info proc" command.  */
 
 static void
@@ -819,48 +1094,86 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
 				void *obfd)
 {
   char mapsfilename[100];
-  char *data;
+  char coredumpfilter_name[100];
+  char *data, *coredumpfilterdata;
+  pid_t pid;
+  /* Default dump behavior of coredump_filter (0x33), according to
+     Documentation/filesystems/proc.txt from the Linux kernel
+     tree.  */
+  unsigned int filterflags = (COREFILTER_ANON_PRIVATE
+			      | COREFILTER_ANON_SHARED
+			      | COREFILTER_ELF_HEADERS
+			      | COREFILTER_HUGETLB_PRIVATE);
 
   /* We need to know the real target PID to access /proc.  */
   if (current_inferior ()->fake_pid_p)
     return 1;
 
-  xsnprintf (mapsfilename, sizeof mapsfilename,
-	     "/proc/%d/smaps", current_inferior ()->pid);
+  pid = current_inferior ()->pid;
+
+  if (use_coredump_filter)
+    {
+      xsnprintf (coredumpfilter_name, sizeof (coredumpfilter_name),
+		 "/proc/%d/coredump_filter", pid);
+      coredumpfilterdata = target_fileio_read_stralloc (coredumpfilter_name);
+      if (coredumpfilterdata != NULL)
+	{
+	  sscanf (coredumpfilterdata, "%x", &filterflags);
+	  xfree (coredumpfilterdata);
+	}
+    }
+
+  xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/smaps", pid);
   data = target_fileio_read_stralloc (mapsfilename);
   if (data == NULL)
     {
       /* Older Linux kernels did not support /proc/PID/smaps.  */
-      xsnprintf (mapsfilename, sizeof mapsfilename,
-		 "/proc/%d/maps", current_inferior ()->pid);
+      xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/maps", pid);
       data = target_fileio_read_stralloc (mapsfilename);
     }
-  if (data)
+
+  if (data != NULL)
     {
       struct cleanup *cleanup = make_cleanup (xfree, data);
-      char *line;
+      char *line, *t;
 
-      line = strtok (data, "\n");
-      while (line)
+      line = strtok_r (data, "\n", &t);
+      while (line != NULL)
 	{
 	  ULONGEST addr, endaddr, offset, inode;
 	  const char *permissions, *device, *filename;
+	  struct smaps_vmflags v;
 	  size_t permissions_len, device_len;
-	  int read, write, exec;
-	  int modified = 0, has_anonymous = 0;
+	  int read, write, exec, private;
+	  int has_anonymous = 0;
+	  int should_dump_p = 0;
+	  int mapping_anon_p;
 
+	  memset (&v, 0, sizeof (v));
 	  read_mapping (line, &addr, &endaddr, &permissions, &permissions_len,
 			&offset, &device, &device_len, &inode, &filename);
+	  mapping_anon_p = mapping_is_anonymous_p (filename);
 
 	  /* Decode permissions.  */
 	  read = (memchr (permissions, 'r', permissions_len) != 0);
 	  write = (memchr (permissions, 'w', permissions_len) != 0);
 	  exec = (memchr (permissions, 'x', permissions_len) != 0);
-
-	  /* Try to detect if region was modified by parsing smaps counters.  */
-	  for (line = strtok (NULL, "\n");
-	       line && line[0] >= 'A' && line[0] <= 'Z';
-	       line = strtok (NULL, "\n"))
+	  /* 'private' here actually means VM_MAYSHARE, and not
+	     VM_SHARED.  In order to know if a mapping is really
+	     private or not, we must check the flag "sh" in the
+	     VmFlags field.  This is done by decode_vmflags.  However,
+	     if we are using a Linux kernel released before the commit
+	     834f82e2aa9a8ede94b17b656329f850c1471514 (3.10), we will
+	     not have the VmFlags there.  In this case, there is
+	     really no way to know if we are dealing with VM_SHARED,
+	     so we just assume that VM_MAYSHARE is enough.  */
+	  private = memchr (permissions, 'p', permissions_len) != 0;
+
+	  /* Try to detect if region should be dumped by parsing smaps
+	     counters.  */
+	  for (line = strtok_r (NULL, "\n", &t);
+	       line != NULL && line[0] >= 'A' && line[0] <= 'Z';
+	       line = strtok_r (NULL, "\n", &t))
 	    {
 	      char keyword[64 + 1];
 
@@ -869,11 +1182,17 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
 		  warning (_("Error parsing {s,}maps file '%s'"), mapsfilename);
 		  break;
 		}
+
 	      if (strcmp (keyword, "Anonymous:") == 0)
-		has_anonymous = 1;
-	      if (strcmp (keyword, "Shared_Dirty:") == 0
-		  || strcmp (keyword, "Private_Dirty:") == 0
-		  || strcmp (keyword, "Swap:") == 0
+		{
+		  /* Older Linux kernels did not support the
+		     "Anonymous:" counter.  Check it here.  */
+		  has_anonymous = 1;
+		}
+	      else if (strcmp (keyword, "VmFlags:") == 0)
+		decode_vmflags (line, &v);
+
+	      if (strcmp (keyword, "AnonHugePages:") == 0
 		  || strcmp (keyword, "Anonymous:") == 0)
 		{
 		  unsigned long number;
@@ -884,19 +1203,38 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
 			       mapsfilename);
 		      break;
 		    }
-		  if (number != 0)
-		    modified = 1;
+		  if (number > 0)
+		    {
+		      /* Even if we are dealing with a file-backed
+			 mapping, if it contains anonymous pages we
+			 consider it to be an anonymous mapping,
+			 because this is what the Linux kernel does:
+
+			 // Dump segments that have been written to.
+			 if (vma->anon_vma && FILTER(ANON_PRIVATE))
+			 	goto whole;
+		      */
+		      mapping_anon_p = 1;
+		    }
 		}
 	    }
 
-	  /* Older Linux kernels did not support the "Anonymous:" counter.
-	     If it is missing, we can't be sure - dump all the pages.  */
-	  if (!has_anonymous)
-	    modified = 1;
+	  if (has_anonymous)
+	    should_dump_p = dump_mapping_p (filterflags, &v, private,
+					    mapping_anon_p, filename);
+	  else
+	    {
+	      /* Older Linux kernels did not support the "Anonymous:" counter.
+		 If it is missing, we can't be sure - dump all the pages.  */
+	      should_dump_p = 1;
+	    }
 
 	  /* Invoke the callback function to create the corefile segment.  */
-	  func (addr, endaddr - addr, offset, inode,
-		read, write, exec, modified, filename, obfd);
+	  if (should_dump_p)
+	    func (addr, endaddr - addr, offset, inode,
+		  read, write, exec, 1, /* MODIFIED is true because we
+					   want to dump the mapping.  */
+		  filename, obfd);
 	}
 
       do_cleanups (cleanup);
@@ -1972,6 +2310,17 @@ linux_infcall_mmap (CORE_ADDR size, unsigned prot)
   return retval;
 }
 
+/* Display whether the gcore command is using the
+   /proc/PID/coredump_filter file.  */
+
+static void
+show_use_coredump_filter (struct ui_file *file, int from_tty,
+			  struct cmd_list_element *c, const char *value)
+{
+  fprintf_filtered (file, _("Use of /proc/PID/coredump_filter file to generate"
+			    " corefiles is %s.\n"), value);
+}
+
 /* To be called from the various GDB_OSABI_LINUX handlers for the
    various GNU/Linux architectures and machine types.  */
 
@@ -2008,4 +2357,16 @@ _initialize_linux_tdep (void)
   /* Observers used to invalidate the cache when needed.  */
   observer_attach_inferior_exit (invalidate_linux_cache_inf);
   observer_attach_inferior_appeared (invalidate_linux_cache_inf);
+
+  add_setshow_boolean_cmd ("use-coredump-filter", class_files,
+			   &use_coredump_filter, _("\
+Set whether gcore should consider /proc/PID/coredump_filter."),
+			   _("\
+Show whether gcore should consider /proc/PID/coredump_filter."),
+			   _("\
+Use this command to set whether gcore should consider the contents\n\
+of /proc/PID/coredump_filter when generating the corefile.  For more information\n\
+about this file, refer to the manpage of core(5)."),
+			   NULL, show_use_coredump_filter,
+			   &setlist, &showlist);
 }

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/2] Implement support for checking /proc/PID/coredump_filter
  2015-03-19 23:22 ` [PATCH 1/2] Implement support for checking /proc/PID/coredump_filter Sergio Durigan Junior
@ 2015-03-20 19:12   ` Pedro Alves
  2015-03-20 20:02     ` Sergio Durigan Junior
  0 siblings, 1 reply; 21+ messages in thread
From: Pedro Alves @ 2015-03-20 19:12 UTC (permalink / raw)
  To: Sergio Durigan Junior, GDB Patches

Thanks, this looks good to me now, just a few minor nits.

On 03/19/2015 11:22 PM, Sergio Durigan Junior wrote:

> +/* Helper function to decode the "VmFlags" field in /proc/PID/smaps.
> +
> +   This function was based on the documentation found on
> +   <Documentation/filesystems/proc.txt>, on the Linux kernel.
> +
> +   Linux kernels before commit
> +   834f82e2aa9a8ede94b17b656329f850c1471514 do not have this field on
> +   smaps.  */

Thanks for the version info.  Ideally, what I'd like with these version notes
is at any point in the time in the future being able to look at the code
and easily identify whether we're working around an old enough kernel that
we potentially can stop worrying about backwards compatibility with
such kernel.  If easy, could you also add the kernel version, like
e.g., "$hash (x.y.z)"?

> +  if (init_regex_p == -1)
> +    {
> +      /* There was an error while compiling the regex'es above.  In
> +	 order to try to give some reliable information to the caller,
> +	 we just try to find the string "(deleted)" in the filename.
> +	 If we managed to find it, then we assume the mapping is
> +	 anonymous.  */
> +      return strstr (filename, "(deleted)") != NULL;

Might as well add the space before parens, and match tail
end only, like e.g.,:

   const char deleted[] = " (deleted)";
   size_t del_len = strlen (deleted);
   size_t filename_len = strlen (filename);

   return (filename_len >= del_len
           && strcmp (filename + filename_len - del_len, deleted) == 0);

> +
> +/* Return 0 if the memory mapping (which is related to FILTERFLAGS, V,
> +   MAYBE_PRIVATE_P, and MAPPING_ANONYMOUS_P) should not be dumped, or
> +   greater than 0 if it should.
> +
> +   In a nutshell, this is the logic that we follow in order to decide
> +   if a mapping should be dumped or not.
> +
> +   - If the mapping is associated to a file whose name ends with "
> +     (deleted)"

Nit: it'd be good to avoid breaking " (deleted)" over two lines.

        > , or if the file is "/dev/zero", or if it is
> +     "/SYSV%08x" (shared memory), or if there is no file associated
> +     with it, or if the AnonHugePages: or the Anonymous: fields in the
> +     /proc/PID/smaps have contents, then GDB considers this mapping to
> +     be anonymous.  Otherwise, GDB considers this mapping to be a
> +     file-backed mapping (because there will be a file associated with
> +     it).
> + 
> +     It is worth mentioning that, from all those checks described
> +     above, the most fragile is the one to see if the file name ends
> +     with " (deleted)".  This does not necessarily mean that the
> +     mapping is anonymous, because the deleted file associated with
> +     the mapping may have been a hard link to another file, for
> +     example.  The Linux kernel checks to see if "i_nlink == 0", but
> +     GDB cannot easily do this check.  Therefore, we made a compromise

Cannot do it easily, or cannot do it at all?

> +     here, and we assume that if the file name ends with " (deleted)",
> +     then the mapping is indeed anonymous.  FWIW, this is something
> +     the Linux kernel could do better: expose this information in a
> +     more direct way.
> + 
> +   - If we see the flag "sh" in the "VmFlags:" field (in
> +     /proc/PID/smaps), then certainly the memory mapping is shared
> +     (VM_SHARED).  If we have access to the VmFlags, and we don't see
> +     the "sh" there, then certainly the mapping is private.  However,
> +     Linux kernels before commit
> +     834f82e2aa9a8ede94b17b656329f850c1471514 do not have the
> +     "VmFlags:" field; in that case, we use another heuristic: if we
> +     see 'p' in the permission flags, then we assume that the mapping
> +     is private, even though the presence of the 's' flag there would
> +     mean VM_MAYSHARE, which means the mapping could still be private.
> +     This should work OK enough, however.  */
> +
> +static int
> +dump_mapping_p (unsigned int filterflags, const struct smaps_vmflags *v,
> +		int maybe_private_p, int mapping_anon_p, const char *filename)
> +{
> +  /* Initially, we trust in what we received from outside.  This value

outside == the caller?  or the kernel?  The former, right?

> +     may not be very precise (i.e., it was probably gathered from the
> +     permission line in the /proc/PID/smaps list, which actually
> +     refers to VM_MAYSHARE, and not VM_SHARED), but it is what we have
> +     for now.  */

"for now" refers to the flag being updated further down, or future
kernel versions?

> +  int private_p = maybe_private_p;
> +
> +  /* We always dump vDSO and vsyscall mappings.  */

Suggest:

   /* We always dump vDSO and vsyscall mappings, because it's likely that
      there'll be no file to read the contents from at core load time.
      The kernel does the same.  */

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH 1/2] Implement support for checking /proc/PID/coredump_filter
  2015-03-19 23:22 [PATCH v4 0/2] Improve corefile generation by using /proc/PID/coredump_filter (PR corefile/16902) Sergio Durigan Junior
@ 2015-03-19 23:22 ` Sergio Durigan Junior
  2015-03-20 19:12   ` Pedro Alves
  0 siblings, 1 reply; 21+ messages in thread
From: Sergio Durigan Junior @ 2015-03-19 23:22 UTC (permalink / raw)
  To: GDB Patches; +Cc: Pedro Alves, Sergio Durigan Junior

This is the core patch.  It implements the support for honoring the
/proc/PID/coredump_filter file.

Changes from v3:

  - Removed the new 'enum memory_mapping_state'; now
    linux_find_memory_regions_full is either calling
    gcore_create_callback when the mapping should be dumped (with
    'modified = 1'), or not calling the function at all.

  - Reviewed comments.  Added new variable 'should_dump_p', and
    removed 'modified' from linux_find_memory_regions_full.

gdb/ChangeLog:
2015-03-19  Sergio Durigan Junior  <sergiodj@redhat.com>
	    Jan Kratochvil  <jan.kratochvil@redhat.com>
	    Oleg Nesterov  <oleg@redhat.com>

	PR corefiles/16092
	* linux-tdep.c: Include 'gdbcmd.h' and 'gdb_regex.h'.
	New enum identifying the various options of the coredump_filter
	file.
	(struct smaps_vmflags): New struct.
	(use_coredump_filter): New variable.
	(decode_vmflags): New function.
	(mapping_is_anonymous_p): Likewise.
	(dump_mapping_p): Likewise.
	(linux_find_memory_regions_full): New variables
	'coredumpfilter_name', 'coredumpfilterdata', 'pid', 'filterflags',
	'should_dump_p'.  Removed variable 'modified'.  Read
	/proc/<PID>/smaps file; improve parsing of its information.
	Implement memory mapping filtering based on its contents.
	(show_use_coredump_filter): New function.
	(_initialize_linux_tdep): New command 'set use-coredump-filter'.
---
 gdb/linux-tdep.c | 408 +++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 380 insertions(+), 28 deletions(-)

diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index ea0d4cd..3831580 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -35,9 +35,61 @@
 #include "observer.h"
 #include "objfiles.h"
 #include "infcall.h"
+#include "gdbcmd.h"
+#include "gdb_regex.h"
 
 #include <ctype.h>
 
+/* This enum represents the values that the user can choose when
+   informing the Linux kernel about which memory mappings will be
+   dumped in a corefile.  They are described in the file
+   Documentation/filesystems/proc.txt, inside the Linux kernel
+   tree.  */
+
+enum
+  {
+    COREFILTER_ANON_PRIVATE = 1 << 0,
+    COREFILTER_ANON_SHARED = 1 << 1,
+    COREFILTER_MAPPED_PRIVATE = 1 << 2,
+    COREFILTER_MAPPED_SHARED = 1 << 3,
+    COREFILTER_ELF_HEADERS = 1 << 4,
+    COREFILTER_HUGETLB_PRIVATE = 1 << 5,
+    COREFILTER_HUGETLB_SHARED = 1 << 6,
+  };
+
+/* This struct is used to map flags found in the "VmFlags:" field (in
+   the /proc/<PID>/smaps file).  */
+
+struct smaps_vmflags
+  {
+    /* Zero if this structure has not been initialized yet.  It
+       probably means that the Linux kernel being used does not emit
+       the "VmFlags:" field on "/proc/PID/smaps".  */
+
+    unsigned int initialized_p : 1;
+
+    /* Memory mapped I/O area (VM_IO, "io").  */
+
+    unsigned int io_page : 1;
+
+    /* Area uses huge TLB pages (VM_HUGETLB, "ht").  */
+
+    unsigned int uses_huge_tlb : 1;
+
+    /* Do not include this memory region on the coredump (VM_DONTDUMP, "dd").  */
+
+    unsigned int exclude_coredump : 1;
+
+    /* Is this a MAP_SHARED mapping (VM_SHARED, "sh").  */
+
+    unsigned int shared_mapping : 1;
+  };
+
+/* Whether to take the /proc/PID/coredump_filter into account when
+   generating a corefile.  */
+
+static int use_coredump_filter = 1;
+
 /* This enum represents the signals' numbers on a generic architecture
    running the Linux kernel.  The definition of "generic" comes from
    the file <include/uapi/asm-generic/signal.h>, from the Linux kernel
@@ -381,6 +433,220 @@ read_mapping (const char *line,
   *filename = p;
 }
 
+/* Helper function to decode the "VmFlags" field in /proc/PID/smaps.
+
+   This function was based on the documentation found on
+   <Documentation/filesystems/proc.txt>, on the Linux kernel.
+
+   Linux kernels before commit
+   834f82e2aa9a8ede94b17b656329f850c1471514 do not have this field on
+   smaps.  */
+
+static void
+decode_vmflags (char *p, struct smaps_vmflags *v)
+{
+  char *saveptr;
+  const char *s;
+
+  v->initialized_p = 1;
+  p = skip_to_space (p);
+  p = skip_spaces (p);
+
+  for (s = strtok_r (p, " ", &saveptr);
+       s != NULL;
+       s = strtok_r (NULL, " ", &saveptr))
+    {
+      if (strcmp (s, "io") == 0)
+	v->io_page = 1;
+      else if (strcmp (s, "ht") == 0)
+	v->uses_huge_tlb = 1;
+      else if (strcmp (s, "dd") == 0)
+	v->exclude_coredump = 1;
+      else if (strcmp (s, "sh") == 0)
+	v->shared_mapping = 1;
+    }
+}
+
+/* Return 1 if the memory mapping is anonymous, 0 otherwise.
+
+   FILENAME is the name of the file present in the first line of the
+   memory mapping, in the "/proc/PID/smaps" output.  For example, if
+   the first line is:
+
+   7fd0ca877000-7fd0d0da0000 r--p 00000000 fd:02 2100770   /path/to/file
+
+   Then FILENAME will be "/path/to/file".  */
+
+static int
+mapping_is_anonymous_p (const char *filename)
+{
+  static regex_t dev_zero_regex, shmem_file_regex, file_deleted_regex;
+  static int init_regex_p = 0;
+
+  if (!init_regex_p)
+    {
+      struct cleanup *c = make_cleanup (null_cleanup, NULL);
+
+      /* Let's be pessimistic and assume there will be an error while
+	 compiling the regex'es.  */
+      init_regex_p = -1;
+
+      /* DEV_ZERO_REGEX matches "/dev/zero" filenames (with or
+	 without the "(deleted)" string in the end).  We know for
+	 sure, based on the Linux kernel code, that memory mappings
+	 whose associated filename is "/dev/zero" are guaranteed to be
+	 MAP_ANONYMOUS.  */
+      compile_rx_or_error (&dev_zero_regex, "^/dev/zero\\( (deleted)\\)\\?$",
+			   _("Could not compile regex to match /dev/zero "
+			     "filename"));
+      /* SHMEM_FILE_REGEX matches "/SYSV%08x" filenames (with or
+	 without the "(deleted)" string in the end).  These filenames
+	 refer to shared memory (shmem), and memory mappings
+	 associated with them are MAP_ANONYMOUS as well.  */
+      compile_rx_or_error (&shmem_file_regex,
+			   "^/\\?SYSV[0-9a-fA-F]\\{8\\}\\( (deleted)\\)\\?$",
+			   _("Could not compile regex to match shmem "
+			     "filenames"));
+      /* FILE_DELETED_REGEX is a heuristic we use to try to mimic the
+	 Linux kernel's 'n_link == 0' code, which is responsible to
+	 decide if it is dealing with a 'MAP_SHARED | MAP_ANONYMOUS'
+	 mapping.  In other words, if FILE_DELETED_REGEX matches, it
+	 does not necessarily mean that we are dealing with an
+	 anonymous shared mapping.  However, there is no easy way to
+	 detect this currently, so this is the best approximation we
+	 have.
+
+	 As a result, GDB will dump readonly pages of deleted
+	 executables when using the default value of coredump_filter
+	 (0x33), while the Linux kernel will not dump those pages.
+	 But we can live with that.  */
+      compile_rx_or_error (&file_deleted_regex, " (deleted)$",
+			   _("Could not compile regex to match "
+			     "'<file> (deleted)'"));
+      /* We will never release these regexes, so just discard the
+	 cleanups.  */
+      discard_cleanups (c);
+
+      /* If we reached this point, then everything succeeded.  */
+      init_regex_p = 1;
+    }
+
+  if (init_regex_p == -1)
+    {
+      /* There was an error while compiling the regex'es above.  In
+	 order to try to give some reliable information to the caller,
+	 we just try to find the string "(deleted)" in the filename.
+	 If we managed to find it, then we assume the mapping is
+	 anonymous.  */
+      return strstr (filename, "(deleted)") != NULL;
+    }
+
+  if (*filename == '\0'
+      || regexec (&dev_zero_regex, filename, 0, NULL, 0) == 0
+      || regexec (&shmem_file_regex, filename, 0, NULL, 0) == 0
+      || regexec (&file_deleted_regex, filename, 0, NULL, 0) == 0)
+    return 1;
+
+  return 0;
+}
+
+/* Return 0 if the memory mapping (which is related to FILTERFLAGS, V,
+   MAYBE_PRIVATE_P, and MAPPING_ANONYMOUS_P) should not be dumped, or
+   greater than 0 if it should.
+
+   In a nutshell, this is the logic that we follow in order to decide
+   if a mapping should be dumped or not.
+
+   - If the mapping is associated to a file whose name ends with "
+     (deleted)", or if the file is "/dev/zero", or if it is
+     "/SYSV%08x" (shared memory), or if there is no file associated
+     with it, or if the AnonHugePages: or the Anonymous: fields in the
+     /proc/PID/smaps have contents, then GDB considers this mapping to
+     be anonymous.  Otherwise, GDB considers this mapping to be a
+     file-backed mapping (because there will be a file associated with
+     it).
+ 
+     It is worth mentioning that, from all those checks described
+     above, the most fragile is the one to see if the file name ends
+     with " (deleted)".  This does not necessarily mean that the
+     mapping is anonymous, because the deleted file associated with
+     the mapping may have been a hard link to another file, for
+     example.  The Linux kernel checks to see if "i_nlink == 0", but
+     GDB cannot easily do this check.  Therefore, we made a compromise
+     here, and we assume that if the file name ends with " (deleted)",
+     then the mapping is indeed anonymous.  FWIW, this is something
+     the Linux kernel could do better: expose this information in a
+     more direct way.
+ 
+   - If we see the flag "sh" in the "VmFlags:" field (in
+     /proc/PID/smaps), then certainly the memory mapping is shared
+     (VM_SHARED).  If we have access to the VmFlags, and we don't see
+     the "sh" there, then certainly the mapping is private.  However,
+     Linux kernels before commit
+     834f82e2aa9a8ede94b17b656329f850c1471514 do not have the
+     "VmFlags:" field; in that case, we use another heuristic: if we
+     see 'p' in the permission flags, then we assume that the mapping
+     is private, even though the presence of the 's' flag there would
+     mean VM_MAYSHARE, which means the mapping could still be private.
+     This should work OK enough, however.  */
+
+static int
+dump_mapping_p (unsigned int filterflags, const struct smaps_vmflags *v,
+		int maybe_private_p, int mapping_anon_p, const char *filename)
+{
+  /* Initially, we trust in what we received from outside.  This value
+     may not be very precise (i.e., it was probably gathered from the
+     permission line in the /proc/PID/smaps list, which actually
+     refers to VM_MAYSHARE, and not VM_SHARED), but it is what we have
+     for now.  */
+  int private_p = maybe_private_p;
+
+  /* We always dump vDSO and vsyscall mappings.  */
+  if (strcmp ("[vdso]", filename) == 0
+      || strcmp ("[vsyscall]", filename) == 0)
+    return 1;
+
+  if (v->initialized_p)
+    {
+      /* We never dump I/O mappings.  */
+      if (v->io_page)
+	return 0;
+
+      /* Check if we should exclude this mapping.  */
+      if (v->exclude_coredump)
+	return 0;
+
+      /* Update our notion of whether this mapping is shared or
+	 private based on a trustworthy value.  */
+      private_p = !v->shared_mapping;
+
+      /* HugeTLB checking.  */
+      if (v->uses_huge_tlb)
+	{
+	  if ((private_p && (filterflags & COREFILTER_HUGETLB_PRIVATE))
+	      || (!private_p && (filterflags & COREFILTER_HUGETLB_SHARED)))
+	    return 1;
+
+	  return 0;
+	}
+    }
+
+  if (private_p)
+    {
+      if (mapping_anon_p)
+	return (filterflags & COREFILTER_ANON_PRIVATE) != 0;
+      else
+	return (filterflags & COREFILTER_MAPPED_PRIVATE) != 0;
+    }
+  else
+    {
+      if (mapping_anon_p)
+	return (filterflags & COREFILTER_ANON_SHARED) != 0;
+      else
+	return (filterflags & COREFILTER_MAPPED_SHARED) != 0;
+    }
+}
+
 /* Implement the "info proc" command.  */
 
 static void
@@ -819,48 +1085,86 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
 				void *obfd)
 {
   char mapsfilename[100];
-  char *data;
+  char coredumpfilter_name[100];
+  char *data, *coredumpfilterdata;
+  pid_t pid;
+  /* Default dump behavior of coredump_filter (0x33), according to
+     Documentation/filesystems/proc.txt from the Linux kernel
+     tree.  */
+  unsigned int filterflags = (COREFILTER_ANON_PRIVATE
+			      | COREFILTER_ANON_SHARED
+			      | COREFILTER_ELF_HEADERS
+			      | COREFILTER_HUGETLB_PRIVATE);
 
   /* We need to know the real target PID to access /proc.  */
   if (current_inferior ()->fake_pid_p)
     return 1;
 
-  xsnprintf (mapsfilename, sizeof mapsfilename,
-	     "/proc/%d/smaps", current_inferior ()->pid);
+  pid = current_inferior ()->pid;
+
+  if (use_coredump_filter)
+    {
+      xsnprintf (coredumpfilter_name, sizeof (coredumpfilter_name),
+		 "/proc/%d/coredump_filter", pid);
+      coredumpfilterdata = target_fileio_read_stralloc (coredumpfilter_name);
+      if (coredumpfilterdata != NULL)
+	{
+	  sscanf (coredumpfilterdata, "%x", &filterflags);
+	  xfree (coredumpfilterdata);
+	}
+    }
+
+  xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/smaps", pid);
   data = target_fileio_read_stralloc (mapsfilename);
   if (data == NULL)
     {
       /* Older Linux kernels did not support /proc/PID/smaps.  */
-      xsnprintf (mapsfilename, sizeof mapsfilename,
-		 "/proc/%d/maps", current_inferior ()->pid);
+      xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/maps", pid);
       data = target_fileio_read_stralloc (mapsfilename);
     }
-  if (data)
+
+  if (data != NULL)
     {
       struct cleanup *cleanup = make_cleanup (xfree, data);
-      char *line;
+      char *line, *t;
 
-      line = strtok (data, "\n");
-      while (line)
+      line = strtok_r (data, "\n", &t);
+      while (line != NULL)
 	{
 	  ULONGEST addr, endaddr, offset, inode;
 	  const char *permissions, *device, *filename;
+	  struct smaps_vmflags v;
 	  size_t permissions_len, device_len;
-	  int read, write, exec;
-	  int modified = 0, has_anonymous = 0;
+	  int read, write, exec, private;
+	  int has_anonymous = 0;
+	  int should_dump_p = 0;
+	  int mapping_anon_p;
 
+	  memset (&v, 0, sizeof (v));
 	  read_mapping (line, &addr, &endaddr, &permissions, &permissions_len,
 			&offset, &device, &device_len, &inode, &filename);
+	  mapping_anon_p = mapping_is_anonymous_p (filename);
 
 	  /* Decode permissions.  */
 	  read = (memchr (permissions, 'r', permissions_len) != 0);
 	  write = (memchr (permissions, 'w', permissions_len) != 0);
 	  exec = (memchr (permissions, 'x', permissions_len) != 0);
-
-	  /* Try to detect if region was modified by parsing smaps counters.  */
-	  for (line = strtok (NULL, "\n");
-	       line && line[0] >= 'A' && line[0] <= 'Z';
-	       line = strtok (NULL, "\n"))
+	  /* 'private' here actually means VM_MAYSHARE, and not
+	     VM_SHARED.  In order to know if a mapping is really
+	     private or not, we must check the flag "sh" in the
+	     VmFlags field.  This is done by decode_vmflags.  However,
+	     if we are using a Linux kernel released before the commit
+	     834f82e2aa9a8ede94b17b656329f850c1471514, we will not
+	     have the VmFlags there.  In this case, there is really no
+	     way to know if we are dealing with VM_SHARED, so we just
+	     assume that VM_MAYSHARE is enough.  */
+	  private = memchr (permissions, 'p', permissions_len) != 0;
+
+	  /* Try to detect if region should be dumped by parsing smaps
+	     counters.  */
+	  for (line = strtok_r (NULL, "\n", &t);
+	       line != NULL && line[0] >= 'A' && line[0] <= 'Z';
+	       line = strtok_r (NULL, "\n", &t))
 	    {
 	      char keyword[64 + 1];
 
@@ -869,11 +1173,17 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
 		  warning (_("Error parsing {s,}maps file '%s'"), mapsfilename);
 		  break;
 		}
+
 	      if (strcmp (keyword, "Anonymous:") == 0)
-		has_anonymous = 1;
-	      if (strcmp (keyword, "Shared_Dirty:") == 0
-		  || strcmp (keyword, "Private_Dirty:") == 0
-		  || strcmp (keyword, "Swap:") == 0
+		{
+		  /* Older Linux kernels did not support the
+		     "Anonymous:" counter.  Check it here.  */
+		  has_anonymous = 1;
+		}
+	      else if (strcmp (keyword, "VmFlags:") == 0)
+		decode_vmflags (line, &v);
+
+	      if (strcmp (keyword, "AnonHugePages:") == 0
 		  || strcmp (keyword, "Anonymous:") == 0)
 		{
 		  unsigned long number;
@@ -884,19 +1194,38 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
 			       mapsfilename);
 		      break;
 		    }
-		  if (number != 0)
-		    modified = 1;
+		  if (number > 0)
+		    {
+		      /* Even if we are dealing with a file-backed
+			 mapping, if it contains anonymous pages we
+			 consider it to be an anonymous mapping,
+			 because this is what the Linux kernel does:
+
+			 // Dump segments that have been written to.
+			 if (vma->anon_vma && FILTER(ANON_PRIVATE))
+			 	goto whole;
+		      */
+		      mapping_anon_p = 1;
+		    }
 		}
 	    }
 
-	  /* Older Linux kernels did not support the "Anonymous:" counter.
-	     If it is missing, we can't be sure - dump all the pages.  */
-	  if (!has_anonymous)
-	    modified = 1;
+	  if (has_anonymous)
+	    should_dump_p = dump_mapping_p (filterflags, &v, private,
+					    mapping_anon_p, filename);
+	  else
+	    {
+	      /* Older Linux kernels did not support the "Anonymous:" counter.
+		 If it is missing, we can't be sure - dump all the pages.  */
+	      should_dump_p = 1;
+	    }
 
 	  /* Invoke the callback function to create the corefile segment.  */
-	  func (addr, endaddr - addr, offset, inode,
-		read, write, exec, modified, filename, obfd);
+	  if (should_dump_p)
+	    func (addr, endaddr - addr, offset, inode,
+		  read, write, exec, 1, /* MODIFIED is true because we
+					   want to dump the mapping.  */
+		  filename, obfd);
 	}
 
       do_cleanups (cleanup);
@@ -1972,6 +2301,17 @@ linux_infcall_mmap (CORE_ADDR size, unsigned prot)
   return retval;
 }
 
+/* Display whether the gcore command is using the
+   /proc/PID/coredump_filter file.  */
+
+static void
+show_use_coredump_filter (struct ui_file *file, int from_tty,
+			  struct cmd_list_element *c, const char *value)
+{
+  fprintf_filtered (file, _("Use of /proc/PID/coredump_filter file to generate"
+			    " corefiles is %s.\n"), value);
+}
+
 /* To be called from the various GDB_OSABI_LINUX handlers for the
    various GNU/Linux architectures and machine types.  */
 
@@ -2008,4 +2348,16 @@ _initialize_linux_tdep (void)
   /* Observers used to invalidate the cache when needed.  */
   observer_attach_inferior_exit (invalidate_linux_cache_inf);
   observer_attach_inferior_appeared (invalidate_linux_cache_inf);
+
+  add_setshow_boolean_cmd ("use-coredump-filter", class_files,
+			   &use_coredump_filter, _("\
+Set whether gcore should consider /proc/PID/coredump_filter."),
+			   _("\
+Show whether gcore should consider /proc/PID/coredump_filter."),
+			   _("\
+Use this command to set whether gcore should consider the contents\n\
+of /proc/PID/coredump_filter when generating the corefile.  For more information\n\
+about this file, refer to the manpage of core(5)."),
+			   NULL, show_use_coredump_filter,
+			   &setlist, &showlist);
 }
-- 
1.9.3

^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2015-04-08 17:21 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-03-24 23:57 [PATCH v4 0/2] Improve corefile generation by using /proc/PID/coredump_filter (PR corefile/16902) Sergio Durigan Junior
2015-03-24 23:57 ` [PATCH 1/2] Implement support for checking /proc/PID/coredump_filter Sergio Durigan Junior
2015-03-27  9:53   ` Pedro Alves
2015-03-31 23:40     ` Sergio Durigan Junior
2015-04-08 14:08       ` Build failure following: Implement support for checking /proc/PID/coredump_filter commit Pierre Muller
2015-04-08 14:43         ` Pedro Alves
2015-04-08 15:14           ` Pedro Alves
2015-04-08 16:08             ` Sergio Durigan Junior
2015-04-08 16:28             ` Pierre Muller
2015-04-08 16:47               ` Sergio Durigan Junior
2015-04-08 17:21                 ` Pedro Alves
2015-04-08 16:27           ` Yao Qi
2015-04-08 16:47             ` Pedro Alves
2015-03-24 23:57 ` [PATCH 2/2] Documentation and testcase Sergio Durigan Junior
2015-03-27  9:53   ` Pedro Alves
  -- strict thread matches above, loose matches on Subject: below --
2015-03-19 23:22 [PATCH v4 0/2] Improve corefile generation by using /proc/PID/coredump_filter (PR corefile/16902) Sergio Durigan Junior
2015-03-19 23:22 ` [PATCH 1/2] Implement support for checking /proc/PID/coredump_filter Sergio Durigan Junior
2015-03-20 19:12   ` Pedro Alves
2015-03-20 20:02     ` Sergio Durigan Junior
2015-03-20 22:02       ` Pedro Alves
2015-03-23 18:40         ` Sergio Durigan Junior
2015-03-23 20:36           ` Pedro Alves

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).