[PATCH 04/16 v3] Determine supported extended-remote features

Don Breazeal
2014-10-31T23:29:18Z

This patch implements a mechanism for GDB to determine what
extended-mode features are enabled in gdbserver. This is
a preparatory patch for extended-remote fork and exec event
support.

Several new features are included in the potential response to
the qSupported packet, denoting fork, vfork, and exec events.
and exec events. Note that vfork_done events are not represented
here, because if vfork events are supported, gdbserver will fake
up a vfork_done event for GDB even if the target doesn't provide
direct support for vfork_done.

A number of changes were required to make this work:

1) Sending the "!" (use extended protocol) packet before sending the
qSupported packet so that gdbserver knows it is in extended mode
when responding to qSupported. Previously qSupported was the
first packet sent.

2) Splitting nat/linux-ptrace.c:linux_enable_event_reporting into two
functions. Previously that function did two things: it checked
which extended ptrace events were supported, and then enabled any
of those events that were supported by the OS. The new functions,
linux_ptrace_check_options and linux_ptrace_enable options, each do
one of those operations. This allows gdbserver to call
linux_ptrace_check_options during initialization, prior to
accepting a connection from GDB. It saves the information about
which events are available, so that if and when gdbserver goes into
extended mode, those events can be enabled, and GDB and gdbserver
will agree about which events are enabled.

There are some changes to linux-ptrace.c that build on the changes
in commit 8009206ae2dec541b55edc488103c6c1ccb1416a. That commit
reduced the use of #ifdef GDBSERVER in linux-ptrace.c by allowing
the ptrace client (GDB or gdbserver) to request support for
certain ptrace options by maintaining static variables
current_ptrace_options (enabled options) and additional_options
(non-default options that the ptrace client has requested).

This patch modifies that to maintain three static variables:
current_ptrace_options (enabled options), requested_ptrace_options
(non-default options that the ptrace client has requested), and
available_ptrace_options (options from requested_ptrace_options
that are supported by the OS). available_ptrace_options is used
in linux_ptrace_enable_options when extended-mode is enabled.

3) Defining a new packet for each of the extended-mode events along
with corresponding "supports" predicates for each of them.

Some support for ptrace exit events is introduced in this patch,
although they can't be enabled until linux_ptrace_test_for_traceexit
is implemented in a subsequent patch. Exit events are used in the
implementation of remote follow exec later in the patch series, so
they are included in the infrastructure here with the other events.

Tested on x64 Ubuntu Lucid, native only, and as part of testing of
subsequent patches.

gdb/gdbserver/ChangeLog:
2014-10-31 Don Breazeal <donb@codesourcery.com>

* linux-low.c (linux_low_filter_event): Replace call to
linux_enable_event_reporting with call to
linux_ptrace_enable_options.
(linux_supports_fork_events): New function.
(linux_supports_vfork_events): New function.
(linux_supports_exec_events): New function.
(linux_enable_extended_features): New function.
(linux_target_ops): Add entries for the four new functions in
the target vector.
(initialize_low): Add calls to linux_ptrace_set_requested_options
and linux_ptrace_check_options.
* lynx-low.c (lynx_target_ops): Add NULL entries for the four
new functions in the target vector.
* server.c (handle_query): Add fork_events, vfork_events, and
exec_events to features that can be listed in qSupported response.
(process_serial_event): Call target function to enable extended
features when "!" extended mode packet is received.
(using_extended_protocol): New function.
* server.h (using_extended_protocol): Declare new function.
* target.h (struct target_ops) <supports_fork_events>: New member.
<supports_vfork_events>: New member.
<supports_exec_events>: New member.
<enable_extended_features>: New member.
* win32-low.c (win32_target_ops): Add NULL entries for the four
new functions in the target vector.

gdb/ChangeLog:
2014-10-31 Don Breazeal <donb@codesourcery.com>

