This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Share ptrace options discovery/linux native code between GDB and gdbserver


Hi,

This is another cleanup/commonalization patch that serves as a base for the future remote fork/exec support.

Both GDB and gdbserver check for ptrace options in similar ways, but each code does its own thing.

The patch moves the ptrace option checks from linux-nat.*/gdbserver/linux-low.c to common/linux-ptrace.c. The code is a little entangled with the native linux stuff too, so some code gets moved to common/linux-nat-common.* instead.

The variable that stores all the supported ptrace options is kept in common/linux-ptrace.c now, and GDB/gdbserver can query features (tracesysgood, tracevfork etc) via helper functions. It seems a bit cleaner this way.

With this change GDB and gdbserver share almost the same code for those checks, leading to less duplication.

Up for discussion are a few things though:

1 - There is a bit of gdbserver-specific code that disallows PTRACE_O_TRACEFORK and friends so gdbserver keeps the same behavior even though those options are available for Linux. This is temporary so we don't break gdbserver while remote fork is being developed. You can see this block in linux_enable_event_reporting.

There is also a gdbserver-specific block for gdbserver debugging messages. Maybe we can get rid of those and come up with something common between GDB and gdbserver as well.

2 - I had to come up with a little bit of magic to merge the gdbserver-specific code to fork childs and grandchilds (fork/clone-handling) with GDB's. gdbserver supports MMU-less targets and we have a few defines there to either use fork or clone based on that condition. ia64 also has its own little thing going on, so that is honored as well for both GDB and gdbserver. This can be seen in linux_fork_to_function.

3 - gdbserver explicitly casts the arguments for a ptrace call to cope with odd architectures that require such a cast to be able to pass parameters correctly. I'm not too sure what to do about this one. We can either have more #ifdef blocks (in a way, defeating the purpose of having common code) or just unconditionally use a #define for a cast and create such a #define at build-time (either GDB or gdbserver) with the correct casting type or no casting at all.

4 - Is linux-nat-common.* an acceptable naming pattern? It seems to me that in the future we will eventually have lots of these, one for each architecture as we share more and more backend code.

Testing-wise, everything is still the same for x86-84, no regressions found for both GDB and gdbserver.

Thoughts?
2013-07-24  Luis Machado  <lgustavo@codesourcery.com>
    
	gdb/
	* Makefile.in (SFILES): Add common/linux-nat-common.c.
	Add common/linux-nat-common.h to list of header files.
	(COMMON_OBS): Add linux-nat-common.o.
	(linux-nat-common.o): New target object file.
	common/linux-nat-common.c: New file.
	common/linux-nat-common.h: New file.
	* common/linux-ptrace.c: Include linux-nat-common.h.
	(current_ptrace_options): Moved from linux-nat.c.
	(linux_fork_to_function): New function.
	(linux_grandchild_function): Likewise.
	(linux_child_function): Likewise.
	(linux_check_ptrace_features): New function, heavily
	based on linux-nat.c:linux_test_for_tracefork.
	(linux_enable_event_reporting): New function.
	(ptrace_supports_feature): Likewise.
	(linux_supports_tracefork): Likewise.
	(linux_supports_tracevforkdone): Likewise.
	(linux_supports_tracesysgood): Likewise.
	common/linux-ptrace.h (linux_enable_event_reporting): New
	declaration.
	(linux_supports_tracefork): Likewise.
	(linux_supports_tracevforkdone): Likewise.
	(linux_supports_tracesysgood): Likewise.
	* linux-nat.c (SYSCALL_SIGTRAP): Moved to
	common/linux-nat-common.h.
	(linux_supports_tracefork_flag): Remove.
	(linux_supports_tracesysgood_flag): Likewise.
	(linux_supports_tracevforkdone_flag): Likewise.
	(current_ptrace_options): Moved to
	common/linux-ptrace.c.
	(block_child_signals): Moved to common/linux-nat-common.h.
	(restore_child_signals_mask): Likewise.
	(linux_tracefork_child): Remove.
	(my_waitpid): Remove.
	(linux_test_for_tracefork): Renamed to
	linux_check_ptrace_features and moved to common/linux-ptrace.c.
	(linux_test_for_tracesysgood): Remove.
	(linux_supports_tracesysgood): Remove.
	(linux_supports_tracefork): Remove.
	(linux_supports_tracevforkdone): Remove.
	(linux_enable_tracesysgood): Remove.
	(linux_enable_event_reporting): Remove.
	(linux_child_post_attach): Remove call to
	linux_enable_tracesysgood.
	(linux_child_post_startup_inferior): Remove call to
	linux_enable_tracesysgood.
	(linux_child_follow_fork): Call linux_supports_tracefork
	and linux_supports_tracevforkdone.
	(linux_child_insert_fork_catchpoint): Call
	linux_supports_tracefork.
	(linux_child_insert_vfork_catchpoint): Likewise.
	(linux_child_set_syscall_catchpoint): Call
	linux_supports_tracesysgood.
	(block_child_signals): Moved to common/linux-nat-common.c.
	(restore_child_signals_mask): Likewise.
	(lin_lwp_attach_lwp): Call linux_supports_tracefork.
	* linux-nat.h: Include linux-nat-common.h

	gdb/gdbserver/
	* Makefile.in (SFILES): Add common/linux-nat-common.c.
	(server_h): Add $(srcdir)/../common/linux-nat-common.h.
	(linux-nat-common.o): New target object file.
	* linux-low.c: Include linux-nat-common.h
	(linux_enable_event_reporting): Remove declaration.
	(my_waitpid): Moved to common/linux-nat-common.c.
	(linux_wait_for_event): Pass ptid when calling
	linux_enable_event_reporting.
	(linux_supports_tracefork_flag): Remove.
	(linux_enable_event_reporting): Likewise.
	(linux_tracefork_grandchild): Remove.
	(STACK_SIZE): Moved to common/linux-ptrace.c.
	(linux_tracefork_child): Remove.
	(linux_test_for_tracefork): Remove.
	(linux_look_up_symbols): Call linux_supports_tracefork.
	(initialize_low): Remove call to linux_test_for_tracefork.

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 2d574d4..bd3c760 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -775,7 +775,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
 	common/gdb_vecs.c common/common-utils.c common/xml-utils.c \
 	common/ptid.c common/buffer.c gdb-dlfcn.c common/agent.c \
 	common/format.c common/filestuff.c btrace.c record-btrace.c ctf.c \
-	common/target-common.c
+	common/target-common.c common/linux-nat-common.c
 
 LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
 
@@ -854,7 +854,8 @@ common/common-utils.h common/xml-utils.h common/buffer.h common/ptid.h \
 common/format.h common/host-defs.h utils.h common/queue.h common/gdb_string.h \
 common/linux-osdata.h gdb-dlfcn.h auto-load.h probe.h stap-probe.h \
 gdb_bfd.h sparc-ravenscar-thread.h ppc-ravenscar-thread.h common/linux-btrace.h \
