From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 30266 invoked by alias); 21 Aug 2014 00:30:57 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Received: (qmail 30255 invoked by uid 89); 21 Aug 2014 00:30:56 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.8 required=5.0 tests=AWL,BAYES_00 autolearn=ham version=3.3.2 X-HELO: relay1.mentorg.com Received: from relay1.mentorg.com (HELO relay1.mentorg.com) (192.94.38.131) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 21 Aug 2014 00:30:53 +0000 Received: from svr-orw-exc-10.mgc.mentorg.com ([147.34.98.58]) by relay1.mentorg.com with esmtp id 1XKGHC-0001NS-9h from donb@codesourcery.com for gdb-patches@sourceware.org; Wed, 20 Aug 2014 17:30:50 -0700 Received: from SVR-ORW-FEM-04.mgc.mentorg.com ([147.34.97.41]) by SVR-ORW-EXC-10.mgc.mentorg.com with Microsoft SMTPSVC(6.0.3790.4675); Wed, 20 Aug 2014 17:30:50 -0700 Received: from build4-lucid-cs (147.34.91.1) by svr-orw-fem-04.mgc.mentorg.com (147.34.97.41) with Microsoft SMTP Server id 14.2.247.3; Wed, 20 Aug 2014 17:30:49 -0700 Received: by build4-lucid-cs (Postfix, from userid 1905) id 4C3CB40D74; Wed, 20 Aug 2014 17:30:48 -0700 (PDT) From: Don Breazeal To: Subject: [PATCH 04/16 v2] Determine supported extended-remote features Date: Thu, 21 Aug 2014 00:30:00 -0000 Message-ID: <1408580964-27916-5-git-send-email-donb@codesourcery.com> In-Reply-To: <1407434395-19089-1-git-send-email-donb@codesourcery.com> References: <1407434395-19089-1-git-send-email-donb@codesourcery.com> MIME-Version: 1.0 Content-Type: text/plain X-IsSubscribed: yes X-SW-Source: 2014-08/txt/msg00440.txt.bz2 This patch implements a mechanism for GDB to ask gdbserver what extended-mode features are enabled. The problems that are solved include: 1) A mechanism other than the qSupported RSP packet is needed for gdbserver to inform GDB about the list of extended mode features that are supported. In the existing implementation most of the information about supported gdbserver features is sent to GDB in response to a qSupported RSP message. This exchange occurs prior to GDB sending the "!" packet to enable extended mode. So as-is this message doesn't work for features that are dependent on extended- mode. Also, the qSupported exchange is intended to inform GDB about which packets are supported, and most of the extended mode features do not have associated packets. There are some features included in the qSupported response that do not have associated RSP messages, but the code comments make it clear that this practice is not acceptable for new packets. 2) A mechanism is needed to enable extended mode features when GDB tells gdbserver to use extended mode. The existing implementation checks for ptrace extended events (just PTRACE_O_TRACELONE) and enables them immediately after checking. This is done when the first event occurs as the program is loaded, which can occur before GDB has connected to gdbserver and told it whether or not to use extended mode. The solution implemented in this patch is as follows: 1) Implement a new RSP packet, qExtendedFeatures, that returns a list of the _currently enabled_ extended mode features, along with a host-side function that tells the caller whether a specified extended-mode feature is supported. The first time the host-side function is called it sends the inquiry to gdbserver to populate its list of features. It is called from every extended-remote target function that uses one of the features. 2) Split linux_enable_event_reporting, which both checked for extended ptrace events and enabled them, into linux_ptrace_check_options and linux_ptrace_enable options. In gdbserver, linux_ptrace_check_options is called during initialization, prior to accepting a connection from GDB. linux_ptrace_enable_options is called from the same place that linux_enable_event_reporting was called, when the first event after program load occurs. It is also called when the "!" packet is received, via a new gdbserver target routine, enable_extended_features. This way both load scenarios are handled: (a) when the program is specified on the gdbserver command line and loaded prior to accepting a GDB connection, and (b) when the program is loaded after GDB connects, using GDB commands. There are some changes to linux-ptrace.c that build on the patch that Gary Benson implemented to reduce the use of #ifdef GDBSERVER in linux-ptrace.c here: https://sourceware.org/ml/gdb-patches/2014-07/msg00633.html. That patch allows 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 (2) above in linux_ptrace_enable_options when extended-mode is enabled. Tested on x64 Ubuntu Lucid, native only, and as part of testing of subsequent patches. gdb/ 2014-08-20 Don Breazeal * linux-nat.c (linux_init_ptrace): Replace call to linux_enable_event_reporting with calls to new functions. (linux_child_follow_fork): Replace call to linux_disable_event_reporting with call to renamed function. * nat/linux-ptrace.c (linux_ptrace_check_options): Use available_ptrace_options and requested_ptrace_options in place of additional_flags. (linux_test_for_tracesysgood): Ditto. (linux_test_for_tracefork): Ditto. (linux_ptrace_enable_options): New function from splitting linux_enable_event_reporting. (linux_ptrace_disable_options): Renamed function. (linux_supports_traceexit): New function. (linux_ptrace_set_requested_options): New function replaces linux_ptrace_set_additional_flags. * nat/linux-ptrace.h (linux_ptrace_check_options, linux_ptrace_enable_options, linux_ptrace_disable_options, linux_supports_traceexit, linux_ptrace_set_requested_options): Declare new and renamed functions. * remote.c (enum extended_feature_type): New enum. (struct extended_feature): New structure type. (enum) , : Define new RSP packets. (remote_protocol_features): Initialize vFollowFork element. (extract_response_item): New function extracted from remote_query_supported. (remote_query_supported): Call extract_response_item. (extended_remote_follow_fork): New function. (extended_remote_query_supported): New function. (extended_remote_feature_supported): New function. (_initialize_remote): Call add_packet_config_cmd for new RSP packets. gdb/gdbserver/ 2014-08-20 Don Breazeal * linux-low.c (linux_low_filter_event): Replace call to linux_enable_event_reporting with call to linux_ptrace_enable_options. (linux_supports_follow_fork): New function. (linux_supports_follow_exec): New function. (linux_enable_extended_features): New function. (linux_target_ops): Initialize new struct members. (initialize_low): Call linux_ptrace_set_requested_options and linux_ptrace_check_options. * lynx-low.c (lynx_target_ops): Initialize new struct members. * nto-low.c (nto_target_ops): Initialize new struct members. * server.c (handle_query): Support qExtendedFeatures packet. (process_serial_event): Call target routine enable_extended_features. (using_extended_protocol): New function. * server.h (using_extended_protocol): Declare new function. * spu-low.c (spu_target_ops): Initialize new struct members. * target.h (struct target_ops) : New member. : New member. : New member. * win32-low.c (win32_target_ops: Initialize new struct members. --- gdb/gdbserver/linux-low.c | 45 ++++++++++- gdb/gdbserver/lynx-low.c | 3 + gdb/gdbserver/nto-low.c | 3 + gdb/gdbserver/server.c | 33 ++++++++ gdb/gdbserver/server.h | 1 + gdb/gdbserver/spu-low.c | 3 + gdb/gdbserver/target.h | 20 +++++ gdb/gdbserver/win32-low.c | 3 + gdb/linux-nat.c | 15 ++-- gdb/nat/linux-ptrace.c | 77 +++++++++++++------- gdb/nat/linux-ptrace.h | 8 +- gdb/remote.c | 179 ++++++++++++++++++++++++++++++++++++++++----- 12 files changed, 330 insertions(+), 60 deletions(-) diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index dd73c24..f501c05 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -205,6 +205,7 @@ int using_threads = 1; jump pads). */ static int stabilizing_threads; +static void async_file_mark (void); static void linux_resume_one_lwp (struct lwp_info *lwp, int step, int signal, siginfo_t *info); static void linux_resume (struct thread_resume *resume_info, size_t n); @@ -213,6 +214,9 @@ static void unstop_all_lwps (int unsuspend, struct lwp_info *except); static int linux_wait_for_event_filtered (ptid_t wait_ptid, ptid_t filter_ptid, int *wstat, int options); static int linux_wait_for_event (ptid_t ptid, int *wstat, int options); +static ptid_t linux_wait_1 (ptid_t ptid, + struct target_waitstatus *ourstatus, + int target_options); static struct lwp_info *add_lwp (ptid_t ptid); static int linux_stopped_by_watchpoint (void); static void mark_lwp_dead (struct lwp_info *lwp, int wstat); @@ -1864,7 +1868,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; } @@ -2367,9 +2371,6 @@ static void move_out_of_jump_pad_callback (struct inferior_list_entry *entry); static int stuck_in_jump_pad_callback (struct inferior_list_entry *entry, void *data); static int lwp_running (struct inferior_list_entry *entry, void *data); -static ptid_t linux_wait_1 (ptid_t ptid, - struct target_waitstatus *ourstatus, - int target_options); /* Stabilize threads (move out of jump pads). @@ -6009,11 +6010,43 @@ linux_low_read_btrace (struct btrace_target_info *tinfo, struct buffer *buffer, } #endif /* HAVE_LINUX_BTRACE */ +/* Check if fork events are supported. */ + +static int +linux_supports_follow_fork (void) +{ + return linux_supports_tracefork (); +} + +/* Check if exec events are supported. */ + +static int +linux_supports_follow_exec (void) +{ + /* Check for PTRACE_O_TRACEEXIT, since our implementation of follow + exec depends on this option, and it was implemented in later + kernel versions than fork, exec, et al. */ + return linux_supports_traceexit (); +} + +/* Enable any available extended-mode-only options. */ + +static void +linux_enable_extended_features (void) +{ + if (current_inferior != NULL) + linux_ptrace_enable_options (ptid_get_lwp (current_inferior->entry.id), + using_extended_protocol ()); +} + static struct target_ops linux_target_ops = { linux_create_inferior, linux_attach, linux_kill, linux_detach, + linux_supports_follow_fork, + linux_supports_follow_exec, + linux_enable_extended_features, linux_mourn, linux_join, linux_thread_alive, @@ -6128,4 +6161,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 0b0ff47..0b27432 100644 --- a/gdb/gdbserver/lynx-low.c +++ b/gdb/gdbserver/lynx-low.c @@ -722,6 +722,9 @@ static struct target_ops lynx_target_ops = { lynx_attach, lynx_kill, lynx_detach, + NULL, /* supports_follow_fork */ + NULL, /* supports_follow_exec */ + 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 0afaec7..a48c6dd 100644 --- a/gdb/gdbserver/nto-low.c +++ b/gdb/gdbserver/nto-low.c @@ -928,6 +928,9 @@ static struct target_ops nto_target_ops = { nto_attach, nto_kill, nto_detach, + NULL, /* supports_follow_fork */ + NULL, /* supports_follow_exec */ + 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..b4fd206 100644 --- a/gdb/gdbserver/server.c +++ b/gdb/gdbserver/server.c @@ -2132,6 +2132,29 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) return; } + if (strncmp ("qExtendedFeatures", own_buf, 15) == 0) + { + int fork_supported = 0; + + /* Assume if fork events are supported then vfork and + vfork-done events are supported. If a target emerges + where this is not true, then each of these will need + to be checked separately. */ + if (target_supports_follow_fork ()) + { + strcat (own_buf, ":fork_event;vfork_event;vfork_done_event"); + fork_supported = 1; + } + + if (target_supports_follow_exec ()) + { + strcat (own_buf, (fork_supported ? ";" : ":")); + strcat (own_buf, "exec_event"); + } + + return; + } + if (handle_qxfer (own_buf, packet_len, new_packet_len_p)) return; @@ -3542,6 +3565,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 '?': @@ -3973,3 +4000,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 e6b2277..2c5377b 100644 --- a/gdb/gdbserver/server.h +++ b/gdb/gdbserver/server.h @@ -114,6 +114,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/spu-low.c b/gdb/gdbserver/spu-low.c index 867f97b..d4c5429 100644 --- a/gdb/gdbserver/spu-low.c +++ b/gdb/gdbserver/spu-low.c @@ -641,6 +641,9 @@ static struct target_ops spu_target_ops = { spu_attach, spu_kill, spu_detach, + NULL, /* supports_follow_fork */ + NULL, /* supports_follow_exec */ + 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..fc1ec73 100644 --- a/gdb/gdbserver/target.h +++ b/gdb/gdbserver/target.h @@ -92,6 +92,18 @@ struct target_ops int (*detach) (int pid); + /* Returns true if follow_fork is supported. */ + + int (*supports_follow_fork) (void); + + /* Returns true if follow_exec is supported. */ + + int (*supports_follow_exec) (void); + + /* Enable features that are only available in extended mode. */ + + void (*enable_extended_features) (void); + /* The inferior process has died. Do what is right. */ void (*mourn) (struct process_info *proc); @@ -389,6 +401,14 @@ 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 detach_inferior(pid) \ (*the_target->detach) (pid) diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c index 2242d5c..7337034 100644 --- a/gdb/gdbserver/win32-low.c +++ b/gdb/gdbserver/win32-low.c @@ -1767,6 +1767,9 @@ static struct target_ops win32_target_ops = { win32_attach, win32_kill, win32_detach, + NULL, /* supports_follow_fork */ + NULL, /* supports_follow_exec */ + NULL, /* enable_extended_features */ win32_mourn, win32_join, win32_thread_alive, diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c index 1798977..b7bb978 100644 --- a/gdb/linux-nat.c +++ b/gdb/linux-nat.c @@ -327,7 +327,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 (); } @@ -415,7 +416,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) @@ -4848,11 +4849,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); } diff --git a/gdb/nat/linux-ptrace.c b/gdb/nat/linux-ptrace.c index 88d29f2..fc9e83a 100644 --- a/gdb/nat/linux-ptrace.c +++ b/gdb/nat/linux-ptrace.c @@ -30,14 +30,20 @@ #include -/* 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' @@ -315,13 +321,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 @@ -363,14 +375,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 @@ -390,14 +402,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 @@ -433,11 +445,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); @@ -454,15 +469,15 @@ 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 requested_ptrace_options. */ 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, @@ -472,7 +487,7 @@ linux_enable_event_reporting (pid_t pid) /* 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); @@ -521,6 +536,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. */ @@ -545,15 +569,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 357e9f2..f3076b3 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -86,6 +86,17 @@ static long target_buf_size; important here, not the possibly larger cache line size. */ enum { REMOTE_ALIGN_WRITES = 16 }; +/* Denotes features that may be supported in extended mode. */ +enum extended_feature_type +{ + EXTENDED_FEATURES_START, + FORK_EVENT = EXTENDED_FEATURES_START, + VFORK_EVENT, + VFORK_DONE_EVENT, + EXEC_EVENT, + EXTENDED_FEATURES_COUNT +}; + /* Prototypes for local functions. */ static void async_cleanup_sigint_signal_handler (void *dummy); static int getpkt_sane (char **buf, long *sizeof_buf, int forever); @@ -224,6 +235,8 @@ static int remote_supports_cond_breakpoints (struct target_ops *self); static int remote_can_run_breakpoint_commands (struct target_ops *self); +static int extended_remote_feature_supported (enum extended_feature_type); + /* For "remote". */ static struct cmd_list_element *remote_cmdlist; @@ -383,6 +396,19 @@ struct private_thread_info int core; }; +/* Describes a feature that may be supported in extended mode. */ +struct extended_feature +{ + const char *name; + int supported; +}; + +/* Used to denote whether an extended-mode feature is supported. */ +static struct extended_feature extended_features[] = { +{ "fork_event", 0}, { "vfork_event", 0}, { "vfork_done_event", 0}, +{ "exec_event", 0} +}; + static void free_private_thread_info (struct private_thread_info *info) { @@ -1330,6 +1356,12 @@ enum { /* Support for qXfer:libraries-svr4:read with a non-empty annex. */ PACKET_augmented_libraries_svr4_read_feature, + /* Query for available extended-mode features. */ + PACKET_qExtendedFeatures, + + /* Support for follow fork. */ + PACKET_vFollowFork, + PACKET_MAX }; @@ -3926,7 +3958,9 @@ 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 } }; static char *remote_support_xml; @@ -3972,6 +4006,35 @@ remote_query_supported_append (char *msg, const char *append) return xstrdup (append); } +/* Separate a response item (delimited by ';') from the rest of + the packet. If there's another item after this, we overwrite + the separator (terminated strings are much easier to work with). */ +static char * +extract_response_item (char ** nextp, char **endp) +{ + char *p; + char *next = *nextp; + char *end; + + p = next; + end = strchr (p, ';'); + + if (end == NULL) + { + end = p + strlen (p); + next = end; + } + else + { + *end = '\0'; + next = end + 1; + } + + *nextp = next; + *endp = end; + return p; +} + static void remote_query_supported (void) { @@ -4025,26 +4088,12 @@ remote_query_supported (void) enum packet_support is_supported; char *p, *end, *name_end, *value; - /* First separate out this item from the rest of the packet. If - there's another item after this, we overwrite the separator - (terminated strings are much easier to work with). */ - p = next; - end = strchr (p, ';'); - if (end == NULL) - { - end = p + strlen (p); - next = end; - } - else + /* First separate out this item from the rest of the packet. */ + p = extract_response_item (&next, &end); + if (end == p) { - *end = '\0'; - next = end + 1; - - if (end == p) - { - warning (_("empty item in \"qSupported\" response")); - continue; - } + warning (_("empty item in \"qSupported\" response")); + continue; } name_end = strchr (p, '='); @@ -7787,6 +7836,20 @@ remote_mourn_1 (struct target_ops *target) generic_mourn_inferior (); } +/* Target follow-fork function for extended-remote targets. */ + +static int +extended_remote_follow_fork (struct target_ops *target, int follow_child, + int detach_fork) +{ + if (extended_remote_feature_supported (FORK_EVENT)) + { + /* FIXME: Implement follow-fork here. */ + return -1; + } + return 0; +} + static void extended_remote_mourn_1 (struct target_ops *target) { @@ -11386,6 +11449,75 @@ remote_augmented_libraries_svr4_read (struct target_ops *self) == PACKET_ENABLE); } +/* Ask the target for a list of extended-remote features that are + supported and enabled. */ + +static void +extended_remote_query_supported (void) +{ + if (packet_support (PACKET_qExtendedFeatures) != PACKET_DISABLE) + { + struct remote_state *rs = get_remote_state (); + char *next; + + xsnprintf (rs->buf, get_remote_packet_size (), "qExtendedFeatures"); + putpkt (rs->buf); + getpkt (&rs->buf, &rs->buf_size, 0); + + /* Locate the list of features. */ + next = rs->buf; + next = strchr (next, ':') + 1; + if ((next - rs->buf) >= rs->buf_size) + return; + + while (*next) + { + char *p; + char *end; + int i; + + /* First separate out this item from the rest of the packet. */ + p = extract_response_item (&next, &end); + if (end == p) + { + warning (_("empty item in \"qExtendedFeatures\" response")); + continue; + } + + for (i = EXTENDED_FEATURES_START; i < EXTENDED_FEATURES_COUNT; i++) + { + if (strncmp (p, extended_features[i].name, strlen (p)) == 0) + { + extended_features[i].supported = 1; + if (strcmp (p, "fork_event") == 0) + { + remote_protocol_packets[PACKET_vFollowFork].support + = PACKET_ENABLE; + } + } + } + } + } +} + +/* Predicate for whether the specified feature is supported. */ + +static int +extended_remote_feature_supported (enum extended_feature_type feature) +{ + static int has_queried = 0; + + /* If the extended features list has not been initialized, + make it so. */ + if (!has_queried) + { + extended_remote_query_supported (); + has_queried = 1; + } + + return extended_features[feature].supported; +} + /* Implementation of to_load. */ static void @@ -11535,6 +11667,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; @@ -12105,6 +12238,12 @@ 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); + add_packet_config_cmd (&remote_protocol_packets[PACKET_qExtendedFeatures], + "qExtendedFeatures", "extended_features", 0); + + add_packet_config_cmd (&remote_protocol_packets[PACKET_vFollowFork], + "vFollowFork", "follow-fork", 0); + /* Assert that we've registered commands for all packet configs. */ { int i; -- 1.7.0.4