* linux-nat.c (linux_init_ptrace): Replace call to
linux_enable_event_reporting with calls to
linux_ptrace_check_options and linux_ptrace_enable_options.
(linux_child_follow_fork): Replace call to
linux_disable_event_reporting with a call to
linux_ptrace_disable_options.
* nat/linux-ptrace.c (linux_ptrace_check_options): New function,
derived from linux_enable_event_reporting.
(linux_test_for_tracesysgood): Replace additional_flags with
requested_ptrace_options.
(linux_ptrace_check_options): Rename from linux_check_ptrace_features,
make it extern, use requested_ptrace_options and
available_ptrace_options in place of additional_flags.
(linux_ptrace_enable_options): New function, derived from
linux_enable_event_reporting.
(linux_ptrace_disable_options): Rename from
linux_disable_event_reporting.
(linux_supports_traceexit): New function.
(linux_ptrace_set_requested_options): Rename from
linux_ptrace_set_additional_flags, use requested_ptrace_options
instead of additional_flags.
* nat/linux-ptrace.h (linux_enable_event_reporting,
linux_disable_event_reporting): Remove renamed functions.
(linux_ptrace_check_options, linux_ptrace_enable_options,
linux_ptrace_disable_options, linux_supports_traceexit): Declare
new functions.
(linux_ptrace_set_additional_flags): Remove renamed function.
(linux_ptrace_set_requested_options): Declare new function.
* remote.c (anonymous enum) <PACKET_vFollowFork>: New constant.
<PACKET_fork_event_feature>: New constant.
<PACKET_vfork_event_feature>: New constant.
<PACKET_exec_event_feature>: New constant.
(extended_remote_fork_event_p): New function.
(extended_remote_vfork_event_p): New function.
(extended_remote_exec_event_p): New function.
(extended_remote_follow_fork): New function.
(remote_protocol_features): Add entries for the four new packets.
(remote_start_remote): Send "!" extended packet before qSupported.
(_initialize_remote): Add three packets to the list of packets
excepted from having config commands.

---
gdb/gdbserver/linux-low.c | 53 +++++++++++++++++++++++-
gdb/gdbserver/lynx-low.c | 4 ++
gdb/gdbserver/server.c | 19 +++++++++
gdb/gdbserver/server.h | 1 +
gdb/gdbserver/target.h | 32 ++++++++++++++
gdb/gdbserver/win32-low.c | 4 ++
gdb/linux-nat.c | 15 ++++---
gdb/nat/linux-ptrace.c | 87 ++++++++++++++++++++++++++-------------
gdb/nat/linux-ptrace.h | 8 ++-
gdb/remote.c | 100 +++++++++++++++++++++++++++++++++++++++-----
10 files changed, 271 insertions(+), 52 deletions(-)

diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 8776670..8334578 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -1878,7 +1878,7 @@ linux_low_filter_event (ptid_t filter_ptid, int lwpid, int wstat)

if (WIFSTOPPED (wstat) && child->must_set_ptrace_flags)
{
- linux_enable_event_reporting (lwpid);
+ linux_ptrace_enable_options (lwpid, using_extended_protocol ());
child->must_set_ptrace_flags = 0;
}

@@ -5168,6 +5168,33 @@ linux_supports_multi_process (void)
return 1;
}