-ctf.h common/i386-cpuid.h common/i386-gcc-cpuid.h common/target-common.h
+ctf.h common/i386-cpuid.h common/i386-gcc-cpuid.h common/target-common.h \
+common/linux-nat-common.h
 
 # Header files that already have srcdir in them, or which are in objdir.
 
@@ -948,7 +949,8 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
 	inferior.o osdata.o gdb_usleep.o record.o record-full.o gcore.o \
 	gdb_vecs.o jit.o progspace.o skip.o probe.o \
 	common-utils.o buffer.o ptid.o gdb-dlfcn.o common-agent.o \
-	format.o registry.o btrace.o record-btrace.o target-common.o
+	format.o registry.o btrace.o record-btrace.o target-common.o \
+	linux-nat-common.o
 
 TSOBS = inflow.o
 
@@ -2026,6 +2028,10 @@ target-common.o: ${srcdir}/common/target-common.c
 	$(COMPILE) $(srcdir)/common/target-common.c
 	$(POSTCOMPILE)
 
+linux-nat-common.o: ${srcdir}/common/linux-nat-common.c
+	$(COMPILE) $(srcdir)/common/linux-nat-common.c
+	$(POSTCOMPILE)
+
 #
 # gdb/tui/ dependencies
 #
diff --git a/gdb/common/linux-nat-common.c b/gdb/common/linux-nat-common.c
new file mode 100644
index 0000000..8a6b2c2
--- /dev/null
+++ b/gdb/common/linux-nat-common.c
@@ -0,0 +1,134 @@
+/* GNU/Linux native-dependent code common to multiple platforms.
+
+   Copyright (C) 2001-2013 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/>.  */
+
+#ifdef GDBSERVER
+#include "server.h"
+#else
+#include "defs.h"
+#include "signal.h"
+#endif
+
+#include "linux-nat-common.h"
+#include "linux-ptrace.h"
+#include "gdb_wait.h"
+
+/* Signals to block to make that sigsuspend work.  */
+static sigset_t blocked_mask;
+
+/* Wrapper function for waitpid which handles EINTR, and emulates
+   __WALL for systems where that is not available.  */
+
+int
+my_waitpid (int pid, int *status, int flags)
+{
+  int ret, out_errno;
+
+#ifdef GDBSERVER
+  if (debug_threads)
+    fprintf (stderr, "my_waitpid (%d, 0x%x)\n", pid, flags);
+#endif
+
+  if (flags & __WALL)
+    {
+      sigset_t block_mask, org_mask, wake_mask;
+      int wnohang;
+
+      wnohang = (flags & WNOHANG) != 0;
+      flags &= ~(__WALL | __WCLONE);
+      flags |= WNOHANG;
+
+      /* Block all signals while here.  This avoids knowing about
+	 LinuxThread's signals.  */
+      sigfillset (&block_mask);
+      sigprocmask (SIG_BLOCK, &block_mask, &org_mask);
+
+      /* ... except during the sigsuspend below.  */
+      sigemptyset (&wake_mask);
+
+      while (1)
+	{
+	  /* Since all signals are blocked, there's no need to check
+	     for EINTR here.  */
+	  ret = waitpid (pid, status, flags);
+	  out_errno = errno;
+
+	  if (ret == -1 && out_errno != ECHILD)
+	    break;
+	  else if (ret > 0)
+	    break;
+
+	  if (flags & __WCLONE)
+	    {
+	      /* We've tried both flavors now.  If WNOHANG is set,
+		 there's nothing else to do, just bail out.  */
+	      if (wnohang)
+		break;
+
+#ifdef GDBSERVER
+	      if (debug_threads)
+		fprintf (stderr, "blocking\n");
+#endif
+
+	      /* Block waiting for signals.  */
+	      sigsuspend (&wake_mask);
+	    }
+	  flags ^= __WCLONE;
+	}
+
+      sigprocmask (SIG_SETMASK, &org_mask, NULL);
+    }
+  else
+    {
+      do
+	ret = waitpid (pid, status, flags);
+      while (ret == -1 && errno == EINTR);
+      out_errno = errno;
+    }
+
+#ifdef GDBSERVER
+  if (debug_threads)
+    fprintf (stderr, "my_waitpid (%d, 0x%x): status(%x), %d\n",
+	     pid, flags, status ? *status : -1, ret);
+#endif
+
+  errno = out_errno;
+  return ret;
+}
+
+/* Block child signals (SIGCHLD and linux threads signals), and store
+   the previous mask in PREV_MASK.  */
+
+void
+block_child_signals (sigset_t *prev_mask)
+{
+  /* Make sure SIGCHLD is blocked.  */
+  if (!sigismember (&blocked_mask, SIGCHLD))
+    sigaddset (&blocked_mask, SIGCHLD);
+
+  sigprocmask (SIG_BLOCK, &blocked_mask, prev_mask);
+}
+
+/* Restore child signals mask, previously returned by
+   block_child_signals.  */
+
+void
+restore_child_signals_mask (sigset_t *prev_mask)
+{
+  sigprocmask (SIG_SETMASK, prev_mask, NULL);
+}
diff --git a/gdb/common/linux-nat-common.h b/gdb/common/linux-nat-common.h
new file mode 100644
index 0000000..074af49
--- /dev/null
+++ b/gdb/common/linux-nat-common.h
@@ -0,0 +1,40 @@
+/* Common code for native debugging support for GNU/Linux (LWP layer).
+
+   Copyright (C) 2000-2013 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/>.  */
+
+#ifndef LINUX_NAT_COMMON_H
+#define LINUX_NAT_COMMON_H
+
+/* Unlike other extended result codes, WSTOPSIG (status) on
+   PTRACE_O_TRACESYSGOOD syscall events doesn't return SIGTRAP, but
+   instead SIGTRAP with bit 7 set.  */
+#define SYSCALL_SIGTRAP (SIGTRAP | 0x80)
+
+/* Wrapper function for waitpid which handles EINTR, and emulates
+   __WALL for systems where that is not available.  */
+extern int my_waitpid (int pid, int *status, int flags);
+
+/* Block child signals (SIGCHLD and linux threads signals), and store
+   the previous mask in PREV_MASK.  */
+extern void block_child_signals (sigset_t *prev_mask);
+
+/* Restore child signals mask, previously returned by
+   block_child_signals.  */
+extern void restore_child_signals_mask (sigset_t *prev_mask);
+
+#endif /* LINUX_NAT_COMMON_H */
diff --git a/gdb/common/linux-ptrace.c b/gdb/common/linux-ptrace.c
index d5ac061..0f1c256 100644
--- a/gdb/common/linux-ptrace.c
+++ b/gdb/common/linux-ptrace.c
@@ -24,11 +24,17 @@
 #endif
 
 #include "linux-ptrace.h"
