Target remote mode fork and exec event support

This patch implements support for fork and exec events with target remote
mode Linux targets.  For such targets with Linux kernels 2.5.46 and later,
this enables follow-fork-mode, detach-on-fork and fork and exec
catchpoints.

The changes required to implement this included:

 * Don't exit from gdbserver if there are still active inferiors.

 * Allow changing the active process in remote mode.

 * Enable fork and exec events in remote mode.

 * Print "Ending remote debugging" only when disconnecting.

 * Combine remote_kill and extended_remote_kill into a single function
   that can handle the multiple inferior case for target remote.  Also,
   the same thing for remote_mourn and extended_remote_mourn.

 * Enable process-style ptids in target remote.

 * Remove restriction on multiprocess mode in target remote.

gdb/gdbserver/ChangeLog:

	* server.c (process_serial_event): Don't exit from gdbserver
	in remote mode if there are still active inferiors.

gdb/ChangeLog:

	* inferior.c (number_of_live_inferiors): New function.
	(have_live_inferiors): Use number_of_live_inferiors in place
	of duplicate code.
	* inferior.h (number_of_live_inferiors): Declare new function.
	* remote.c (set_general_process): Remove restriction on target
	remote mode.
	(remote_query_supported): Likewise.
	(remote_detach_1): Exit in target remote mode only when there
	is just one live inferior left.
	(remote_disconnect): Unpush the target directly instead of
	calling remote_mourn.
	(remote_kill): Rewrite function to handle both target remote
	and extended-remote.  Call remote_kill_k.
	(remote_kill_k): New function.
	(extended_remote_kill): Delete function.
	(remote_mourn, extended_remote_mourn): Combine functions into
	one, remote_mourn, and enable extended functionality for target
	remote.
	(remote_pid_to_str): Enable "process" style ptid string for
	target remote.
	(remote_supports_multi_process): Remove restriction on target
	remote mode.
This commit is contained in:
Don Breazeal 2015-12-14 11:18:05 -08:00
parent a8f077dc25
commit 8020350c52
6 changed files with 163 additions and 116 deletions

View File

@ -1,3 +1,28 @@
2015-12-11 Don Breazeal <donb@codesourcery.com>
* inferior.c (number_of_live_inferiors): New function.
(have_live_inferiors): Use number_of_live_inferiors in place
of duplicate code.
* inferior.h (number_of_live_inferiors): Declare new function.
* remote.c (set_general_process): Remove restriction on target
remote mode.
(remote_query_supported): Likewise.
(remote_detach_1): Exit in target remote mode only when there
is just one live inferior left.
(remote_disconnect): Unpush the target directly instead of
calling remote_mourn.
(remote_kill): Rewrite function to handle both target remote
and extended-remote. Call remote_kill_k.
(remote_kill_k): New function.
(extended_remote_kill): Delete function.
(remote_mourn, extended_remote_mourn): Combine functions into
one, remote_mourn, and enable extended functionality for target
remote.
(remote_pid_to_str): Enable "process" style ptid string for
target remote.
(remote_supports_multi_process): Remove restriction on target
remote mode.
2015-12-14 Andrew Burgess <andrew.burgess@embecosm.com>
* i386-tdep.c (i386_mpx_info_bounds): Use TYPE_LENGTH.

View File

@ -1,3 +1,8 @@
2015-12-11 Don Breazeal <donb@codesourcery.com>
* server.c (process_serial_event): Don't exit from gdbserver
in remote mode if there are still active inferiors.
2015-12-11 Yao Qi <yao.qi@linaro.org>
* linux-aarch64-low.c (aarch64_breakpoint_at): Call

View File