+/* Check if fork events are supported. */
+
+static int
+linux_supports_fork_events (void)
+{
+ return linux_supports_tracefork ();
+}
+
+/* Check if vfork events are supported. */
+
+static int
+linux_supports_vfork_events (void)
+{
+ return linux_supports_tracefork ();
+}
+
+/* Check if exec events are supported. */
+
+static int
+linux_supports_exec_events (void)
+{
+ /* Check for PTRACE_O_TRACEEXIT, since our implementation of follow
+ exec depends on this option, which was implemented in a later
+ kernel version than PTRACE_O_TRACEFORK et al. */
+ return linux_supports_traceexit ();
+}
+
static int
linux_supports_disable_randomization (void)
{
@@ -6035,6 +6062,22 @@ linux_low_read_btrace (struct btrace_target_info *tinfo, struct buffer *buffer,
}
#endif /* HAVE_LINUX_BTRACE */

+/* Enable any available extended-mode-only options. */
+
+static void
+linux_enable_extended_features (void)
+{
+ long lwp = 0;
+
+ if (current_thread != NULL)
+ {
+ /* There is an inferior, so set the lwp argument. */
+ lwp = ptid_get_lwp (current_thread->entry.id);
+ }
+
+ linux_ptrace_enable_options (lwp, using_extended_protocol ());
+}
+
static struct target_ops linux_target_ops = {
linux_create_inferior,
linux_attach,
@@ -6079,6 +6122,10 @@ static struct target_ops linux_target_ops = {
linux_async,
linux_start_non_stop,
linux_supports_multi_process,
+ linux_supports_fork_events,
+ linux_supports_vfork_events,
+ linux_supports_exec_events,
+ linux_enable_extended_features,
#ifdef USE_THREAD_DB
thread_db_handle_monitor_command,
#else
@@ -6154,4 +6201,8 @@ initialize_low (void)
sigaction (SIGCHLD, &sigchld_action, NULL);

initialize_low_arch ();
+
+ /* Placeholder to enable extended events. */
+ linux_ptrace_set_requested_options (0);
+ linux_ptrace_check_options ();
}
diff --git a/gdb/gdbserver/lynx-low.c b/gdb/gdbserver/lynx-low.c
index 96dea03..3ccc032 100644
--- a/gdb/gdbserver/lynx-low.c
+++ b/gdb/gdbserver/lynx-low.c
@@ -751,6 +751,10 @@ static struct target_ops lynx_target_ops = {
NULL, /* async */
NULL, /* start_non_stop */
NULL, /* supports_multi_process */
+ NULL, /* supports_fork_events */
+ NULL, /* supports_vfork_events */
+ NULL, /* supports_exec_events */
+ NULL, /* enable_extended_features */
NULL, /* handle_monitor_command */
};

diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 522d6f6..d297403 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -1903,6 +1903,15 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
if (target_supports_multi_process ())
strcat (own_buf, ";multiprocess+");

+ if (target_supports_fork_events ())
+ strcat (own_buf, ";fork_events+");
+
+ if (target_supports_vfork_events ())
+ strcat (own_buf, ";vfork_events+");
+
+ if (target_supports_exec_events ())
+ strcat (own_buf, ";exec_events+");
+
if (target_supports_non_stop ())
strcat (own_buf, ";QNonStop+");

@@ -3559,6 +3568,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 '?':
@@ -3990,3 +4003,9 @@ handle_target_event (int err, gdb_client_data client_data)

return 0;
}
+
+int
+using_extended_protocol (void)
+{
+ return extended_protocol;
+}
diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h
index cac73e9..f4f192c 100644
--- a/gdb/gdbserver/server.h
+++ b/gdb/gdbserver/server.h
@@ -109,6 +109,7 @@ typedef int gdb_fildes_t;
/* Functions from server.c. */
extern int handle_serial_event (int err, gdb_client_data client_data);
extern int handle_target_event (int err, gdb_client_data client_data);
+extern int using_extended_protocol (void);

#include "remote-utils.h"

diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h
index 5e29b7f..570f57d 100644
--- a/gdb/gdbserver/target.h
+++ b/gdb/gdbserver/target.h
@@ -262,6 +262,18 @@ struct target_ops
/* Returns true if the target supports multi-process debugging. */
int (*supports_multi_process) (void);

+ /* Returns true if fork events are supported. */
+ int (*supports_fork_events) (void);
+
+ /* Returns true if vfork events are supported. */
+ int (*supports_vfork_events) (void);
+
+ /* Returns true if exec events are supported. */
+ int (*supports_exec_events) (void);
+
+ /* Enable features that are only available in extended mode. */
+ void (*enable_extended_features) (void);
+
/* If not NULL, target-specific routine to process monitor command.
Returns 1 if handled, or 0 to perform default processing. */
int (*handle_monitor_command) (char *);
@@ -390,6 +402,26 @@ void set_target_ops (struct target_ops *);

int kill_inferior (int);

+#define target_supports_follow_fork() \
+ (the_target->supports_follow_fork ? \
+ (*the_target->supports_follow_fork) () : 0)
+
+#define target_supports_follow_exec() \
+ (the_target->supports_follow_exec ? \
+ (*the_target->supports_follow_exec) () : 0)
+
+#define target_supports_fork_events() \
+ (the_target->supports_fork_events ? \
+ (*the_target->supports_fork_events) () : 0)
+
+#define target_supports_vfork_events() \
+ (the_target->supports_vfork_events ? \
+ (*the_target->supports_vfork_events) () : 0)
+
+#define target_supports_exec_events() \
+ (the_target->supports_exec_events ? \
+ (*the_target->supports_exec_events) () : 0)
+
#define detach_inferior(pid) \
(*the_target->detach) (pid)

diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c
index e714933..9ae2f94 100644
--- a/gdb/gdbserver/win32-low.c
+++ b/gdb/gdbserver/win32-low.c
@@ -1823,6 +1823,10 @@ static struct target_ops win32_target_ops = {
NULL, /* async */
NULL, /* start_non_stop */
NULL, /* supports_multi_process */
+ NULL, /* supports_fork_events */
+ NULL, /* supports_vfork_events */
+ NULL, /* supports_exec_events */
+ NULL, /* enable_extended_features */
NULL, /* handle_monitor_command */
NULL, /* core_of_thread */
NULL, /* read_loadmap */
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index 21797c1..f0487e9 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -326,7 +326,8 @@ pull_pid_from_list (struct simple_pid_list **listp, int pid, int *statusp)
static void
linux_init_ptrace (pid_t pid)
{
- linux_enable_event_reporting (pid);
+ linux_ptrace_check_options ();
+ linux_ptrace_enable_options (pid, 1);
linux_ptrace_init_warnings ();
}

@@ -418,7 +419,7 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child,
if (!gdbarch_software_single_step_p (target_thread_architecture
(child_lp->ptid)))
{
- linux_disable_event_reporting (child_pid);
+ linux_ptrace_disable_options (child_pid);
if (ptrace (PTRACE_SINGLESTEP, child_pid, 0, 0) < 0)
perror_with_name (_("Couldn't do single step"));
if (my_waitpid (child_pid, &status, 0) < 0)
@@ -4803,11 +4804,11 @@ Enables printf debugging output."),

/* 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_requested_options (PTRACE_O_TRACESYSGOOD
+ | PTRACE_O_TRACEVFORKDONE
+ | PTRACE_O_TRACEVFORK
+ | PTRACE_O_TRACEFORK
+ | PTRACE_O_TRACEEXEC);
}
\f

diff --git a/gdb/nat/linux-ptrace.c b/gdb/nat/linux-ptrace.c
index 8bc3f16..7871d95 100644
--- a/gdb/nat/linux-ptrace.c
+++ b/gdb/nat/linux-ptrace.c
@@ -25,14 +25,20 @@

#include <stdint.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;
+/* Stores the ptrace options that have been requested by the
+ ptrace client beyond the default options that we attempt
+ to enable for all ptrace clients. */
+static int requested_ptrace_options;

-/* Additional flags to test. */
+/* Stores the ptrace options from REQUESTED_PTRACE_OPTIONS
+ that are supported by the OS. A value of -1 means we did
+ not check for features yet. A value of 0 means that none
+ of the requested options are supported. */
+static int available_ptrace_options = -1;

-static int additional_flags;
+/* Stores the currently enabled ptrace options, or the default
+ option(s) that will be enabled once a process is loaded. */
+static int current_ptrace_options;

/* Find all possible reasons we could fail to attach PID and append
these as strings to the already initialized BUFFER. '\0'
@@ -310,13 +316,19 @@ static void linux_test_for_tracefork (int child_pid);

/* Determine ptrace features available on this target. */

-static void
-linux_check_ptrace_features (void)
+void
+linux_ptrace_check_options (void)
{
int child_pid, ret, status;

+ /* Check if we have initialized the ptrace features for this
+ target. If not, proceed. */
+ if (available_ptrace_options != -1)
+ return;
+
/* Initialize the options. */
current_ptrace_options = 0;
+ available_ptrace_options = 0;

/* Fork a child so we can do some testing. The child will call
linux_child_function and will get traced. The child will
@@ -358,14 +370,14 @@ linux_test_for_tracesysgood (int child_pid)
{
int ret;

- if ((additional_flags & PTRACE_O_TRACESYSGOOD) == 0)
+ if ((requested_ptrace_options & PTRACE_O_TRACESYSGOOD) == 0)
return;

ret = ptrace (PTRACE_SETOPTIONS, child_pid, (PTRACE_TYPE_ARG3) 0,
(PTRACE_TYPE_ARG4) PTRACE_O_TRACESYSGOOD);

if (ret == 0)
- current_ptrace_options |= PTRACE_O_TRACESYSGOOD;
+ available_ptrace_options |= PTRACE_O_TRACESYSGOOD;
}

/* Determine if PTRACE_O_TRACEFORK can be used to follow fork
@@ -385,14 +397,14 @@ linux_test_for_tracefork (int child_pid)
if (ret != 0)
return;

- if ((additional_flags & PTRACE_O_TRACEVFORKDONE) != 0)
+ if ((requested_ptrace_options & 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;
+ available_ptrace_options |= PTRACE_O_TRACEVFORKDONE;
}

/* Setting PTRACE_O_TRACEFORK did not cause an error, however we
@@ -428,11 +440,14 @@ linux_test_for_tracefork (int child_pid)
int second_status;

/* We got the PID from the grandchild, which means fork
- tracing is supported. */
+ tracing is supported. Include default options in
+ current_ptrace_options and save the rest as
+ available options. */
current_ptrace_options |= PTRACE_O_TRACECLONE;
- current_ptrace_options |= (additional_flags & (PTRACE_O_TRACEFORK
- | PTRACE_O_TRACEVFORK
- | PTRACE_O_TRACEEXEC));
+ available_ptrace_options |= (requested_ptrace_options
+ & (PTRACE_O_TRACEFORK
+ | PTRACE_O_TRACEVFORK
+ | PTRACE_O_TRACEEXEC));

/* Do some cleanup and kill the grandchild. */
my_waitpid (second_pid, &second_status, 0);
@@ -449,25 +464,29 @@ linux_test_for_tracefork (int child_pid)
"(%d, status 0x%x)"), ret, status);
}

-/* Enable reporting of all currently supported ptrace events. */
+/* Enable reporting of supported ptrace events. If
+ USE_AVAILABLE_OPTIONS is false, then exclude the events
+ specified in available_ptrace_options. If PID is non-zero,
+ set the ptrace options using that process. */

void
-linux_enable_event_reporting (pid_t pid)
+linux_ptrace_enable_options (pid_t pid, int use_available_options)
{
- /* 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 ();
+ if (use_available_options)
+ current_ptrace_options |= available_ptrace_options;

- /* Set the options. */
- ptrace (PTRACE_SETOPTIONS, pid, (PTRACE_TYPE_ARG3) 0,
- (PTRACE_TYPE_ARG4) (uintptr_t) current_ptrace_options);
+ if (pid != 0)
+ {
+ /* Set the options. */
+ ptrace (PTRACE_SETOPTIONS, pid, (PTRACE_TYPE_ARG3) 0,
+ (PTRACE_TYPE_ARG4) (uintptr_t) current_ptrace_options);
+ }
}

/* Disable reporting of all currently supported ptrace events. */

void
-linux_disable_event_reporting (pid_t pid)
+linux_ptrace_disable_options (pid_t pid)
{
/* Set the options. */
ptrace (PTRACE_SETOPTIONS, pid, (PTRACE_TYPE_ARG3) 0, 0);
@@ -516,6 +535,15 @@ linux_supports_tracevforkdone (void)
return ptrace_supports_feature (PTRACE_O_TRACEVFORKDONE);
}

+/* Returns non-zero if PTRACE_O_TRACEEXIT is supported by ptrace,
+ 0 otherwise. */
+
+int
+linux_supports_traceexit (void)
+{
+ return ptrace_supports_feature (PTRACE_O_TRACEEXIT);
+}
+
/* Returns non-zero if PTRACE_O_TRACESYSGOOD is supported by ptrace,
0 otherwise. */

@@ -540,15 +568,16 @@ linux_ptrace_init_warnings (void)
linux_ptrace_test_ret_to_nx ();
}