+#include "linux-nat-common.h"
 #include "linux-procfs.h"
 #include "buffer.h"
 #include "gdb_assert.h"
 #include "gdb_wait.h"
 
+/* Stores the currently supported ptrace options.  A value of
+   -1 means we did not check for features yet.  A value of 0 means
+   there are no supported features.  */
+static int current_ptrace_options = -1;
+
 /* Find all possible reasons we could fail to attach PID and append these
    newline terminated reason strings to initialized BUFFER.  '\0' termination
    of BUFFER must be done by the caller.  */
@@ -222,8 +228,270 @@ linux_ptrace_test_ret_to_nx (void)
 #endif /* defined __i386__ || defined __x86_64__ */
 }
 
-/* Display possible problems on this system.  Display them only once per GDB
-   execution.  */
+/* Helper function to fork a process and make the child process call the
+   function FUNCTION passing ARG as parameter.  */
+
+static int
+linux_fork_to_function (void *arg, void (*function) (void *))
+{
+  int child_pid;
+
+  gdb_byte *stack = (gdb_byte *) arg;
+
+  /* Sanity check the function pointer.  */
+  gdb_assert (function != NULL);
+
+#if defined(__UCLIBC__) && defined(HAS_NOMMU)
+#define STACK_SIZE 4096
+
+    if (arg == NULL)
+      stack = xmalloc (STACK_SIZE * 4);
+
+    /* Use CLONE_VM instead of fork, to support uClinux (no MMU).  */
+    #ifdef __ia64__
+      child_pid = __clone2 (function, stack, STACK_SIZE,
+			    CLONE_VM | SIGCHLD, stack + STACK_SIZE * 2);
+    #else /* !__ia64__ */
+      child_pid = clone (function, stack + STACK_SIZE,
+			 CLONE_VM | SIGCHLD, stack + STACK_SIZE * 2);
+  #endif /* !__ia64__ */
+#else /* !defined(__UCLIBC) && defined(HAS_NOMMU) */
+  child_pid = fork ();
+
+  if (child_pid == 0)
+    function (stack);
+#endif /* defined(__UCLIBC) && defined(HAS_NOMMU) */
+
+  if (child_pid == -1)
+    perror_with_name (("fork"));
+
+  return child_pid;
+}
+
+/* A helper function for linux_check_ptrace_features, called after the child
+   forks a grandchild.  */
+
+static void
+linux_grandchild_function (void *arg)
+{
+  /* Free any allocated stack.  */
+  xfree (arg);
+
+  /* This code is only reacheable by the grandchild (child's child)
+     process.  */
+  _exit (0);
+}
+
+/* A helper function for linux_check_ptrace_features, called after the
+   parent process forks a child.  The child allows itself to be traced
+   by its parent.  */
+
+static void
+linux_child_function (void *arg)
+{
+  ptrace (PTRACE_TRACEME, 0, 0, 0);
+  kill (getpid (), SIGSTOP);
+
+  /* Fork a grandchild.  */
+  linux_fork_to_function (arg, linux_grandchild_function);
+
+  /* This code is only reacheable by the child (grandchild's parent)
+     process.  */
+  _exit (0);
+}
+
+/* Determine ptrace features available on this target.  */
+
+static void
+linux_check_ptrace_features (void)
+{
+  int child_pid, ret, status;
+  long second_pid;
+  sigset_t prev_mask;
+
+  /* Initialize the options.  */
+  current_ptrace_options = 0;
+
+  /* We don't want those ptrace calls to be interrupted.  */
+  block_child_signals (&prev_mask);
+
+  /* Fork a child so we can do some testing.  The child will call
+     linux_child_function and will get traced.  The child will eventually
+     fork a grandchild so we can test fork event reporting.  */
+  child_pid = linux_fork_to_function (NULL, linux_child_function);
+
+  ret = my_waitpid (child_pid, &status, 0);
+  if (ret == -1)
+    perror_with_name (("waitpid"));
+  else if (ret != child_pid)
+    error (_("linux_check_ptrace_features: waitpid: unexpected result %d."),
+	   ret);
+  if (! WIFSTOPPED (status))
+    error (_("linux_check_ptrace_features: waitpid: unexpected status %d."),
+	   status);
+
+  /* First, set the PTRACE_O_TRACEFORK option.  If this fails, we know
+     for sure that it is not supported.  */
+  ret = ptrace (PTRACE_SETOPTIONS, child_pid, 0, PTRACE_O_TRACEFORK);
+  if (ret != 0)
+    {
+      ret = ptrace (PTRACE_KILL, child_pid, 0, 0);
+      if (ret != 0)
+	{
+	  warning (_("linux_check_ptrace_features: failed to kill child"));
+	  restore_child_signals_mask (&prev_mask);
+	  return;
+	}
+
+      ret = my_waitpid (child_pid, &status, 0);
+      if (ret != child_pid)
+	warning (_("linux_check_ptrace_features: failed "
+		   "to wait for killed child"));
+      else if (!WIFSIGNALED (status))
+	warning (_("linux_check_ptrace_features: unexpected "
+		   "wait status 0x%x from killed child"), status);
+
+      restore_child_signals_mask (&prev_mask);
+      return;
+    }
+
+  /* Check if the target supports PTRACE_O_TRACESYSGOOD.  */
+  ret = ptrace (PTRACE_SETOPTIONS, child_pid, 0, PTRACE_O_TRACESYSGOOD);
+  current_ptrace_options |= (ret == 0)? PTRACE_O_TRACESYSGOOD : 0;
+
+  /* Check if the target supports PTRACE_O_TRACEVFORKDONE.  */
+  ret = ptrace (PTRACE_SETOPTIONS, child_pid, 0,
+		PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORKDONE);
+  current_ptrace_options |= (ret == 0)? PTRACE_O_TRACEVFORKDONE : 0;
+
+  /* Setting PTRACE_O_TRACEFORK did not cause an error, however we don't know
+     for sure that the feature is available; old versions of PTRACE_SETOPTIONS
+     ignored unknown options.  Therefore, we attach to the child process, use
+     PTRACE_SETOPTIONS to enable fork tracing, and let it fork.  If the
+     process exits, we assume that we can't use PTRACE_O_TRACEFORK; if we get
+     the fork notification, and we can extract the new child's PID, then we
+     assume that we can.
+
+     We do not explicitly check for vfork tracing here.  It is assumed that
+     vfork tracing is available whenever fork tracing is available.  */
+  ret = ptrace (PTRACE_CONT, child_pid, 0, 0);
+  if (ret != 0)
+    warning (_("linux_check_ptrace_features: failed to resume child"));
+
+  ret = my_waitpid (child_pid, &status, 0);
+
+  /* Check if we received a fork event notification.  */
+  if (ret == child_pid && WIFSTOPPED (status)
+      && status >> 16 == PTRACE_EVENT_FORK)
+    {
+      /* We did receive a fork event notification.  Make sure its PID is
+	 reported.  */
+      second_pid = 0;
+      ret = ptrace (PTRACE_GETEVENTMSG, child_pid, 0, &second_pid);
+      if (ret == 0 && second_pid != 0)
+	{
+	  int second_status;
+
+	  /* We got the PID from the grandchild, which means fork tracing
+	     is supported.  */
+	  current_ptrace_options |= PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK
+	    | PTRACE_O_TRACECLONE | PTRACE_O_TRACEEXEC;
+
+	  /* Do some cleanup and kill the grandchild.  */
+	  my_waitpid (second_pid, &second_status, 0);
+	  ret = ptrace (PTRACE_KILL, second_pid, 0, 0);
+	  if (ret != 0)
+	    warning (_("linux_check_ptrace_features: "
+		       "failed to kill second child"));
+	  my_waitpid (second_pid, &status, 0);
+	}
+    }
+  else
+    warning (_("linux_check_ptrace_features: unexpected result from waitpid "
+	     "(%d, status 0x%x)"), ret, status);
+
+  /* Clean things up and kill any pending childs.  */
+  do
+    {
+      ret = ptrace (PTRACE_KILL, child_pid, 0, 0);
+      if (ret != 0)
+	warning ("linux_check_ptrace_features: failed to kill child");
+      my_waitpid (child_pid, &status, 0);
+    }
+  while (WIFSTOPPED (status));
+
+  restore_child_signals_mask (&prev_mask);
+}
+
+/* Enable reporting of all currently supported ptrace events.  */
+
+void
+linux_enable_event_reporting (ptid_t ptid)
+{
+  int pid = ptid_get_lwp (ptid);
+
+  if (pid == 0)
+    pid = ptid_get_pid (ptid);
+
+  /* Check if we have initialized the ptrace features for this target.  If not,
+     do it now.  */
+  if (current_ptrace_options == -1)
+    linux_check_ptrace_features ();
+
+  /* Do not enable PTRACE_O_TRACEEXIT until GDB is more prepared to support
+     read-only process state.  */
+
+#ifdef GDBSERVER
+  /* Disable these options for now since gdbserver does not properly support
+     them.  */
+  current_ptrace_options &= ~(PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK
+			      | PTRACE_O_TRACEEXEC | PTRACE_O_TRACEVFORKDONE
+			      | PTRACE_O_TRACESYSGOOD);
+#endif
+
+  /* Set the options.  */
+  ptrace (PTRACE_SETOPTIONS, pid, 0, current_ptrace_options);
+}
+
+/* Returns non-zero if PTRACE_OPTIONS is contained within
+   CURRENT_PTRACE_OPTIONS, therefore supported.  Returns 0 otherwise.  */
+
+static int
+ptrace_supports_feature (int ptrace_options)
+{
+  gdb_assert (current_ptrace_options >= 0);
+
+  return ((current_ptrace_options & ptrace_options) != 0);
+}
+
+/* Returns non-zero if PTRACE_O_TRACEFORK, PTRACE_O_TRACEVFORK,
+   PTRACE_O_TRACECLONE and PTRACE_O_TRACEEXEC are supported by ptrace,
+   0 otherwise  */
+
+int
+linux_supports_tracefork (void)
+{
+  return ptrace_supports_feature (PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK
+				  | PTRACE_O_TRACECLONE | PTRACE_O_TRACEEXEC);
+}
+
+/* Returns non-zero if PTRACE_O_TRACEVFORKDONE is supported by ptrace,
+   0 otherwise  */
+
+int
+linux_supports_tracevforkdone (void)
+{
+  return ptrace_supports_feature (PTRACE_O_TRACEVFORKDONE);
+}
+
+/* Returns non-zero if PTRACE_O_TRACESYSGOOD is supported by ptrace,
+   0 otherwise  */
+
+int
+linux_supports_tracesysgood (void)
+{
+  return ptrace_supports_feature (PTRACE_O_TRACESYSGOOD);
+}
 
 void
 linux_ptrace_init_warnings (void)
