From patchwork Fri Apr 10 17:09:44 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Don Breazeal X-Patchwork-Id: 6144 Received: (qmail 109265 invoked by alias); 10 Apr 2015 17:11:09 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 109231 invoked by uid 89); 10 Apr 2015 17:11:08 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.2 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_LOW, SPF_PASS 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; Fri, 10 Apr 2015 17:11:05 +0000 Received: from svr-orw-fem-06.mgc.mentorg.com ([147.34.97.120]) by relay1.mentorg.com with esmtp id 1YgcSM-0001gg-F5 from Don_Breazeal@mentor.com for gdb-patches@sourceware.org; Fri, 10 Apr 2015 10:11:02 -0700 Received: from build4-lucid-cs (147.34.91.1) by SVR-ORW-FEM-06.mgc.mentorg.com (147.34.97.120) with Microsoft SMTP Server id 14.3.224.2; Fri, 10 Apr 2015 10:11:02 -0700 Received: by build4-lucid-cs (Postfix, from userid 1905) id 0104940F27; Fri, 10 Apr 2015 10:11:01 -0700 (PDT) From: Don Breazeal To: Subject: [PATCH v7 5/7] Remote follow vfork Date: Fri, 10 Apr 2015 10:09:44 -0700 Message-ID: <1428685786-18094-6-git-send-email-donb@codesourcery.com> In-Reply-To: <1428685786-18094-1-git-send-email-donb@codesourcery.com> References: <1428685786-18094-1-git-send-email-donb@codesourcery.com> MIME-Version: 1.0 X-IsSubscribed: yes Hi Pedro, This version of the patch incorporates changes based on your comments on the previous version, as outlined below. On 3/24/2015 5:28 AM, Pedro Alves wrote: > On 03/17/2015 08:56 PM, Don Breazeal wrote: > >> diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c >> index dc43e38..42c3ec5 100644 >> --- a/gdb/gdbserver/remote-utils.c >> +++ b/gdb/gdbserver/remote-utils.c >> @@ -1115,15 +1115,19 @@ prepare_resume_reply (char *buf, ptid_t ptid, >> { >> case TARGET_WAITKIND_STOPPED: >> case TARGET_WAITKIND_FORKED: >> + case TARGET_WAITKIND_VFORKED: >> { >> struct thread_info *saved_thread; >> const char **regp; >> struct regcache *regcache; >> >> - if (status->kind == TARGET_WAITKIND_FORKED && report_fork_events) >> + if ((status->kind == TARGET_WAITKIND_FORKED && report_fork_events) >> + || (status->kind == TARGET_WAITKIND_VFORKED >> + && report_vfork_events)) >> { >> enum gdb_signal signal = GDB_SIGNAL_TRAP; >> - const char *event = "xfork"; >> + const char *event = (status->kind == TARGET_WAITKIND_FORKED >> + ? "xfork" : "vfork"); >> >> sprintf (buf, "T%02x%s:", signal, event); >> buf += strlen (buf); >> @@ -1245,6 +1249,15 @@ prepare_resume_reply (char *buf, ptid_t ptid, >> else >> sprintf (buf, "X%02x", status->value.sig); >> break; >> + case TARGET_WAITKIND_VFORK_DONE: >> + if (multi_process) >> + { >> + enum gdb_signal signal = GDB_SIGNAL_TRAP; >> + const char *event = "vforkdone"; >> + > > Should only include vforkdone if report_vfork_events is true, I'd think. If we get one of these events (fork, vfork, vforkdone) and report_xxx_events is not set, then it is a bug, so I put those flags into asserts for all three events to ensure proper behavior. > >> + sprintf (buf, "T%02x%s:;", signal, event); >> + } >> + break; >> default: >> error ("unhandled waitkind"); >> break; >> diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h >> index 696a24e..09a5624 100644 >> --- a/gdb/gdbserver/server.h >> +++ b/gdb/gdbserver/server.h >> @@ -85,6 +85,7 @@ extern int disable_packet_qfThreadInfo; >> extern int run_once; >> extern int multi_process; >> extern int report_fork_events; >> +extern int report_vfork_events; >> extern int non_stop; >> >> /* True if the "swbreak+" feature is active. In that case, GDB wants >> diff --git a/gdb/remote.c b/gdb/remote.c >> index 899c7a2..d1ba62d 100644 >> --- a/gdb/remote.c >> +++ b/gdb/remote.c >> @@ -4526,15 +4526,20 @@ remote_follow_fork (struct target_ops *ops, int follow_child, >> { >> struct remote_state *rs = get_remote_state (); >> >> + /* If fork events aren't supported, then return. We know that if >> + fork events are supported, then so are vfork events, since they >> + were both introduced in the same version of the linux kernel. */ > > "Linux", caps. > > But this really doesn't make sense -- if we define different > qSupported features for fork and vfork, then we should check > them separately. We don't know (and shouldn't care) whether > we're debugging against a Linux target here. The packets/features > should work with other OSs. Point taken. I've made that change. > >> if (remote_fork_event_p (rs)) >> { >> if (detach_fork && !follow_child) >> { >> ptid_t parent_ptid; >> ptid_t child_ptid; >> + enum target_waitkind kind; >> > > Thanks, > Pedro Alves > Thanks, --Don This patch implements follow-fork for vfork on remote and extended-remote Linux targets. The implementation follows the native implementation as much as possible. Most of the work is done on the GDB side in the existing code now in infrun.c. GDBserver just has to report the events and do a little bookkeeping. Implementation includes: * enabling VFORK events by adding ptrace options for VFORK and VFORK_DONE to linux-low.c:linux_low_ptrace_options. * handling VFORK and VFORK_DONE events in linux-low.c:handle_extended_wait and reporting them to GDB. * including VFORK and VFORK_DONE events in the predicate linux-low.c:extended_event_reported. * adding support for VFORK and VFORK_DONE events in RSP by adding stop reasons "vfork" and "vforkdone" to the 'T' Stop Reply Packet in both gdbserver/remote-utils.c and gdb/remote.c. Tested on x64 Ubuntu Lucid, native, remote, extended-remote. Thanks --Don gdb/gdbserver/ 2015-04-08 Don Breazeal * linux-low.c (handle_extended_wait): Handle PTRACE_EVENT_FORK and PTRACE_EVENT_VFORK_DONE. (linux_low_ptrace_options, extended_event_reported): Add vfork events. * remote-utils.c (prepare_resume_reply): New stop reasons "vfork" and "vforkdone" for RSP 'T' Stop Reply Packet. * server.h (report_vfork_events): Declare global variable. gdb/ 2015-04-08 Don Breazeal * remote.c (remove_vfork_event_p): New function. (remote_follow_fork): Add vfork event type to event checking. (remote_parse_stop_reply): New stop reasons "vfork" and "vforkdone" for RSP 'T' Stop Reply Packet. --- gdb/gdbserver/linux-low.c | 26 ++++++++++++++++++++++---- gdb/gdbserver/remote-utils.c | 25 +++++++++++++++++++++---- gdb/gdbserver/server.h | 1 + gdb/remote.c | 22 +++++++++++++++++++++- 4 files changed, 65 insertions(+), 9 deletions(-) diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index 645c94f..0c3dfeb 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -425,7 +425,8 @@ handle_extended_wait (struct lwp_info *event_lwp, int wstat) struct thread_info *event_thr = get_lwp_thread (event_lwp); struct lwp_info *new_lwp; - if ((event == PTRACE_EVENT_FORK) || (event == PTRACE_EVENT_CLONE)) + if ((event == PTRACE_EVENT_FORK) || (event == PTRACE_EVENT_VFORK) + || (event == PTRACE_EVENT_CLONE)) { ptid_t ptid; unsigned long new_pid; @@ -451,7 +452,7 @@ handle_extended_wait (struct lwp_info *event_lwp, int wstat) warning ("wait returned unexpected status 0x%x", status); } - if (event == PTRACE_EVENT_FORK) + if (event == PTRACE_EVENT_FORK || event == PTRACE_EVENT_VFORK) { struct process_info *parent_proc; struct process_info *child_proc; @@ -494,8 +495,13 @@ handle_extended_wait (struct lwp_info *event_lwp, int wstat) the_low_target.new_fork (parent_proc, child_proc); /* Save fork info in the parent thread. */ - event_lwp->waitstatus.kind = TARGET_WAITKIND_FORKED; + if (event == PTRACE_EVENT_FORK) + event_lwp->waitstatus.kind = TARGET_WAITKIND_FORKED; + else if (event == PTRACE_EVENT_VFORK) + event_lwp->waitstatus.kind = TARGET_WAITKIND_VFORKED; + event_lwp->waitstatus.value.related_pid = ptid; + /* The status_pending field contains bits denoting the extended event, so when the pending event is handled, the handler will look at lwp->waitstatus. */ @@ -538,6 +544,13 @@ handle_extended_wait (struct lwp_info *event_lwp, int wstat) /* Don't report the event. */ return 1; } + else if (event == PTRACE_EVENT_VFORK_DONE) + { + event_lwp->waitstatus.kind = TARGET_WAITKIND_VFORK_DONE; + + /* Report the event. */ + return 0; + } internal_error (__FILE__, __LINE__, _("unknown ptrace event %d"), event); } @@ -2010,6 +2023,9 @@ linux_low_ptrace_options (int attached) if (report_fork_events) options |= PTRACE_O_TRACEFORK; + if (report_vfork_events) + options |= (PTRACE_O_TRACEVFORK | PTRACE_O_TRACEVFORKDONE); + return options; } @@ -2714,7 +2730,9 @@ extended_event_reported (const struct target_waitstatus *waitstatus) if (waitstatus == NULL) return 0; - return (waitstatus->kind == TARGET_WAITKIND_FORKED); + return (waitstatus->kind == TARGET_WAITKIND_FORKED + || waitstatus->kind == TARGET_WAITKIND_VFORKED + || waitstatus->kind == TARGET_WAITKIND_VFORK_DONE); } /* Wait for process, returns status. */ diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c index 5c1982a..43e7916 100644 --- a/gdb/gdbserver/remote-utils.c +++ b/gdb/gdbserver/remote-utils.c @@ -1115,17 +1115,25 @@ prepare_resume_reply (char *buf, ptid_t ptid, { case TARGET_WAITKIND_STOPPED: case TARGET_WAITKIND_FORKED: + case TARGET_WAITKIND_VFORKED: { struct thread_info *saved_thread; const char **regp; struct regcache *regcache; - if (status->kind == TARGET_WAITKIND_FORKED && report_fork_events) + if (status->kind == TARGET_WAITKIND_FORKED || status->kind == TARGET_WAITKIND_VFORKED) { enum gdb_signal signal = GDB_SIGNAL_TRAP; - - gdb_assert (report_fork_events); - sprintf (buf, "T%02xfork:", signal); + if (status->kind == TARGET_WAITKIND_FORKED) + { + gdb_assert (report_fork_events); + sprintf (buf, "T%02xfork:", signal); + } + else + { + gdb_assert (report_vfork_events); + sprintf (buf, "T%02xvfork:", signal); + } buf += strlen (buf); buf = write_ptid (buf, status->value.related_pid); strcat (buf, ";"); @@ -1245,6 +1253,15 @@ prepare_resume_reply (char *buf, ptid_t ptid, else sprintf (buf, "X%02x", status->value.sig); break; + case TARGET_WAITKIND_VFORK_DONE: + if (multi_process) + { + enum gdb_signal signal = GDB_SIGNAL_TRAP; + + gdb_assert (report_vfork_events); + sprintf (buf, "T%02xvforkdone:;", signal); + } + break; default: error ("unhandled waitkind"); break; diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h index 696a24e..09a5624 100644 --- a/gdb/gdbserver/server.h +++ b/gdb/gdbserver/server.h @@ -85,6 +85,7 @@ extern int disable_packet_qfThreadInfo; extern int run_once; extern int multi_process; extern int report_fork_events; +extern int report_vfork_events; extern int non_stop; /* True if the "swbreak+" feature is active. In that case, GDB wants diff --git a/gdb/remote.c b/gdb/remote.c index 6176620..4e65092 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -1469,6 +1469,14 @@ remote_fork_event_p (struct remote_state *rs) return packet_support (PACKET_fork_event_feature) == PACKET_ENABLE; } +/* Returns true if vfork events are supported. */ + +static int +remote_vfork_event_p (struct remote_state *rs) +{ + return packet_support (PACKET_vfork_event_feature) == PACKET_ENABLE; +} + /* 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; @@ -4528,8 +4536,10 @@ remote_follow_fork (struct target_ops *ops, int follow_child, int detach_fork) { struct remote_state *rs = get_remote_state (); + enum target_waitkind kind = inferior_thread ()->pending_follow.kind; - if (remote_fork_event_p (rs)) + if ((kind == TARGET_WAITKIND_FORKED && remote_fork_event_p (rs)) + || (kind == TARGET_WAITKIND_VFORKED && remote_vfork_event_p (rs))) { if (detach_fork && !follow_child) { @@ -5712,6 +5722,16 @@ Packet: '%s'\n"), event->ws.value.related_pid = read_ptid (++p1, &p); event->ws.kind = TARGET_WAITKIND_FORKED; } + else if (strncmp (p, "vfork", p1 - p) == 0) + { + event->ws.value.related_pid = read_ptid (++p1, &p); + event->ws.kind = TARGET_WAITKIND_VFORKED; + } + else if (strncmp (p, "vforkdone", p1 - p) == 0) + { + event->ws.kind = TARGET_WAITKIND_VFORK_DONE; + p = skip_to_semicolon (p1 + 1); + } else { ULONGEST pnum;