-/* Set additional ptrace flags to use. Some such flags may be checked
+/* Set additional ptrace flags to use, beyond the default options
+ checked for every ptrace client. 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. */

void
-linux_ptrace_set_additional_flags (int flags)
+linux_ptrace_set_requested_options (int flags)
{
- additional_flags = flags;
+ requested_ptrace_options = flags;
}

/* Extract extended ptrace event from wait status. */
diff --git a/gdb/nat/linux-ptrace.h b/gdb/nat/linux-ptrace.h
index 31a77cd..03d27e1 100644
--- a/gdb/nat/linux-ptrace.h
+++ b/gdb/nat/linux-ptrace.h
@@ -85,13 +85,15 @@ struct buffer;

extern void linux_ptrace_attach_fail_reason (pid_t pid, struct buffer *buffer);
extern void linux_ptrace_init_warnings (void);
-extern void linux_enable_event_reporting (pid_t pid);
-extern void linux_disable_event_reporting (pid_t pid);
+extern void linux_ptrace_check_options (void);
+extern void linux_ptrace_enable_options (pid_t pid, int use_available_options);
+extern void linux_ptrace_disable_options (pid_t pid);
extern int linux_supports_tracefork (void);
extern int linux_supports_traceclone (void);
extern int linux_supports_tracevforkdone (void);
+extern int linux_supports_traceexit (void);
extern int linux_supports_tracesysgood (void);
-extern void linux_ptrace_set_additional_flags (int);
+extern void linux_ptrace_set_requested_options (int);
extern int linux_ptrace_get_extended_event (int wstat);
extern int linux_is_extended_waitstatus (int wstat);