diff --git a/gdb/common/linux-ptrace.h b/gdb/common/linux-ptrace.h
index 8f02c82..7a50f9e 100644
--- a/gdb/common/linux-ptrace.h
+++ b/gdb/common/linux-ptrace.h
@@ -70,4 +70,19 @@ struct buffer;
 extern void linux_ptrace_attach_warnings (pid_t pid, struct buffer *buffer);
 extern void linux_ptrace_init_warnings (void);
 
+/* Enable reporting of all currently supported ptrace events.  */
+extern void linux_enable_event_reporting (ptid_t ptid);
+
+/* Returns non-zero if PTRACE_EVENT_FORK, PTRACE_EVENT_CLONE, PTRACE_EVENT_EXEC
+   and PTRACE_EVENT_VFORK are supported by ptrace, 0 otherwise  */
+extern int linux_supports_tracefork (void);
+
+/* Returns non-zero if PTRACE_O_TRACEVFORKDONE is supported by ptrace,
+   0 otherwise  */
+extern int linux_supports_tracevforkdone (void);
+
+/* Returns non-zero if PTRACE_O_TRACESYSGOOD is supported by ptrace,
+   0 otherwise  */
+extern int linux_supports_tracesysgood (void);
+
 #endif /* COMMON_LINUX_PTRACE_H */
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index b28f743..bdb83e3 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -157,7 +157,8 @@ SFILES=	$(srcdir)/gdbreplay.c $(srcdir)/inferiors.c $(srcdir)/dll.c \
 	$(srcdir)/common/common-utils.c $(srcdir)/common/xml-utils.c \
 	$(srcdir)/common/linux-osdata.c $(srcdir)/common/ptid.c \
 	$(srcdir)/common/buffer.c $(srcdir)/common/linux-btrace.c \
-	$(srcdir)/common/filestuff.c $(srcdir)/common/target-common.c
+	$(srcdir)/common/filestuff.c $(srcdir)/common/target-common.c \
+	$(srcdir)/common/linux-nat-common.c
 
 DEPFILES = @GDBSERVER_DEPFILES@
 
@@ -167,8 +168,8 @@ SOURCES = $(SFILES)
 TAGFILES = $(SOURCES) ${HFILES} ${ALLPARAM} ${POSSLIBS}
 
 OBS = agent.o ax.o inferiors.o regcache.o remote-utils.o server.o signals.o \
