This patch implements follow-fork for vfork on 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.
gdb/gdbserver/ChangeLog:
* 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/ChangeLog:
* 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.
+2015-05-12 Don Breazeal <donb@codesourcery.com>
+
+ * 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.
+
2015-05-12 Don Breazeal <donb@codesourcery.com>
* linux-nat.c (linux_nat_ptrace_options): New function.
+2015-05-12 Don Breazeal <donb@codesourcery.com>
+
+ * 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.
+
2015-05-12 Don Breazeal <donb@codesourcery.com>
* linux-aarch64-low.c (aarch64_linux_new_fork): New function.
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;
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;
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. */
/* 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);
}
if (report_fork_events)
options |= PTRACE_O_TRACEFORK;
+ if (report_vfork_events)
+ options |= (PTRACE_O_TRACEVFORK | PTRACE_O_TRACEVFORKDONE);
+
return options;
}
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. */
{
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 = (status->kind == TARGET_WAITKIND_FORKED
+ ? "fork" : "vfork");
- sprintf (buf, "T%02xfork:", signal);
+ sprintf (buf, "T%02x%s:", signal, event);
buf += strlen (buf);
buf = write_ptid (buf, status->value.related_pid);
strcat (buf, ";");
else
sprintf (buf, "X%02x", status->value.sig);
break;
+ case TARGET_WAITKIND_VFORK_DONE:
+ if (report_vfork_events)
+ {
+ enum gdb_signal signal = GDB_SIGNAL_TRAP;
+
+ sprintf (buf, "T%02xvforkdone:;", signal);
+ }
+ else
+ sprintf (buf, "T%02x", GDB_SIGNAL_0);
+ break;
default:
error ("unhandled waitkind");
break;
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
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;
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)))
{
/* When following the parent and detaching the child, we detach
the child here. For the case of following the child and
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;