@ -3959,9 +3959,11 @@ process_serial_event (void)
discard_queued_stop_replies (pid_to_ptid (pid));
write_ok (own_buf);
if (extended_protocol)
if (extended_protocol || target_running ())
{
/* Treat this like a normal program exit. */
/* There is still at least one inferior remaining or
we are in extended mode, so don't terminate gdbserver,
and instead treat this like a normal program exit. */
last_status.kind = TARGET_WAITKIND_EXITED;
last_status.value.integer = 0;
last_ptid = pid_to_ptid (pid);

View File

@ -459,22 +459,41 @@ have_inferiors (void)
return 0;
}
/* Return the number of live inferiors. We account for the case
where an inferior might have a non-zero pid but no threads, as
in the middle of a 'mourn' operation. */
int
have_live_inferiors (void)
number_of_live_inferiors (void)
{
struct inferior *inf;
int num_inf = 0;
for (inf = inferior_list; inf; inf = inf->next)
if (inf->pid != 0)
{
struct thread_info *tp;
tp = any_thread_of_process (inf->pid);
if (tp && target_has_execution_1 (tp->ptid))
break;
ALL_NON_EXITED_THREADS (tp)
if (tp && ptid_get_pid (tp->ptid) == inf->pid)
if (target_has_execution_1 (tp->ptid))
{
/* Found a live thread in this inferior, go to the next
inferior. */
++num_inf;
break;
}
}
return inf != NULL;
return num_inf;
}
/* Return true if there is at least one live inferior. */
int
have_live_inferiors (void)
{
return number_of_live_inferiors () > 0;
}
/* Prune away any unused inferiors, and then prune away no longer used

View File

@ -490,6 +490,9 @@ extern struct inferior *iterate_over_inferiors (int (*) (struct inferior *,
/* Returns true if the inferior list is not empty. */
extern int have_inferiors (void);
/* Returns the number of live inferiors (real live processes). */
extern int number_of_live_inferiors (void);
/* Returns true if there are any live inferiors in the inferior list
(not cores, not executables, real live processes). */
extern int have_live_inferiors (void);

View File