-      target.o target-common.o utils.o version.o vec.o gdb_vecs.o \
-      mem-break.o hostio.o event-loop.o tracepoint.o xml-utils.o \
+      target.o target-common.o linux-nat-common.o utils.o version.o vec.o \
+      gdb_vecs.o mem-break.o hostio.o event-loop.o tracepoint.o xml-utils.o \
       common-utils.o ptid.o buffer.o format.o filestuff.o dll.o notif.o \
       tdesc.o $(XML_BUILTIN) $(DEPFILES) $(LIBOBJS)
 GDBREPLAY_OBS = gdbreplay.o version.o
@@ -437,6 +438,7 @@ server_h = $(srcdir)/server.h $(regcache_h) $(srcdir)/target.h \
 		$(srcdir)/../common/gdb_assert.h \
 		$(srcdir)/../common/gdb_locale.h \
 		$(srcdir)/../common/target-common.h \
+		$(srcdir)/../common/linux-nat-common.h \
 		$(ptid_h) \
 		$(signals_h) \
 		$(libiberty_h) \
@@ -550,6 +552,9 @@ agent.o: ../common/agent.c
 target-common.o: ../common/target-common.c
 	$(COMPILE) $<
 	$(POSTCOMPILE)
+linux-nat-common.o: ../common/linux-nat-common.c
+	$(COMPILE) $<
+	$(POSTCOMPILE)
 
 linux-btrace.o: ../common/linux-btrace.c $(linux_btrace_h) $(server_h)
 	$(CC) -c $(CPPFLAGS) $(INTERNAL_CFLAGS) $<
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 47ea76d..2675b78 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -17,6 +17,7 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "server.h"
+#include "linux-nat-common.h"
 #include "linux-low.h"
 #include "linux-osdata.h"
 #include "agent.h"
@@ -236,7 +237,6 @@ static void proceed_all_lwps (void);
 static int finish_step_over (struct lwp_info *lwp);
 static CORE_ADDR get_stop_pc (struct lwp_info *lwp);
 static int kill_lwp (unsigned long lwpid, int signo);
-static void linux_enable_event_reporting (int pid);
 
 /* True if the low target can hardware single-step.  Such targets
    don't need a BREAKPOINT_REINSERT_ADDR callback.  */
@@ -376,81 +376,6 @@ linux_add_process (int pid, int attached)
   return proc;
 }
 
-/* Wrapper function for waitpid which handles EINTR, and emulates
-   __WALL for systems where that is not available.  */
-
-static int
-my_waitpid (int pid, int *status, int flags)
-{
-  int ret, out_errno;
-
-  if (debug_threads)
-    fprintf (stderr, "my_waitpid (%d, 0x%x)\n", pid, flags);
-
-  if (flags & __WALL)
-    {
-      sigset_t block_mask, org_mask, wake_mask;
-      int wnohang;
-
-      wnohang = (flags & WNOHANG) != 0;
-      flags &= ~(__WALL | __WCLONE);
-      flags |= WNOHANG;
-
-      /* Block all signals while here.  This avoids knowing about
-	 LinuxThread's signals.  */
-      sigfillset (&block_mask);
-      sigprocmask (SIG_BLOCK, &block_mask, &org_mask);
-
-      /* ... except during the sigsuspend below.  */
-      sigemptyset (&wake_mask);
-
-      while (1)
-	{
-	  /* Since all signals are blocked, there's no need to check
-	     for EINTR here.  */
-	  ret = waitpid (pid, status, flags);
-	  out_errno = errno;
-
-	  if (ret == -1 && out_errno != ECHILD)
-	    break;
-	  else if (ret > 0)
-	    break;
-
-	  if (flags & __WCLONE)
-	    {
-	      /* We've tried both flavors now.  If WNOHANG is set,
-		 there's nothing else to do, just bail out.  */
-	      if (wnohang)
-		break;
-
-	      if (debug_threads)
-		fprintf (stderr, "blocking\n");
-
-	      /* Block waiting for signals.  */
-	      sigsuspend (&wake_mask);
-	    }
-
-	  flags ^= __WCLONE;
-	}
-
-      sigprocmask (SIG_SETMASK, &org_mask, NULL);
-    }
-  else
-    {
-      do
-	ret = waitpid (pid, status, flags);
-      while (ret == -1 && errno == EINTR);
-      out_errno = errno;
-    }
-
-  if (debug_threads)
-    fprintf (stderr, "my_waitpid (%d, 0x%x): status(%x), %d\n",
-	     pid, flags, status ? *status : -1, ret);
-
-  errno = out_errno;
-  return ret;
-}
-
 /* Handle a GNU/Linux extended wait response.  If we see a clone
    event, we need to add the new LWP to our list (and not report the
    trap to higher layers).  */
@@ -1998,7 +1923,7 @@ linux_wait_for_event (ptid_t ptid, int *wstat, int options)
 
       if (event_child->must_set_ptrace_flags)
 	{
-	  linux_enable_event_reporting (lwpid_of (event_child));
+	  linux_enable_event_reporting (ptid_of (event_child));
 	  event_child->must_set_ptrace_flags = 0;
 	}
 
@@ -4659,168 +4584,6 @@ linux_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
   return 0;
 }
 
