diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index db22e92..2a346d9 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -1177,6 +1177,30 @@ linux_detach (int pid)
   return 0;
 }
 
+/* Enable extended mode features by enabling extended ptrace events.  */
+
+static void
+linux_enable_extended_features (void)
+{
+  struct thread_info *tp = (struct thread_info *) current_inferior;
+  
+  if (tp == NULL)
+    tp = get_first_thread ();
+
+  if (tp == NULL)
+    {
+      /* There is no process yet, so include extended options in the
+	 base options for subsequent ptrace configuration.  */
+      linux_ptrace_set_desired_options (PTRACE_O_TRACECLONE, 0);
+    }
+  else
+    {
+      /* Re-initialize ptrace options with extended options.  */
+      pid_t pid = ptid_get_lwp (tp->entry.id);
+      linux_enable_additional_options (pid);
+    }
+}
+
 /* Remove all LWPs that belong to process PROC from the lwp list.  */
 
 static int
@@ -6018,6 +6042,7 @@ static struct target_ops linux_target_ops = {
   linux_attach,
   linux_kill,
   linux_detach,
+  linux_enable_extended_features,
   linux_mourn,
   linux_join,
   linux_thread_alive,
@@ -6132,4 +6157,6 @@ initialize_low (void)
   sigaction (SIGCHLD, &sigchld_action, NULL);
 
   initialize_low_arch ();
+
+  linux_ptrace_set_desired_options (PTRACE_O_TRACECLONE, 0);
 }
