Identify remote fork event support
authorDon Breazeal <donb@codesourcery.com>
Tue, 12 May 2015 16:52:41 +0000 (09:52 -0700)
committerDon Breazeal <donb@codesourcery.com>
Tue, 12 May 2015 16:52:41 +0000 (09:52 -0700)
This patch implements a mechanism for GDB to determine whether fork
events are supported in gdbserver.  This is a preparatory patch for
remote fork and exec event support.

Two new RSP packets are defined to represent fork and vfork event
support.  These packets are used just like PACKET_multiprocess_feature
to denote whether the corresponding event is supported.  GDB sends
fork-events+ and vfork-events+ to gdbserver to inquire about fork
event support.  If the response enables these packets, then GDB
knows that gdbserver supports the corresponding events and will
enable them.

Target functions used to query for support are included along with
each new packet.

In order for gdbserver to know whether the events are supported at the
point where the qSupported packet arrives, the code in nat/linux-ptrace.c
had to be reorganized.  Previously it would test for fork/exec event
support, then enable the events using the pid of the inferior.  When the
qSupported packet arrives there may not be an inferior.  So the mechanism
was split into two parts: a function that checks whether the events are
supported, called when gdbserver starts up, and another that enables the
events when the inferior stops for the first time.

Another gdbserver change was to add some global variables similar to
multi_process, one per new packet.  These are used to control whether
the corresponding fork events are enabled.  If GDB does not inquire
about the event support in the qSupported packet, then gdbserver will
not set these "report the event" flags.  If the flags are not set, the
events are ignored like they were in the past.  Thus, gdbserver will
never send fork event notification to an older GDB that doesn't
recognize fork events.

Tested on Ubuntu x64, native/remote/extended-remote, and as part of
subsequent patches in the series.

gdb/gdbserver/ChangeLog:

        * linux-low.c (linux_supports_fork_events): New function.
        (linux_supports_vfork_events): New function.
        (linux_target_ops): Initialize new structure members.
        (initialize_low): Call linux_check_ptrace_features.
        * lynx-low.c (lynx_target_ops): Initialize new structure
        members.
        * server.c (report_fork_events, report_vfork_events):
        New global flags.
        (handle_query): Add new features to qSupported packet and
        response.
        (captured_main): Initialize new global variables.
        * target.h (struct target_ops) <supports_fork_events>:
        New member.
        <supports_vfork_events>: New member.
        (target_supports_fork_events): New macro.
        (target_supports_vfork_events): New macro.
        * win32-low.c (win32_target_ops): Initialize new structure
        members.

gdb/ChangeLog:

        * nat/linux-ptrace.c (linux_check_ptrace_features): Change
        from static to extern.
        * nat/linux-ptrace.h (linux_check_ptrace_features): Declare.
        * remote.c (anonymous enum): <PACKET_fork_event_feature,
        * PACKET_vfork_event_feature>: New enumeration constants.
        (remote_protocol_features): Add table entries for new packets.
        (remote_query_supported): Add new feature queries to qSupported
        packet.
        (_initialize_remote): Exempt new packets from the requirement
        to have 'set remote' commands.

gdb/ChangeLog
gdb/gdbserver/ChangeLog
gdb/gdbserver/linux-low.c
gdb/gdbserver/lynx-low.c
gdb/gdbserver/server.c
gdb/gdbserver/target.h
gdb/gdbserver/win32-low.c
gdb/nat/linux-ptrace.c
gdb/nat/linux-ptrace.h
gdb/remote.c

index 7f4b45724db3bd005d0079f9842f2671348ff8ed..be75baf4fe33eb7fde45d41a03b89e8c998797f4 100644 (file)
@@ -1,3 +1,14 @@
+2015-05-12  Don Breazeal  <donb@codesourcery.com>
+
+       * nat/linux-ptrace.c (linux_check_ptrace_features): Change
+       from static to extern.
+       * nat/linux-ptrace.h (linux_check_ptrace_features): Declare.
+       * remote.c (anonymous enum): <PACKET_fork_event_feature,
+       * PACKET_vfork_event_feature>: New enumeration constants.
+       (remote_protocol_features): Add table entries for new packets.
+       (remote_query_supported): Add new feature queries to qSupported
+       packet.
+
 2015-05-12  Gary Benson <gbenson@redhat.com>
 
        * remote.c (remote_add_inferior): Call exec_file_locate_attach