-/* Non-zero if the kernel supports PTRACE_O_TRACEFORK.  */
-static int linux_supports_tracefork_flag;
-
-static void
-linux_enable_event_reporting (int pid)
-{
-  if (!linux_supports_tracefork_flag)
-    return;
-
-  ptrace (PTRACE_SETOPTIONS, pid, (PTRACE_ARG3_TYPE) 0,
-	  (PTRACE_ARG4_TYPE) PTRACE_O_TRACECLONE);
-}
-
-/* Helper functions for linux_test_for_tracefork, called via clone ().  */
-
-static int
-linux_tracefork_grandchild (void *arg)
-{
-  _exit (0);
-}
-
-#define STACK_SIZE 4096
-
-static int
-linux_tracefork_child (void *arg)
-{
-  ptrace (PTRACE_TRACEME, 0, (PTRACE_ARG3_TYPE) 0, (PTRACE_ARG4_TYPE) 0);
-  kill (getpid (), SIGSTOP);
-
-#if !(defined(__UCLIBC__) && defined(HAS_NOMMU))
-
-  if (fork () == 0)
-    linux_tracefork_grandchild (NULL);
-
-#else /* defined(__UCLIBC__) && defined(HAS_NOMMU) */
-
-#ifdef __ia64__
-  __clone2 (linux_tracefork_grandchild, arg, STACK_SIZE,
-	    CLONE_VM | SIGCHLD, NULL);
-#else
-  clone (linux_tracefork_grandchild, (char *) arg + STACK_SIZE,
-	 CLONE_VM | SIGCHLD, NULL);
-#endif
-
-#endif /* defined(__UCLIBC__) && defined(HAS_NOMMU) */
-
-  _exit (0);
-}
-
-/* Determine if PTRACE_O_TRACEFORK can be used to follow fork events.  Make
-   sure that we can enable the option, and that it had the desired
-   effect.  */
-
-static void
-linux_test_for_tracefork (void)
-{
-  int child_pid, ret, status;
-  long second_pid;
-#if defined(__UCLIBC__) && defined(HAS_NOMMU)
-  char *stack = xmalloc (STACK_SIZE * 4);
-#endif /* defined(__UCLIBC__) && defined(HAS_NOMMU) */
-
-  linux_supports_tracefork_flag = 0;
-
-#if !(defined(__UCLIBC__) && defined(HAS_NOMMU))
-
-  child_pid = fork ();
-  if (child_pid == 0)
-    linux_tracefork_child (NULL);
-
-#else /* defined(__UCLIBC__) && defined(HAS_NOMMU) */
-
-  /* Use CLONE_VM instead of fork, to support uClinux (no MMU).  */
-#ifdef __ia64__
-  child_pid = __clone2 (linux_tracefork_child, stack, STACK_SIZE,
-			CLONE_VM | SIGCHLD, stack + STACK_SIZE * 2);
-#else /* !__ia64__ */
-  child_pid = clone (linux_tracefork_child, stack + STACK_SIZE,
-		     CLONE_VM | SIGCHLD, stack + STACK_SIZE * 2);
-#endif /* !__ia64__ */
-
-#endif /* defined(__UCLIBC__) && defined(HAS_NOMMU) */
-
-  if (child_pid == -1)
-    perror_with_name ("clone");
-
-  ret = my_waitpid (child_pid, &status, 0);
-  if (ret == -1)
-    perror_with_name ("waitpid");
-  else if (ret != child_pid)
-    error ("linux_test_for_tracefork: waitpid: unexpected result %d.", ret);
-  if (! WIFSTOPPED (status))
-    error ("linux_test_for_tracefork: waitpid: unexpected status %d.", status);
-
-  ret = ptrace (PTRACE_SETOPTIONS, child_pid, (PTRACE_ARG3_TYPE) 0,
-		(PTRACE_ARG4_TYPE) PTRACE_O_TRACEFORK);
-  if (ret != 0)
-    {
-      ret = ptrace (PTRACE_KILL, child_pid, (PTRACE_ARG3_TYPE) 0,
-		    (PTRACE_ARG4_TYPE) 0);
-      if (ret != 0)
-	{
-	  warning ("linux_test_for_tracefork: failed to kill child");
-	  return;
-	}
-
-      ret = my_waitpid (child_pid, &status, 0);
-      if (ret != child_pid)
-	warning ("linux_test_for_tracefork: failed to wait for killed child");
-      else if (!WIFSIGNALED (status))
-	warning ("linux_test_for_tracefork: unexpected wait status 0x%x from "
-		 "killed child", status);
-
-      return;
-    }
-
-  ret = ptrace (PTRACE_CONT, child_pid, (PTRACE_ARG3_TYPE) 0,
-		(PTRACE_ARG4_TYPE) 0);
-  if (ret != 0)
-    warning ("linux_test_for_tracefork: failed to resume child");
-
-  ret = my_waitpid (child_pid, &status, 0);
-
-  if (ret == child_pid && WIFSTOPPED (status)
-      && status >> 16 == PTRACE_EVENT_FORK)
-    {
-      second_pid = 0;
-      ret = ptrace (PTRACE_GETEVENTMSG, child_pid, (PTRACE_ARG3_TYPE) 0,
-		    &second_pid);
-      if (ret == 0 && second_pid != 0)
-	{
-	  int second_status;
-
-	  linux_supports_tracefork_flag = 1;
-	  my_waitpid (second_pid, &second_status, 0);
-	  ret = ptrace (PTRACE_KILL, second_pid, (PTRACE_ARG3_TYPE) 0,
-			(PTRACE_ARG4_TYPE) 0);
-	  if (ret != 0)
-	    warning ("linux_test_for_tracefork: failed to kill second child");
-	  my_waitpid (second_pid, &status, 0);
-	}
-    }
-  else
-    warning ("linux_test_for_tracefork: unexpected result from waitpid "
-	     "(%d, status 0x%x)", ret, status);
-
-  do
-    {
-      ret = ptrace (PTRACE_KILL, child_pid, (PTRACE_ARG3_TYPE) 0,
-		    (PTRACE_ARG4_TYPE) 0);
-      if (ret != 0)
-	warning ("linux_test_for_tracefork: failed to kill child");
-      my_waitpid (child_pid, &status, 0);
-    }
-  while (WIFSTOPPED (status));
-
-#if defined(__UCLIBC__) && defined(HAS_NOMMU)
-  free (stack);
-#endif /* defined(__UCLIBC__) && defined(HAS_NOMMU) */
-}
-
-
 static void
 linux_look_up_symbols (void)
 {
@@ -4833,7 +4596,7 @@ linux_look_up_symbols (void)
   /* If the kernel supports tracing forks then it also supports tracing
      clones, and then we don't need to use the magic thread event breakpoint
      to learn about threads.  */
-  thread_db_init (!linux_supports_tracefork_flag);
+  thread_db_init (!linux_supports_tracefork ());
 #endif
 }
 
@@ -6097,7 +5860,6 @@ initialize_low (void)
   set_breakpoint_data (the_low_target.breakpoint,
 		       the_low_target.breakpoint_len);
   linux_init_signals ();
-  linux_test_for_tracefork ();
   linux_ptrace_init_warnings ();
 
   sigchld_action.sa_handler = sigchld_handler;
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index 45a6e5f..077639d 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -171,11 +171,6 @@ blocked.  */
 #define O_LARGEFILE 0
 #endif
 
-/* Unlike other extended result codes, WSTOPSIG (status) on
-   PTRACE_O_TRACESYSGOOD syscall events doesn't return SIGTRAP, but
-   instead SIGTRAP with bit 7 set.  */
-#define SYSCALL_SIGTRAP (SIGTRAP | 0x80)
-
 /* The single-threaded native GNU/Linux target_ops.  We save a pointer for
    the use of the multi-threaded target.  */
 static struct target_ops *linux_ops;
@@ -226,24 +221,6 @@ struct simple_pid_list
 };
 struct simple_pid_list *stopped_pids;
 