diff --git a/gdb/gdbserver/lynx-low.c b/gdb/gdbserver/lynx-low.c
index 0b0ff47..750503d 100644
--- a/gdb/gdbserver/lynx-low.c
+++ b/gdb/gdbserver/lynx-low.c
@@ -722,6 +722,7 @@ static struct target_ops lynx_target_ops = {
   lynx_attach,
   lynx_kill,
   lynx_detach,
+  NULL,  /* enable_extended_features */
   lynx_mourn,
   lynx_join,
   lynx_thread_alive,
diff --git a/gdb/gdbserver/nto-low.c b/gdb/gdbserver/nto-low.c
index 3587156..729328f 100644
--- a/gdb/gdbserver/nto-low.c
+++ b/gdb/gdbserver/nto-low.c
@@ -929,6 +929,7 @@ static struct target_ops nto_target_ops = {
   nto_attach,
   nto_kill,
   nto_detach,
+  NULL, /* enable_extended_features */
   nto_mourn,
   NULL, /* nto_join */
   nto_thread_alive,
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index cf1dffe..e42e596 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -3542,6 +3542,10 @@ process_serial_event (void)
       break;
     case '!':
       extended_protocol = 1;
+
+      if (the_target->enable_extended_features != NULL)
+	(*the_target->enable_extended_features) ();
+
       write_ok (own_buf);
       break;
     case '?':
diff --git a/gdb/gdbserver/spu-low.c b/gdb/gdbserver/spu-low.c
index 9bb0c40..cfd33b0 100644
--- a/gdb/gdbserver/spu-low.c
+++ b/gdb/gdbserver/spu-low.c
@@ -645,6 +645,7 @@ static struct target_ops spu_target_ops = {
   spu_attach,
   spu_kill,
   spu_detach,
+  NULL, /* enable_extended_features */
   spu_mourn,
   spu_join,
   spu_thread_alive,
diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h
index f5eda8a..e09e885 100644
--- a/gdb/gdbserver/target.h
+++ b/gdb/gdbserver/target.h
@@ -92,11 +92,16 @@ struct target_ops
 
   int (*detach) (int pid);
 
+  /* Enable target specific features for extended mode.  */
+
+  void (*enable_extended_features) (void);
+
   /* The inferior process has died.  Do what is right.  */
 
   void (*mourn) (struct process_info *proc);
 
   /* Wait for inferior PID to exit.  */
+
   void (*join) (int pid);
 
   /* Return 1 iff the thread with process ID PID is alive.  */
diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c
index bc2506c..d09cec3 100644
--- a/gdb/gdbserver/win32-low.c
+++ b/gdb/gdbserver/win32-low.c
@@ -1768,6 +1768,7 @@ static struct target_ops win32_target_ops = {
   win32_attach,
   win32_kill,
   win32_detach,
+  NULL, /* enable_extended_features */
   win32_mourn,
   win32_join,
   win32_thread_alive,
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index b72c066..bda535c 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -4849,13 +4849,12 @@ Enables printf debugging output."),
 
   sigemptyset (&blocked_mask);
 
-  /* Do not enable PTRACE_O_TRACEEXIT until GDB is more prepared to
-     support read-only process state.  */
-  linux_ptrace_set_additional_flags (PTRACE_O_TRACESYSGOOD
-				     | PTRACE_O_TRACEVFORKDONE
-				     | PTRACE_O_TRACEVFORK
-				     | PTRACE_O_TRACEFORK
-				     | PTRACE_O_TRACEEXEC);
+  linux_ptrace_set_desired_options (PTRACE_O_TRACECLONE
+				    | PTRACE_O_TRACESYSGOOD
+				    | PTRACE_O_TRACEVFORKDONE
+				    | PTRACE_O_TRACEVFORK
+				    | PTRACE_O_TRACEFORK
+				    | PTRACE_O_TRACEEXEC, 0);
 }
 
 
diff --git a/gdb/nat/linux-ptrace.c b/gdb/nat/linux-ptrace.c
index 69eb83c..a9b80a0 100644
--- a/gdb/nat/linux-ptrace.c
+++ b/gdb/nat/linux-ptrace.c
@@ -37,9 +37,14 @@
    there are no supported features.  */
 static int current_ptrace_options = -1;
 
-/* Additional flags to test.  */
+/* Stores the ptrace options that the debugger wants enabled if
+   the operating system supports them.  */
+static int base_ptrace_options;
 
-static int additional_flags;
+/* Stores ptrace options that the ptrace caller may wish to enable
+   after initial ptrace option checking is complete, e.g. for
+   gdbserver extended-remote targets.  */
+static int additional_ptrace_options;
 
 /* Find all possible reasons we could fail to attach PID and append
    these as strings to the already initialized BUFFER.  '\0'
@@ -357,22 +362,27 @@ linux_check_ptrace_features (void)
   while (WIFSTOPPED (status));
 }
 
-/* Determine if PTRACE_O_TRACESYSGOOD can be used to catch
-   syscalls.  */
+/* Determine if PTRACE_O_TRACESYSGOOD can be used to catch syscalls.
+   Enable if it is in the base options, otherwise save it.  */
 
 static void
 linux_test_for_tracesysgood (int child_pid)
 {
   int ret;
 
-  if ((additional_flags & PTRACE_O_TRACESYSGOOD) == 0)
+  /* Check if the caller want PTRACE_O_TRACESYSGOOD under any
+     circumstances.  */
+  if (((base_ptrace_options | additional_ptrace_options)
+       & PTRACE_O_TRACESYSGOOD) == 0)
     return;
 
   ret = ptrace (PTRACE_SETOPTIONS, child_pid, (PTRACE_TYPE_ARG3) 0,
-		(PTRACE_TYPE_ARG4) PTRACE_O_TRACESYSGOOD);
+	        (PTRACE_TYPE_ARG4) PTRACE_O_TRACESYSGOOD);
 
   if (ret == 0)
-    current_ptrace_options |= PTRACE_O_TRACESYSGOOD;
+    current_ptrace_options |= (PTRACE_O_TRACESYSGOOD & base_ptrace_options);
+  else
+    additional_ptrace_options &= ~PTRACE_O_TRACESYSGOOD;
 }
 
 /* Determine if PTRACE_O_TRACEFORK can be used to follow fork
@@ -392,15 +402,14 @@ linux_test_for_tracefork (int child_pid)
   if (ret != 0)
     return;
 
-  if ((additional_flags & PTRACE_O_TRACEVFORKDONE) != 0)
-    {
-      /* Check if the target supports PTRACE_O_TRACEVFORKDONE.  */
-      ret = ptrace (PTRACE_SETOPTIONS, child_pid, (PTRACE_TYPE_ARG3) 0,
-		    (PTRACE_TYPE_ARG4) (PTRACE_O_TRACEFORK
-					| PTRACE_O_TRACEVFORKDONE));
-      if (ret == 0)
-	current_ptrace_options |= PTRACE_O_TRACEVFORKDONE;
-    }
+  /* Check if the target supports PTRACE_O_TRACEVFORKDONE.  */
+  ret = ptrace (PTRACE_SETOPTIONS, child_pid, (PTRACE_TYPE_ARG3) 0,
+		(PTRACE_TYPE_ARG4) (PTRACE_O_TRACEFORK
+				    | PTRACE_O_TRACEVFORKDONE));
+  if (ret == 0)
+    current_ptrace_options |= (PTRACE_O_TRACEVFORKDONE & base_ptrace_options);
+  else
+    additional_ptrace_options &= ~PTRACE_O_TRACEVFORKDONE;
 
   /* Setting PTRACE_O_TRACEFORK did not cause an error, however we
      don't know for sure that the feature is available; old
@@ -432,14 +441,19 @@ linux_test_for_tracefork (int child_pid)
 		    (PTRACE_TYPE_ARG4) &second_pid);
       if (ret == 0 && second_pid != 0)
 	{
+	  /* We got the PID from the grandchild, which means fork
+	     tracing and related options are supported by the OS.  */
+	  int supported_options = (PTRACE_O_TRACEFORK
+				   | PTRACE_O_TRACEVFORK
+				   | PTRACE_O_TRACECLONE
+				   | PTRACE_O_TRACEEXEC);
 	  int second_status;
 
-	  /* We got the PID from the grandchild, which means fork
-	     tracing is supported.  */
-	  current_ptrace_options |= PTRACE_O_TRACECLONE;
-	  current_ptrace_options |= (additional_flags & (PTRACE_O_TRACEFORK
-                                                         | PTRACE_O_TRACEVFORK
-                                                         | PTRACE_O_TRACEEXEC));
+	  if (ret == 0)
+	    current_ptrace_options |= (supported_options
+				       & base_ptrace_options);
+	  else
+	    additional_ptrace_options &= ~supported_options;
 
 	  /* Do some cleanup and kill the grandchild.  */
 	  my_waitpid (second_pid, &second_status, 0);
@@ -547,15 +561,31 @@ linux_ptrace_init_warnings (void)
   linux_ptrace_test_ret_to_nx ();
 }
 