index 94146b8f48b4a20a6528551dba8ad5957d08cb19..a37051d5c6980e41b54b7b90d4710dca9f7bab83 100644 (file)
@@ -1,3 +1,24 @@
+2015-05-12  Don Breazeal  <donb@codesourcery.com>
+
+       * linux-low.c (linux_supports_fork_events): New function.
+       (linux_supports_vfork_events): New function.
+       (linux_target_ops): Initialize new structure members.
+       (initialize_low): Call linux_check_ptrace_features.
+       * lynx-low.c (lynx_target_ops): Initialize new structure
+       members.
+       * server.c (report_fork_events, report_vfork_events):
+       New global flags.
+       (handle_query): Add new features to qSupported packet and
+       response.
+       (captured_main): Initialize new global variables.
+       * target.h (struct target_ops) <supports_fork_events>:
+       New member.
+       <supports_vfork_events>: New member.
+       (target_supports_fork_events): New macro.
+       (target_supports_vfork_events): New macro.
+       * win32-low.c (win32_target_ops): Initialize new structure
+       members.
+
 2015-05-12  Gary Benson <gbenson@redhat.com>
 
        * server.c (handle_qxfer_exec_file): Use current process
index bc76ffc126661c4dba1b100bdf75b5b73c675042..1724b5491d8434ae4edccf1185be5d583a8d3643 100644 (file)
@@ -5438,6 +5438,22 @@ 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 ();
+}
+
 static int
 linux_supports_disable_randomization (void)
 {
@@ -6411,6 +6427,8 @@ 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,
 #ifdef USE_THREAD_DB
   thread_db_handle_monitor_command,
 #else
@@ -6488,4 +6506,6 @@ initialize_low (void)
   sigaction (SIGCHLD, &sigchld_action, NULL);
 
   initialize_low_arch ();
+
+  linux_check_ptrace_features ();
 }
index 364c79f363cfd5f1b1c892fb69728f2cda1e2000..f08741601d14c3e538a68c58d2fe88e5ac6874ee 100644 (file)
@@ -762,6 +762,8 @@ 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,  /* handle_monitor_command */
 };
 
index 174ab398b0b4c15f283ca56c77b1e7311adc88fe..1544e99bdb3a9d79226ce8c00b41da151b47e34d 100644 (file)
@@ -57,6 +57,8 @@ static int exit_requested;
 int run_once;
 
 int multi_process;
+int report_fork_events;
+int report_vfork_events;
 int non_stop;
 int swbreak_feature;
 int hwbreak_feature;
@@ -2046,6 +2048,18 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
                  if (target_supports_stopped_by_hw_breakpoint ())
                    hwbreak_feature = 1;
                }
+             else if (strcmp (p, "fork-events+") == 0)
+               {
+                 /* GDB supports and wants fork events if possible.  */
+                 if (target_supports_fork_events ())
+                   report_fork_events = 1;
+               }
+             else if (strcmp (p, "vfork-events+") == 0)
+               {
+                 /* GDB supports and wants vfork events if possible.  */
+                 if (target_supports_vfork_events ())
+                   report_vfork_events = 1;
+               }
              else
                target_process_qsupported (p);
 
@@ -2096,6 +2110,12 @@ 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_non_stop ())
        strcat (own_buf, ";QNonStop+");
 
@@ -3472,6 +3492,8 @@ captured_main (int argc, char *argv[])
 
       noack_mode = 0;
       multi_process = 0;
+      report_fork_events = 0;
+      report_vfork_events = 0;
       /* Be sure we're out of tfind mode.  */
       current_traceframe = -1;
       cont_thread = null_ptid;