-/* This variable is a tri-state flag: -1 for unknown, 0 if PTRACE_O_TRACEFORK
-   can not be used, 1 if it can.  */
-
-static int linux_supports_tracefork_flag = -1;
-
-/* This variable is a tri-state flag: -1 for unknown, 0 if
-   PTRACE_O_TRACESYSGOOD can not be used, 1 if it can.  */
-
-static int linux_supports_tracesysgood_flag = -1;
-
-/* If we have PTRACE_O_TRACEFORK, this flag indicates whether we also have
-   PTRACE_O_TRACEVFORKDONE.  */
-
-static int linux_supports_tracevforkdone_flag = -1;
-
-/* Stores the current used ptrace() options.  */
-static int current_ptrace_options = 0;
-
 /* Async mode support.  */
 
 /* The read/write ends of the pipe registered as waitable file in the
@@ -297,9 +274,6 @@ static int kill_lwp (int lwpid, int signo);
 
 static int stop_callback (struct lwp_info *lp, void *data);
 
-static void block_child_signals (sigset_t *prev_mask);
-static void restore_child_signals_mask (sigset_t *prev_mask);
-
 struct lwp_info;
 static struct lwp_info *add_lwp (ptid_t ptid);
 static void purge_lwp_list (int pid);
@@ -349,248 +323,10 @@ pull_pid_from_list (struct simple_pid_list **listp, int pid, int *statusp)
   return 0;
 }
 
-
-/* A helper function for linux_test_for_tracefork, called after fork ().  */
-
-static void
-linux_tracefork_child (void)
-{
-  ptrace (PTRACE_TRACEME, 0, 0, 0);
-  kill (getpid (), SIGSTOP);
-  fork ();
-  _exit (0);
-}
-
-/* Wrapper function for waitpid which handles EINTR.  */
-
-static int
-my_waitpid (int pid, int *statusp, int flags)
-{
-  int ret;
-
-  do
-    {
-      ret = waitpid (pid, statusp, flags);
-    }
-  while (ret == -1 && errno == EINTR);
-
-  return ret;
-}
-
-/* Determine if PTRACE_O_TRACEFORK can be used to follow fork events.
-
-   First, we try to enable fork tracing on ORIGINAL_PID.  If this fails,
-   we know that the feature is not available.  This may change the tracing
-   options for ORIGINAL_PID, but we'll be setting them shortly anyway.
-
-   However, if it succeeds, we don't know for sure that the feature is
-   available; old versions of PTRACE_SETOPTIONS ignored unknown options.  We
-   create a child process, attach to it, use PTRACE_SETOPTIONS to enable
-   fork tracing, and let it fork.  If the process exits, we assume that we
-   can't use TRACEFORK; if we get the fork notification, and we can extract
-   the new child's PID, then we assume that we can.  */
-
-static void
-linux_test_for_tracefork (int original_pid)
-{
-  int child_pid, ret, status;
-  long second_pid;
-  sigset_t prev_mask;
-
-  /* We don't want those ptrace calls to be interrupted.  */
-  block_child_signals (&prev_mask);
-
-  linux_supports_tracefork_flag = 0;
-  linux_supports_tracevforkdone_flag = 0;
-
-  ret = ptrace (PTRACE_SETOPTIONS, original_pid, 0, PTRACE_O_TRACEFORK);
-  if (ret != 0)
-    {
-      restore_child_signals_mask (&prev_mask);
-      return;
-    }
-
-  child_pid = fork ();
-  if (child_pid == -1)
-    perror_with_name (("fork"));
-
-  if (child_pid == 0)
-    linux_tracefork_child ();
-
-  ret = my_waitpid (child_pid, &status, 0);
-  if (ret == -1)
-    perror_with_name (("waitpid"));
-  else if (ret != child_pid)
-    error (_("linux_test_for_tracefork: waitpid: unexpected result %d."), ret);
-  if (! WIFSTOPPED (status))
-    error (_("linux_test_for_tracefork: waitpid: unexpected status %d."),
-	   status);
-
-  ret = ptrace (PTRACE_SETOPTIONS, child_pid, 0, PTRACE_O_TRACEFORK);
-  if (ret != 0)
-    {
-      ret = ptrace (PTRACE_KILL, child_pid, 0, 0);
-      if (ret != 0)
-	{
-	  warning (_("linux_test_for_tracefork: failed to kill child"));
-	  restore_child_signals_mask (&prev_mask);
-	  return;
-	}
-
-      ret = my_waitpid (child_pid, &status, 0);
-      if (ret != child_pid)
-	warning (_("linux_test_for_tracefork: failed "
-		   "to wait for killed child"));
-      else if (!WIFSIGNALED (status))
-	warning (_("linux_test_for_tracefork: unexpected "
-		   "wait status 0x%x from killed child"), status);
-
-      restore_child_signals_mask (&prev_mask);
-      return;
-    }
-
-  /* Check whether PTRACE_O_TRACEVFORKDONE is available.  */
-  ret = ptrace (PTRACE_SETOPTIONS, child_pid, 0,
-		PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORKDONE);
-  linux_supports_tracevforkdone_flag = (ret == 0);
-
-  ret = ptrace (PTRACE_CONT, child_pid, 0, 0);
-  if (ret != 0)
-    warning (_("linux_test_for_tracefork: failed to resume child"));
-
-  ret = my_waitpid (child_pid, &status, 0);
-
-  if (ret == child_pid && WIFSTOPPED (status)
-      && status >> 16 == PTRACE_EVENT_FORK)
-    {
-      second_pid = 0;
-      ret = ptrace (PTRACE_GETEVENTMSG, child_pid, 0, &second_pid);
-      if (ret == 0 && second_pid != 0)
-	{
-	  int second_status;
-
-	  linux_supports_tracefork_flag = 1;
-	  my_waitpid (second_pid, &second_status, 0);
-	  ret = ptrace (PTRACE_KILL, second_pid, 0, 0);
-	  if (ret != 0)
-	    warning (_("linux_test_for_tracefork: "
-		       "failed to kill second child"));
-	  my_waitpid (second_pid, &status, 0);
-	}
-    }
-  else
-    warning (_("linux_test_for_tracefork: unexpected result from waitpid "
-	     "(%d, status 0x%x)"), ret, status);
-
-  ret = ptrace (PTRACE_KILL, child_pid, 0, 0);
-  if (ret != 0)
-    warning (_("linux_test_for_tracefork: failed to kill child"));
-  my_waitpid (child_pid, &status, 0);
-
-  restore_child_signals_mask (&prev_mask);
-}
-
-/* Determine if PTRACE_O_TRACESYSGOOD can be used to follow syscalls.
-
-   We try to enable syscall tracing on ORIGINAL_PID.  If this fails,
-   we know that the feature is not available.  This may change the tracing
-   options for ORIGINAL_PID, but we'll be setting them shortly anyway.  */
-
-static void
-linux_test_for_tracesysgood (int original_pid)
-{
-  int ret;
-  sigset_t prev_mask;
-
-  /* We don't want those ptrace calls to be interrupted.  */
-  block_child_signals (&prev_mask);
-
-  linux_supports_tracesysgood_flag = 0;
-
-  ret = ptrace (PTRACE_SETOPTIONS, original_pid, 0, PTRACE_O_TRACESYSGOOD);
-  if (ret != 0)
-    goto out;
-
-  linux_supports_tracesysgood_flag = 1;
-out:
-  restore_child_signals_mask (&prev_mask);
-}
-
-/* Determine wether we support PTRACE_O_TRACESYSGOOD option available.
-   This function also sets linux_supports_tracesysgood_flag.  */
-
-static int
-linux_supports_tracesysgood (int pid)
-{
-  if (linux_supports_tracesysgood_flag == -1)
-    linux_test_for_tracesysgood (pid);
-  return linux_supports_tracesysgood_flag;
-}
-
-/* Return non-zero iff we have tracefork functionality available.
-   This function also sets linux_supports_tracefork_flag.  */
-
-static int
-linux_supports_tracefork (int pid)
-{
-  if (linux_supports_tracefork_flag == -1)
-    linux_test_for_tracefork (pid);
-  return linux_supports_tracefork_flag;
-}
-
-static int
-linux_supports_tracevforkdone (int pid)
-{
-  if (linux_supports_tracefork_flag == -1)
-    linux_test_for_tracefork (pid);
-  return linux_supports_tracevforkdone_flag;
-}
-
-static void
-linux_enable_tracesysgood (ptid_t ptid)
-{
-  int pid = ptid_get_lwp (ptid);
-
-  if (pid == 0)
-    pid = ptid_get_pid (ptid);
-
-  if (linux_supports_tracesysgood (pid) == 0)
-    return;
-
-  current_ptrace_options |= PTRACE_O_TRACESYSGOOD;
-
-  ptrace (PTRACE_SETOPTIONS, pid, 0, current_ptrace_options);
-}
-
-
-void
-linux_enable_event_reporting (ptid_t ptid)
-{
-  int pid = ptid_get_lwp (ptid);
-
-  if (pid == 0)
-    pid = ptid_get_pid (ptid);
-
-  if (! linux_supports_tracefork (pid))
-    return;
-
-  current_ptrace_options |= PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK
-    | PTRACE_O_TRACEEXEC | PTRACE_O_TRACECLONE;
-
-  if (linux_supports_tracevforkdone (pid))
-    current_ptrace_options |= PTRACE_O_TRACEVFORKDONE;
-
-  /* Do not enable PTRACE_O_TRACEEXIT until GDB is more prepared to support
-     read-only process state.  */
-
-  ptrace (PTRACE_SETOPTIONS, pid, 0, current_ptrace_options);
-}
-
 static void
 linux_child_post_attach (int pid)
 {
   linux_enable_event_reporting (pid_to_ptid (pid));
-  linux_enable_tracesysgood (pid_to_ptid (pid));
   linux_ptrace_init_warnings ();
 }
 