diff --git a/gdb/remote.c b/gdb/remote.c
index 20f2988..77c68d8 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -1327,6 +1327,18 @@ enum {
/* Support for qXfer:libraries-svr4:read with a non-empty annex. */
PACKET_augmented_libraries_svr4_read_feature,

+ /* Support for follow fork. */
+ PACKET_vFollowFork,
+
+ /* Support for fork events. */
+ PACKET_fork_event_feature,
+
+ /* Support for vfork events. */
+ PACKET_vfork_event_feature,
+
+ /* Support for exec events. */
+ PACKET_exec_event_feature,
+
PACKET_MAX
};

@@ -1432,6 +1444,52 @@ remote_multi_process_p (struct remote_state *rs)
return packet_support (PACKET_multiprocess_feature) == PACKET_ENABLE;
}

+/* Returns true if fork events are supported. */
+
+static int
+extended_remote_fork_event_p (struct remote_state *rs)
+{
+ return packet_support (PACKET_fork_event_feature) == PACKET_ENABLE;
+}
+
+/* Ifdef out the two functions below until they are needed for vfork
+ and exec catchpoints. */
+#if 0
+/* Returns true if vfork events are supported. */
+
+static int
+extended_remote_vfork_event_p (struct remote_state *rs)
+{
+ return packet_support (PACKET_vfork_event_feature) == PACKET_ENABLE;
+}
+
+/* Returns true if exec events are supported. */
+
+static int
+extended_remote_exec_event_p (struct remote_state *rs)
+{
+ return packet_support (PACKET_exec_event_feature) == PACKET_ENABLE;
+}
+#endif
+
+/* Target follow-fork function for extended-remote targets. */
+
+static int
+extended_remote_follow_fork (struct target_ops *target, int follow_child,
+ int detach_fork)
+{
+ struct remote_state *rs = get_remote_state ();
+
+ /* There is no need to check for anything other than the fork event.
+ We will also follow vforks if they are supported. */
+ if (extended_remote_fork_event_p (rs))
+ {
+ /* FIXME: Implement follow-fork here. */
+ return -1;
+ }
+ return 0;
+}
+
/* Tokens for use by the asynchronous signal handlers for SIGINT. */
static struct async_signal_handler *async_sigint_remote_twice_token;
static struct async_signal_handler *async_sigint_remote_token;
@@ -3386,9 +3444,18 @@ remote_start_remote (int from_tty, struct target_ops *target, int extended_p)
and so things may not be stable yet. */
rs->starting_up = 1;

