@@ -77,8 +77,11 @@ vFile:fstat:
Return information about files on the remote system.
T Stop Reply Packet's reason
- The T stop reply packet supports a new stop reason 'xfork', which
- signifies that the specified inferior has executed a fork.
+ The T stop reply packet supports new stop reasons 'xfork', 'vfork',
+ and 'vforkdone'. The 'xfork' and 'vfork' reasons signify that the
+ specified inferior has executed a fork or vfork, respectively. The
+ 'vforkdone' reason signifies that the a vforked child process has
+ executed either an exec or exit.
* The info record command now shows the recording format and the
branch tracing configuration for the current thread when using
@@ -102,8 +105,8 @@ Itanium running HP-UX ia64-*-hpux*
GDB's qSupported query.
GDBserver extended-remote Linux targets now provides basic support
- for fork events. This enables follow-fork-mode and detach-on-fork
- for those targets with Linux kernels 2.5.60 and later.
+ for fork and vfork events. This enables follow-fork-mode and
+ detach-on-fork for those targets with Linux kernels 2.5.60 and later.
*** Changes in GDB 7.9
@@ -35206,6 +35206,20 @@ The packet indicates that @code{fork} was called, and @var{r}
is the ptid of the new child process. This packet is only
applicable to targets that support fork events.
+@cindex vfork events, remote reply
+@item vfork
+The packet indicates that @code{vfork} was called, and @var{r}
+is the ptid of the new child process. This packet is only
+applicable to targets that support vfork events.
+
+@cindex vforkdone events, remote reply
+@item vforkdone
+The packet indicates that a child process created by a vfork
+has either called @code{exec} or terminated, so that the
+address spaces of the parent and child process are no longer
+shared. The @var{r} part is ignored. This packet is only
+applicable to targets that support vforkdone events.
+
@cindex replay log events, remote reply
@item replaylog
The packet indicates that the target cannot continue replaying
@@ -382,7 +382,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;
@@ -408,7 +409,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;
@@ -451,8 +452,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. */
@@ -495,6 +501,14 @@ handle_extended_wait (struct lwp_info *event_lwp, int wstat)
/* Don't report the event. */
return 1;
}
+ else if (event == PTRACE_EVENT_VFORK_DONE)
+ {
+ struct lwp_info *parent_lwp;
+
+ parent_lwp = get_thread_lwp (event_thr);
+ parent_lwp->waitstatus.kind = TARGET_WAITKIND_VFORK_DONE;
+ return 0;
+ }
internal_error (__FILE__, __LINE__, _("unknown ptrace event %d"), event);
}
@@ -1899,6 +1913,8 @@ linux_low_enable_events (pid_t pid, int attached)
{
if (!report_fork_events)
linux_ptrace_clear_flags (PTRACE_O_TRACEFORK);
+ if (!report_vfork_events)
+ linux_ptrace_clear_flags (PTRACE_O_TRACEVFORK);
linux_enable_event_reporting (pid, attached);
}
@@ -2590,7 +2606,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. */
@@ -6458,6 +6476,8 @@ initialize_low (void)
initialize_low_arch ();
/* Enable extended ptrace events. */
- linux_ptrace_set_additional_flags (PTRACE_O_TRACEFORK);
+ linux_ptrace_set_additional_flags (PTRACE_O_TRACEFORK
+ | PTRACE_O_TRACEVFORK
+ | PTRACE_O_TRACEVFORKDONE);
linux_check_ptrace_features ();
}
@@ -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";
+
+ sprintf (buf, "T%02x%s:;", signal, event);
+ }
+ break;
default:
error ("unhandled waitkind");
break;
@@ -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
@@ -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. */
if (remote_fork_event_p (rs))
{
if (detach_fork && !follow_child)
{
ptid_t parent_ptid;
ptid_t child_ptid;
+ enum target_waitkind kind;
- gdb_assert (inferior_thread ()->pending_follow.kind
- == TARGET_WAITKIND_FORKED);
+ kind = inferior_thread ()->pending_follow.kind;
+ gdb_assert (kind == TARGET_WAITKIND_FORKED
+ || kind == TARGET_WAITKIND_VFORKED);
/* remote_detach_1 detaches inferior_ptid, which is currently
the ptid of the parent. Switch inferior_ptid to the ptid
@@ -5724,6 +5729,23 @@ 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)
+ {
+ char *p_temp;
+
+ p1++;
+ p_temp = p1;
+ while (*p_temp && *p_temp != ';')
+ p_temp++;
+
+ event->ws.kind = TARGET_WAITKIND_VFORK_DONE;
+ p = p_temp;
+ }
else
{
ULONGEST pnum;