index b3d08cddd1a18cb14decbfed3e9cb59aec8fbd23..697b223bcb3f8a160cfa07bcaf5eead93f1a6929 100644 (file)
@@ -281,6 +281,12 @@ 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);
+
   /* 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 *);
@@ -420,6 +426,14 @@ void set_target_ops (struct target_ops *);
 
 int kill_inferior (int);
 
+#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 detach_inferior(pid) \
   (*the_target->detach) (pid)
 
index 6cf56bd54d358950b0601234367238dbd1018ffb..a58f9634883b084328e664cad8791b8c5b5f9d66 100644 (file)
@@ -1831,6 +1831,8 @@ 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, /* handle_monitor_command */
   NULL, /* core_of_thread */
   NULL, /* read_loadmap */
index 2244d9d5792d9bb71ced17a86fa353817fe185e1..aba3da85796246d363ffb7f391decaf6e029f4ad 100644 (file)
@@ -337,7 +337,7 @@ static void linux_test_for_exitkill (int child_pid);
 
 /* Determine ptrace features available on this target.  */
 
-static void
+void
 linux_check_ptrace_features (void)
 {
   int child_pid, ret, status;
index 8354a4de526d9c1e718456a3c88b7c981d88e650..03d98c92e5ebc0547c98739ab6699b5bb9c552d8 100644 (file)
@@ -149,6 +149,7 @@ extern void linux_ptrace_attach_fail_reason (pid_t pid, struct buffer *buffer);
 extern char *linux_ptrace_attach_fail_reason_string (ptid_t ptid, int err);
 
 extern void linux_ptrace_init_warnings (void);
+extern void linux_check_ptrace_features (void);
 extern void linux_enable_event_reporting (pid_t pid, int attached);
 extern void linux_disable_event_reporting (pid_t pid);
 extern int linux_supports_tracefork (void);
index 02c83711b6fde1625384e612f72e9b69d5dfdc7d..6dae9205c55b4c2041a241e394c271aaaa4f5a19 100644 (file)
@@ -1342,6 +1342,12 @@ enum {
   /* Support for hwbreak+ feature.  */
   PACKET_hwbreak_feature,
 
+  /* Support for fork events.  */
+  PACKET_fork_event_feature,
+
+  /* Support for vfork events.  */
+  PACKET_vfork_event_feature,
+
   PACKET_MAX
 };
 
@@ -4051,6 +4057,10 @@ static const struct protocol_feature remote_protocol_features[] = {
     PACKET_Qbtrace_conf_bts_size },
   { "swbreak", PACKET_DISABLE, remote_supported_packet, PACKET_swbreak_feature },
   { "hwbreak", PACKET_DISABLE, remote_supported_packet, PACKET_hwbreak_feature },
+  { "fork-events", PACKET_DISABLE, remote_supported_packet,
+    PACKET_fork_event_feature },
+  { "vfork-events", PACKET_DISABLE, remote_supported_packet,
+    PACKET_vfork_event_feature },
 };
 
 static char *remote_support_xml;
@@ -4129,6 +4139,16 @@ remote_query_supported (void)
 
       q = remote_query_supported_append (q, "qRelocInsn+");
 
+      if (rs->extended)
+       {
+         if (packet_set_cmd_state (PACKET_fork_event_feature)
+             != AUTO_BOOLEAN_FALSE)
+           q = remote_query_supported_append (q, "fork-events+");
+         if (packet_set_cmd_state (PACKET_vfork_event_feature)
+             != AUTO_BOOLEAN_FALSE)
+           q = remote_query_supported_append (q, "vfork-events+");
+       }
+
       q = reconcat (q, "qSupported:", q, (char *) NULL);
       putpkt (q);
 
@@ -12434,6 +12454,12 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
   add_packet_config_cmd (&remote_protocol_packets[PACKET_hwbreak_feature],
                          "hwbreak-feature", "hwbreak-feature", 0);
 
+  add_packet_config_cmd (&remote_protocol_packets[PACKET_fork_event_feature],
+                        "fork-event-feature", "fork-event-feature", 0);
+
+  add_packet_config_cmd (&remote_protocol_packets[PACKET_vfork_event_feature],
+                        "vfork-event-feature", "vfork-event-feature", 0);
+
   /* Assert that we've registered "set remote foo-packet" commands
      for all packet configs.  */
   {