-/* Set additional ptrace flags to use.  Some such flags may be checked
-   by the implementation above.  This function must be called before
-   any other function in this file; otherwise the flags may not take
-   effect appropriately.  */
+/* Set masks to be used for initializing ptrace options.  Options in BASE
+   will always be enabled if the OS supports them.  Options in ADDITIONAL
+   will only be enabled if linux_ptrace_enable_additional_options is
+   called.  This function must be called before testing for ptrace
+   option support; otherwise the options may not be enabled.  */
 
 void
-linux_ptrace_set_additional_flags (int flags)
+linux_ptrace_set_desired_options (int base, int additional)
 {
-  additional_flags = flags;
+  base_ptrace_options = base;
+  additional_ptrace_options = additional;
+}
+
+/* Enable the additional ptrace options requested by a previous call to
+   linux_ptrace_set_desired_options.  */
+
+void
+linux_enable_additional_options (pid_t pid)
+{
+  if (additional_ptrace_options != 0)
+    {
+      current_ptrace_options |= additional_ptrace_options;
+      ptrace (PTRACE_SETOPTIONS, pid, (PTRACE_TYPE_ARG3) 0,
+	      (PTRACE_TYPE_ARG4) (uintptr_t) current_ptrace_options);
+    }
 }
 
 /* Extract extended ptrace event from wait status.  */
diff --git a/gdb/nat/linux-ptrace.h b/gdb/nat/linux-ptrace.h
index 31a77cd..140a86b 100644
--- a/gdb/nat/linux-ptrace.h
+++ b/gdb/nat/linux-ptrace.h
@@ -91,7 +91,9 @@ extern int linux_supports_tracefork (void);
 extern int linux_supports_traceclone (void);
 extern int linux_supports_tracevforkdone (void);
 extern int linux_supports_tracesysgood (void);
-extern void linux_ptrace_set_additional_flags (int);
+extern void linux_ptrace_set_desired_options (int base_options,
+					      int additional_options);
+extern void linux_enable_additional_options (pid_t pid);
 extern int linux_ptrace_get_extended_event (int wstat);
 extern int linux_is_extended_waitstatus (int wstat);
 