- /* The first packet we send to the target is the optional "supported
- packets" request. If the target can answer this, it will tell us
- which later probes to skip. */
+ if (extended_p)
+ {
+ /* Tell the remote that we are using the extended protocol
+ before making any queries about supported features, since
+ some features may only be supported in extended mode. */
+ putpkt ("!");
+ getpkt (&rs->buf, &rs->buf_size, 0);
+ }
+
+ /* The first query packet we send to the target is the optional
+ "supported packets" request. If the target can answer this, it
+ will tell us which later probes to skip. */
remote_query_supported ();

/* If the stub wants to get a QAllow, compose one and send it. */
@@ -3417,13 +3484,6 @@ remote_start_remote (int from_tty, struct target_ops *target, int extended_p)
rs->noack_mode = 1;
}

- if (extended_p)
- {
- /* Tell the remote that we are using the extended protocol. */
- putpkt ("!");
- getpkt (&rs->buf, &rs->buf_size, 0);
- }
-
/* Let the target know which signals it is allowed to pass down to
the program. */
update_signals_program_target ();
@@ -3981,7 +4041,15 @@ static const struct protocol_feature remote_protocol_features[] = {
{ "Qbtrace:off", PACKET_DISABLE, remote_supported_packet, PACKET_Qbtrace_off },
{ "Qbtrace:bts", PACKET_DISABLE, remote_supported_packet, PACKET_Qbtrace_bts },
{ "qXfer:btrace:read", PACKET_DISABLE, remote_supported_packet,
- PACKET_qXfer_btrace }
+ PACKET_qXfer_btrace },
+ { "vFollowFork", PACKET_DISABLE, remote_supported_packet,
+ PACKET_vFollowFork },
+ { "fork_events", PACKET_DISABLE, remote_supported_packet,
+ PACKET_fork_event_feature },
+ { "vfork_events", PACKET_DISABLE, remote_supported_packet,
+ PACKET_vfork_event_feature },
+ { "exec_events", PACKET_DISABLE, remote_supported_packet,
+ PACKET_exec_event_feature }
};