@@ -598,7 +334,6 @@ static void
 linux_child_post_startup_inferior (ptid_t ptid)
 {
   linux_enable_event_reporting (ptid);
-  linux_enable_tracesysgood (ptid);
   linux_ptrace_init_warnings ();
 }
 
@@ -788,9 +523,9 @@ holding the child stopped.  Try \"set detach-on-fork\" or \
 	  parent_inf->pspace->breakpoints_not_allowed = detach_fork;
 
 	  parent_lp = find_lwp_pid (pid_to_ptid (parent_pid));
-	  gdb_assert (linux_supports_tracefork_flag >= 0);
+	  gdb_assert (linux_supports_tracefork () >= 0);
 
-	  if (linux_supports_tracevforkdone (0))
+	  if (linux_supports_tracevforkdone ())
 	    {
   	      if (debug_linux_nat)
   		fprintf_unfiltered (gdb_stdlog,
@@ -962,7 +697,7 @@ holding the child stopped.  Try \"set detach-on-fork\" or \
 static int
 linux_child_insert_fork_catchpoint (int pid)
 {
-  return !linux_supports_tracefork (pid);
+  return !linux_supports_tracefork ();
 }
 
 static int
@@ -974,7 +709,7 @@ linux_child_remove_fork_catchpoint (int pid)
 static int
 linux_child_insert_vfork_catchpoint (int pid)
 {
-  return !linux_supports_tracefork (pid);
+  return !linux_supports_tracefork ();
 }
 
 static int
@@ -986,7 +721,7 @@ linux_child_remove_vfork_catchpoint (int pid)
 static int
 linux_child_insert_exec_catchpoint (int pid)
 {
-  return !linux_supports_tracefork (pid);
+  return !linux_supports_tracefork ();
 }
 
 static int
@@ -999,7 +734,7 @@ static int
 linux_child_set_syscall_catchpoint (int pid, int needed, int any_count,
 				    int table_size, int *table)
 {
-  if (!linux_supports_tracesysgood (pid))
+  if (!linux_supports_tracesysgood ())
     return 1;
 
   /* On GNU/Linux, we ignore the arguments.  It means that we only
@@ -1060,28 +795,6 @@ static sigset_t blocked_mask;
 /* SIGCHLD action.  */
 struct sigaction sigchld_action;
 
-/* Block child signals (SIGCHLD and linux threads signals), and store
-   the previous mask in PREV_MASK.  */
-
-static void
-block_child_signals (sigset_t *prev_mask)
-{
-  /* Make sure SIGCHLD is blocked.  */
-  if (!sigismember (&blocked_mask, SIGCHLD))
-    sigaddset (&blocked_mask, SIGCHLD);
-
-  sigprocmask (SIG_BLOCK, &blocked_mask, prev_mask);
-}
-
-/* Restore child signals mask, previously returned by
-   block_child_signals.  */
-
-static void
-restore_child_signals_mask (sigset_t *prev_mask)
-{
-  sigprocmask (SIG_SETMASK, prev_mask, NULL);
-}
-
 /* Mask of signals to pass directly to the inferior.  */
 static sigset_t pass_mask;
 
@@ -1449,7 +1162,7 @@ lin_lwp_attach_lwp (ptid_t ptid)
 
       if (ptrace (PTRACE_ATTACH, lwpid, 0, 0) < 0)
 	{
-	  if (linux_supports_tracefork_flag)
+	  if (linux_supports_tracefork ())
 	    {
 	      /* If we haven't stopped all threads when we get here,
 		 we may have seen a thread listed in thread_db's list,
diff --git a/gdb/linux-nat.h b/gdb/linux-nat.h
index cb8f1da..3473e23 100644
--- a/gdb/linux-nat.h
+++ b/gdb/linux-nat.h
@@ -18,6 +18,7 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "target.h"
+#include "linux-nat-common.h"
 
 #include <signal.h>
 

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]