@ -119,12 +119,12 @@ struct remote_state;
static int remote_vkill (int pid, struct remote_state *rs);
static void remote_kill_k (void);
static void remote_mourn (struct target_ops *ops);
static void extended_remote_restart (void);
static void extended_remote_mourn (struct target_ops *);
static void remote_send (char **buf, long *sizeof_buf_p);
static int readchar (int timeout);
@ -1918,7 +1918,8 @@ demand_private_info (ptid_t ptid)
info->priv = XNEW (struct private_thread_info);
info->private_dtor = free_private_thread_info;
info->priv->core = -1;
info->priv->extra = 0;
info->priv->extra = NULL;
info->priv->name = NULL;
}
return info->priv;
@ -2097,7 +2098,7 @@ set_general_process (void)
struct remote_state *rs = get_remote_state ();
/* If the remote can't handle multiple processes, don't bother. */
if (!rs->extended || !remote_multi_process_p (rs))
if (!remote_multi_process_p (rs))
return;
/* We only need to change the remote current thread if it's pointing
@ -4609,18 +4610,15 @@ 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+");
if (packet_set_cmd_state (PACKET_exec_event_feature)
!= AUTO_BOOLEAN_FALSE)
q = remote_query_supported_append (q, "exec-events+");
}
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+");
if (packet_set_cmd_state (PACKET_exec_event_feature)
!= AUTO_BOOLEAN_FALSE)
q = remote_query_supported_append (q, "exec-events+");
if (packet_set_cmd_state (PACKET_vContSupported) != AUTO_BOOLEAN_FALSE)
q = remote_query_supported_append (q, "vContSupported+");
@ -4975,7 +4973,8 @@ remote_detach_1 (const char *args, int from_tty)
/* Tell the remote target to detach. */
remote_detach_pid (pid);
if (from_tty && !rs->extended)
/* Exit only if this is the only active inferior. */
if (from_tty && !rs->extended && number_of_live_inferiors () == 1)
puts_filtered (_("Ending remote debugging.\n"));
/* Check to see if we are detaching a fork parent. Note that if we
@ -5071,10 +5070,11 @@ remote_disconnect (struct target_ops *target, const char *args, int from_tty)
if (args)
error (_("Argument given to \"disconnect\" when remotely debugging."));
/* Make sure we unpush even the extended remote targets; mourn
won't do it. So call remote_mourn directly instead of
target_mourn_inferior. */
remote_mourn (target);
/* Make sure we unpush even the extended remote targets. Calling
target_mourn_inferior won't unpush, and remote_mourn won't
unpush if there is more than one inferior left. */
unpush_target (target);
generic_mourn_inferior ();
if (from_tty)
puts_filtered ("Ending remote debugging.\n");
@ -8800,42 +8800,53 @@ kill_new_fork_children (int pid, struct remote_state *rs)
}
/* Target hook to kill the current inferior. */
static void
remote_kill (struct target_ops *ops)
{
int res = -1;
int pid = ptid_get_pid (inferior_ptid);
struct remote_state *rs = get_remote_state ();
/* Catch errors so the user can quit from gdb even when we
aren't on speaking terms with the remote system. */
TRY
if (packet_support (PACKET_vKill) != PACKET_DISABLE)
{
putpkt ("k");
}
CATCH (ex, RETURN_MASK_ERROR)
{
if (ex.error == TARGET_CLOSE_ERROR)
/* If we're stopped while forking and we haven't followed yet,
kill the child task. We need to do this before killing the
parent task because if this is a vfork then the parent will
be sleeping. */
kill_new_fork_children (pid, rs);
res = remote_vkill (pid, rs);
if (res == 0)
{
/* If we got an (EOF) error that caused the target
to go away, then we're done, that's what we wanted.
"k" is susceptible to cause a premature EOF, given
that the remote server isn't actually required to
reply to "k", and it can happen that it doesn't
even get to reply ACK to the "k". */
target_mourn_inferior ();
return;
}
/* Otherwise, something went wrong. We didn't actually kill
the target. Just propagate the exception, and let the
user or higher layers decide what to do. */
throw_exception (ex);
}
END_CATCH
/* We've killed the remote end, we get to mourn it. Since this is
target remote, single-process, mourning the inferior also
unpushes remote_ops. */
target_mourn_inferior ();
/* If we are in 'target remote' mode and we are killing the only
inferior, then we will tell gdbserver to exit and unpush the
target. */
if (res == -1 && !remote_multi_process_p (rs)
&& number_of_live_inferiors () == 1)
{
remote_kill_k ();
/* We've killed the remote end, we get to mourn it. If we are
not in extended mode, mourning the inferior also unpushes
remote_ops from the target stack, which closes the remote
connection. */
target_mourn_inferior ();
return;
}
error (_("Can't kill process"));
}
/* Send a kill request to the target using the 'vKill' packet. */
static int
remote_vkill (int pid, struct remote_state *rs)
{
@ -8861,56 +8872,53 @@ remote_vkill (int pid, struct remote_state *rs)
}
}
/* Send a kill request to the target using the 'k' packet. */
static void
extended_remote_kill (struct target_ops *ops)
remote_kill_k (void)
{
int res;
int pid = ptid_get_pid (inferior_ptid);
struct remote_state *rs = get_remote_state ();
/* If we're stopped while forking and we haven't followed yet, kill the
child task. We need to do this before killing the parent task
because if this is a vfork then the parent will be sleeping. */
kill_new_fork_children (pid, rs);
res = remote_vkill (pid, rs);
if (res == -1 && !(rs->extended && remote_multi_process_p (rs)))
/* Catch errors so the user can quit from gdb even when we
aren't on speaking terms with the remote system. */
TRY
{
/* Don't try 'k' on a multi-process aware stub -- it has no way
to specify the pid. */
putpkt ("k");
#if 0
getpkt (&rs->buf, &rs->buf_size, 0);
if (rs->buf[0] != 'O' || rs->buf[0] != 'K')
res = 1;
#else
/* Don't wait for it to die. I'm not really sure it matters whether
we do or not. For the existing stubs, kill is a noop. */
res = 0;
#endif
}
CATCH (ex, RETURN_MASK_ERROR)
{
if (ex.error == TARGET_CLOSE_ERROR)
{
/* If we got an (EOF) error that caused the target
to go away, then we're done, that's what we wanted.
"k" is susceptible to cause a premature EOF, given
that the remote server isn't actually required to
reply to "k", and it can happen that it doesn't
even get to reply ACK to the "k". */
return;
}
if (res != 0)
error (_("Can't kill process"));
target_mourn_inferior ();
/* Otherwise, something went wrong. We didn't actually kill
the target. Just propagate the exception, and let the
user or higher layers decide what to do. */
throw_exception (ex);
}
END_CATCH
}
static void
remote_mourn (struct target_ops *target)
{
unpush_target (target);
/* remote_close takes care of doing most of the clean up. */
generic_mourn_inferior ();
}
static void
extended_remote_mourn (struct target_ops *target)
{
struct remote_state *rs = get_remote_state ();
/* In 'target remote' mode with one inferior, we close the connection. */
if (!rs->extended && number_of_live_inferiors () <= 1)
{
unpush_target (target);
/* remote_close takes care of doing most of the clean up. */
generic_mourn_inferior ();
return;
}
/* In case we got here due to an error, but we're going to stay
connected. */
rs->waiting_for_stop_reply = 0;
@ -8940,10 +8948,7 @@ extended_remote_mourn (struct target_ops *target)
current thread. */
record_currthread (rs, minus_one_ptid);
/* Unlike "target remote", we do not want to unpush the target; then
the next time the user says "run", we won't be connected. */
/* Call common code to mark the inferior as not running. */
/* Call common code to mark the inferior as not running. */
generic_mourn_inferior ();
if (!have_inferiors ())
@ -10465,7 +10470,7 @@ remote_pid_to_str (struct target_ops *ops, ptid_t ptid)
{
if (ptid_equal (magic_null_ptid, ptid))
xsnprintf (buf, sizeof buf, "Thread <main>");
else if (rs->extended && remote_multi_process_p (rs))
else if (remote_multi_process_p (rs))
if (ptid_get_lwp (ptid) == 0)
return normal_pid_to_str (ptid);
else
@ -11635,11 +11640,7 @@ remote_supports_multi_process (struct target_ops *self)
{
struct remote_state *rs = get_remote_state ();
/* Only extended-remote handles being attached to multiple
processes, even though plain remote can use the multi-process
thread id extensions, so that GDB knows the target process's
PID. */
return rs->extended && remote_multi_process_p (rs);
return remote_multi_process_p (rs);
}
static int
@ -13071,6 +13072,14 @@ Specify the serial device it is connected to\n\
remote_ops.to_btrace_conf = remote_btrace_conf;
remote_ops.to_augmented_libraries_svr4_read =
remote_augmented_libraries_svr4_read;
remote_ops.to_follow_fork = remote_follow_fork;
remote_ops.to_follow_exec = remote_follow_exec;
remote_ops.to_insert_fork_catchpoint = remote_insert_fork_catchpoint;
remote_ops.to_remove_fork_catchpoint = remote_remove_fork_catchpoint;
remote_ops.to_insert_vfork_catchpoint = remote_insert_vfork_catchpoint;
remote_ops.to_remove_vfork_catchpoint = remote_remove_vfork_catchpoint;
remote_ops.to_insert_exec_catchpoint = remote_insert_exec_catchpoint;
remote_ops.to_remove_exec_catchpoint = remote_remove_exec_catchpoint;
}
/* Set up the extended remote vector by making a copy of the standard
@ -13089,27 +13098,11 @@ 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_mourn_inferior = extended_remote_mourn;
extended_remote_ops.to_detach = extended_remote_detach;
extended_remote_ops.to_attach = extended_remote_attach;
extended_remote_ops.to_post_attach = extended_remote_post_attach;
extended_remote_ops.to_kill = extended_remote_kill;
extended_remote_ops.to_supports_disable_randomization
= extended_remote_supports_disable_randomization;
extended_remote_ops.to_follow_fork = remote_follow_fork;
extended_remote_ops.to_follow_exec = remote_follow_exec;
extended_remote_ops.to_insert_fork_catchpoint
= remote_insert_fork_catchpoint;
extended_remote_ops.to_remove_fork_catchpoint
= remote_remove_fork_catchpoint;
extended_remote_ops.to_insert_vfork_catchpoint
= remote_insert_vfork_catchpoint;
extended_remote_ops.to_remove_vfork_catchpoint
= remote_remove_vfork_catchpoint;
extended_remote_ops.to_insert_exec_catchpoint
= remote_insert_exec_catchpoint;
extended_remote_ops.to_remove_exec_catchpoint
= remote_remove_exec_catchpoint;
}
static int