static char *remote_support_xml;
@@ -11592,6 +11660,7 @@ init_extended_remote_ops (void)
Specify the serial device it is connected to (e.g. /dev/ttya).";
extended_remote_ops.to_open = extended_remote_open;
extended_remote_ops.to_create_inferior = extended_remote_create_inferior;
+ extended_remote_ops.to_follow_fork = extended_remote_follow_fork;
extended_remote_ops.to_mourn_inferior = extended_remote_mourn;
extended_remote_ops.to_detach = extended_remote_detach;
extended_remote_ops.to_attach = extended_remote_attach;
@@ -12162,7 +12231,11 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_btrace],
"qXfer:btrace", "read-btrace", 0);

- /* Assert that we've registered commands for all packet configs. */
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_vFollowFork],
+ "vFollowFork", "follow-fork", 0);
+
+ /* Assert that we've registered "set remote foo-packet" commands
+ for all packet configs. */
{
int i;

@@ -12181,6 +12254,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
case PACKET_DisconnectedTracing_feature:
case PACKET_augmented_libraries_svr4_read_feature:
case PACKET_qCRC:
+ case PACKET_fork_event_feature:
+ case PACKET_vfork_event_feature:
+ case PACKET_exec_event_feature:
/* Additions to this list need to be well justified:
pre-existing packets are OK; new packets are not. */
excepted = 1;
--
1.7.0.4