static int readchar (int timeout);
-static void remote_kill (void);
+static void remote_kill (struct target_ops *ops);
static int tohex (int nib);
PACKET_vKill,
PACKET_qXfer_siginfo_read,
PACKET_qXfer_siginfo_write,
+ PACKET_qAttached,
PACKET_MAX
};
static ptid_t general_thread;
static ptid_t continue_thread;
+/* Find out if the stub attached to PID (and hence GDB should offer to
+ detach instead of killing it when bailing out). */
+
+static int
+remote_query_attached (int pid)
+{
+ struct remote_state *rs = get_remote_state ();
+
+ if (remote_protocol_packets[PACKET_qAttached].support == PACKET_DISABLE)
+ return 0;
+
+ if (remote_multi_process_p (rs))
+ sprintf (rs->buf, "qAttached:%x", pid);
+ else
+ sprintf (rs->buf, "qAttached");
+
+ putpkt (rs->buf);
+ getpkt (&rs->buf, &rs->buf_size, 0);
+
+ switch (packet_ok (rs->buf,
+ &remote_protocol_packets[PACKET_qAttached]))
+ {
+ case PACKET_OK:
+ if (strcmp (rs->buf, "1") == 0)
+ return 1;
+ break;
+ case PACKET_ERROR:
+ warning (_("Remote failure reply: %s"), rs->buf);
+ break;
+ case PACKET_UNKNOWN:
+ break;
+ }
+
+ return 0;
+}
+
/* Add PID to GDB's inferior table. Since we can be connected to a
remote system before before knowing about any inferior, mark the
- target with execution when we find the first inferior. */
+ target with execution when we find the first inferior. If ATTACHED
+ is 1, then we had just attached to this inferior. If it is 0, then
+ we just created this inferior. If it is -1, then try querying the
+ remote stub to find out if it had attached to the inferior or
+ not. */
static struct inferior *
-remote_add_inferior (int pid)
+remote_add_inferior (int pid, int attached)
{
struct remote_state *rs = get_remote_state ();
struct inferior *inf;
+ /* Check whether this process we're learning about is to be
+ considered attached, or if is to be considered to have been
+ spawned by the stub. */
+ if (attached == -1)
+ attached = remote_query_attached (pid);
+
inf = add_inferior (pid);
+ inf->attach_flag = attached;
+
/* This may be the first inferior we hear about. */
if (!target_has_execution)
{
if (!in_thread_list (currthread))
{
struct inferior *inf = NULL;
+ int pid = ptid_get_pid (currthread);
- if (ptid_equal (pid_to_ptid (ptid_get_pid (currthread)), inferior_ptid))
+ if (ptid_is_pid (inferior_ptid)
+ && pid == ptid_get_pid (inferior_ptid))
{
/* inferior_ptid has no thread member yet. This can happen
with the vAttach -> remote_wait,"TAAthread:" path if the
stub doesn't support qC. This is the first stop reported
after an attach, so this is the main thread. Update the
ptid in the thread list. */
- thread_change_ptid (inferior_ptid, currthread);
+ if (in_thread_list (pid_to_ptid (pid)))
+ thread_change_ptid (inferior_ptid, currthread);
+ else
+ {
+ remote_add_thread (currthread, running);
+ inferior_ptid = currthread;
+ }
return;
}
may not know about it yet. Add it before adding its child
thread, so notifications are emitted in a sensible order. */
if (!in_inferior_list (ptid_get_pid (currthread)))
- inf = remote_add_inferior (ptid_get_pid (currthread));
+ inf = remote_add_inferior (ptid_get_pid (currthread), -1);
/* This is really a new thread. Add it. */
remote_add_thread (currthread, running);
delete_async_event_handler (&remote_async_inferior_event_token);
if (remote_async_get_pending_events_token)
delete_async_event_handler (&remote_async_get_pending_events_token);
-
- generic_mourn_inferior ();
}
/* Query the remote side for the text, data and bss offsets. */
/* Now, if we have thread information, update inferior_ptid. */
inferior_ptid = remote_current_thread (inferior_ptid);
- remote_add_inferior (ptid_get_pid (inferior_ptid));
+ remote_add_inferior (ptid_get_pid (inferior_ptid), -1);
/* Always add the main thread. */
add_thread_silent (inferior_ptid);
}
else
{
+ /* Clear WFI global state. Do this before finding about new
+ threads and inferiors, and setting the current inferior.
+ Otherwise we would clear the proceed status of the current
+ inferior when we want its stop_soon state to be preserved
+ (see notice_new_inferior). */
+ init_wait_for_inferior ();
+
/* In non-stop, we will either get an "OK", meaning that there
are no stopped threads at this time; or, a regular stop
reply. In the latter case, there may be more than one thread
remote_check_symbols (symfile_objfile);
}
- /* If code is shared between processes, then breakpoints are global
- too; Insert them now. */
- if (gdbarch_has_global_solist (target_gdbarch)
+ /* If breakpoints are global, insert them now. */
+ if (gdbarch_has_global_breakpoints (target_gdbarch)
&& breakpoints_always_inserted_mode ())
insert_breakpoints ();
}
int pid;
char *dummy;
char *wait_status = NULL;
- struct inferior *inf;
if (!args)
error_no_arg (_("process-id to attach"));
error (_("Attaching to %s failed"),
target_pid_to_str (pid_to_ptid (pid)));
+ remote_add_inferior (pid, 1);
+
inferior_ptid = pid_to_ptid (pid);
- /* Now, if we have thread information, update inferior_ptid. */
- inferior_ptid = remote_current_thread (inferior_ptid);
+ if (non_stop)
+ {
+ struct thread_info *thread;
- inf = remote_add_inferior (pid);
- inf->attach_flag = 1;
+ /* Get list of threads. */
+ remote_threads_info (target);
- if (non_stop)
- /* Get list of threads. */
- remote_threads_info (target);
+ thread = first_thread_of_process (pid);
+ if (thread)
+ inferior_ptid = thread->ptid;
+ else
+ inferior_ptid = pid_to_ptid (pid);
+
+ /* Invalidate our notion of the remote current thread. */
+ record_currthread (minus_one_ptid);
+ }
else
- /* Add the main thread to the thread list. */
- add_thread_silent (inferior_ptid);
+ {
+ /* Now, if we have thread information, update inferior_ptid. */
+ inferior_ptid = remote_current_thread (inferior_ptid);
+
+ /* Add the main thread to the thread list. */
+ add_thread_silent (inferior_ptid);
+ }
/* Next, if the target can specify a description, read it. We do
this before anything involving memory or registers. */
packet_ok (buf, &remote_protocol_packets[PACKET_vCont]);
}
+/* Helper function for building "vCont" resumptions. Write a
+ resumption to P. ENDP points to one-passed-the-end of the buffer
+ we're allowed to write to. Returns BUF+CHARACTERS_WRITTEN. The
+ thread to be resumed is PTID; STEP and SIGGNAL indicate whether the
+ resumed thread should be single-stepped and/or signalled. If PTID
+ equals minus_one_ptid, then all threads are resumed; if PTID
+ represents a process, then all threads of the process are resumed;
+ the thread to be stepped and/or signalled is given in the global
+ INFERIOR_PTID. */
+
+static char *
+append_resumption (char *p, char *endp,
+ ptid_t ptid, int step, enum target_signal siggnal)
+{
+ struct remote_state *rs = get_remote_state ();
+
+ if (step && siggnal != TARGET_SIGNAL_0)
+ p += xsnprintf (p, endp - p, ";S%02x", siggnal);
+ else if (step)
+ p += xsnprintf (p, endp - p, ";s");
+ else if (siggnal != TARGET_SIGNAL_0)
+ p += xsnprintf (p, endp - p, ";C%02x", siggnal);
+ else
+ p += xsnprintf (p, endp - p, ";c");
+
+ if (remote_multi_process_p (rs) && ptid_is_pid (ptid))
+ {
+ ptid_t nptid;
+
+ /* All (-1) threads of process. */
+ nptid = ptid_build (ptid_get_pid (ptid), 0, -1);
+
+ p += xsnprintf (p, endp - p, ":");
+ p = write_ptid (p, endp, nptid);
+ }
+ else if (!ptid_equal (ptid, minus_one_ptid))
+ {
+ p += xsnprintf (p, endp - p, ":");
+ p = write_ptid (p, endp, ptid);
+ }
+
+ return p;
+}
+
/* Resume the remote inferior by using a "vCont" packet. The thread
to be resumed is PTID; STEP and SIGGNAL indicate whether the
resumed thread should be single-stepped and/or signalled. If PTID
about overflowing BUF. Should there be a generic
"multi-part-packet" packet? */
+ p += xsnprintf (p, endp - p, "vCont");
+
if (ptid_equal (ptid, magic_null_ptid))
{
/* MAGIC_NULL_PTID means that we don't have any active threads,
so we don't have any TID numbers the inferior will
understand. Make sure to only send forms that do not specify
a TID. */
- if (step && siggnal != TARGET_SIGNAL_0)
- xsnprintf (p, endp - p, "vCont;S%02x", siggnal);
- else if (step)
- xsnprintf (p, endp - p, "vCont;s");
- else if (siggnal != TARGET_SIGNAL_0)
- xsnprintf (p, endp - p, "vCont;C%02x", siggnal);
- else
- xsnprintf (p, endp - p, "vCont;c");
+ p = append_resumption (p, endp, minus_one_ptid, step, siggnal);
}
- else if (ptid_equal (ptid, minus_one_ptid))
+ else if (ptid_equal (ptid, minus_one_ptid) || ptid_is_pid (ptid))
{
- /* Resume all threads, with preference for INFERIOR_PTID. */
- if (step && siggnal != TARGET_SIGNAL_0)
- {
- /* Step inferior_ptid with signal. */
- p += xsnprintf (p, endp - p, "vCont;S%02x:", siggnal);
- p = write_ptid (p, endp, inferior_ptid);
- /* And continue others. */
- p += xsnprintf (p, endp - p, ";c");
- }
- else if (step)
- {
- /* Step inferior_ptid. */
- p += xsnprintf (p, endp - p, "vCont;s:");
- p = write_ptid (p, endp, inferior_ptid);
- /* And continue others. */
- p += xsnprintf (p, endp - p, ";c");
- }
- else if (siggnal != TARGET_SIGNAL_0)
+ /* Resume all threads (of all processes, or of a single
+ process), with preference for INFERIOR_PTID. This assumes
+ inferior_ptid belongs to the set of all threads we are about
+ to resume. */
+ if (step || siggnal != TARGET_SIGNAL_0)
{
- /* Continue inferior_ptid with signal. */
- p += xsnprintf (p, endp - p, "vCont;C%02x:", siggnal);
- p = write_ptid (p, endp, inferior_ptid);
- /* And continue others. */
- p += xsnprintf (p, endp - p, ";c");
+ /* Step inferior_ptid, with or without signal. */
+ p = append_resumption (p, endp, inferior_ptid, step, siggnal);
}
- else
- xsnprintf (p, endp - p, "vCont;c");
+
+ /* And continue others without a signal. */
+ p = append_resumption (p, endp, ptid, /*step=*/ 0, TARGET_SIGNAL_0);
}
else
{
/* Scheduler locking; resume only PTID. */
- if (step && siggnal != TARGET_SIGNAL_0)
- {
- /* Step ptid with signal. */
- p += xsnprintf (p, endp - p, "vCont;S%02x:", siggnal);
- p = write_ptid (p, endp, ptid);
- }
- else if (step)
- {
- /* Step ptid. */
- p += xsnprintf (p, endp - p, "vCont;s:");
- p = write_ptid (p, endp, ptid);
- }
- else if (siggnal != TARGET_SIGNAL_0)
- {
- /* Continue ptid with signal. */
- p += xsnprintf (p, endp - p, "vCont;C%02x:", siggnal);
- p = write_ptid (p, endp, ptid);
- }
- else
- {
- /* Continue ptid. */
- p += xsnprintf (p, endp - p, "vCont;c:");
- p = write_ptid (p, endp, ptid);
- }
+ p = append_resumption (p, endp, ptid, step, siggnal);
}
gdb_assert (strlen (rs->buf) < get_remote_packet_size ());
if (!rs->support_vCont_t)
error (_("Remote server does not support stopping threads"));
- if (ptid_equal (ptid, minus_one_ptid))
+ if (ptid_equal (ptid, minus_one_ptid)
+ || (!remote_multi_process_p (rs) && ptid_is_pid (ptid)))
p += xsnprintf (p, endp - p, "vCont;t");
else
{
ptid_t nptid;
- /* Step inferior_ptid. */
p += xsnprintf (p, endp - p, "vCont;t:");
if (ptid_is_pid (ptid))
/* The non-stop mode version of target_wait. */
static ptid_t
-remote_wait_ns (ptid_t ptid, struct target_waitstatus *status)
+remote_wait_ns (ptid_t ptid, struct target_waitstatus *status, int options)
{
struct remote_state *rs = get_remote_state ();
struct remote_arch_state *rsa = get_remote_arch_state ();
if (stop_reply != NULL)
return process_stop_reply (stop_reply, status);
- /* Still no event. If we're in asynchronous mode, then just
+ /* Still no event. If we're just polling for an event, then
return to the event loop. */
- if (remote_is_async_p ())
+ if (options & TARGET_WNOHANG)
{
status->kind = TARGET_WAITKIND_IGNORE;
return minus_one_ptid;
}
- /* Otherwise, asynchronous mode is masked, so do a blocking
- wait. */
+ /* Otherwise do a blocking wait. */
ret = getpkt_or_notif_sane (&rs->buf, &rs->buf_size,
1 /* forever */);
}
STATUS just as `wait' would. */
static ptid_t
-remote_wait_as (ptid_t ptid, struct target_waitstatus *status)
+remote_wait_as (ptid_t ptid, struct target_waitstatus *status, int options)
{
struct remote_state *rs = get_remote_state ();
struct remote_arch_state *rsa = get_remote_arch_state ();
char *buf, *p;
struct stop_reply *stop_reply;
+ again:
+
status->kind = TARGET_WAITKIND_IGNORE;
status->value.integer = 0;
}
if (status->kind == TARGET_WAITKIND_IGNORE)
- /* Nothing interesting happened. */
- return minus_one_ptid;
+ {
+ /* Nothing interesting happened. If we're doing a non-blocking
+ poll, we're done. Otherwise, go back to waiting. */
+ if (options & TARGET_WNOHANG)
+ return minus_one_ptid;
+ else
+ goto again;
+ }
else if (status->kind != TARGET_WAITKIND_EXITED
&& status->kind != TARGET_WAITKIND_SIGNALLED)
{
static ptid_t
remote_wait (struct target_ops *ops,
- ptid_t ptid, struct target_waitstatus *status)
+ ptid_t ptid, struct target_waitstatus *status, int options)
{
ptid_t event_ptid;
if (non_stop)
- event_ptid = remote_wait_ns (ptid, status);
+ event_ptid = remote_wait_ns (ptid, status, options);
else
- {
- /* In synchronous mode, keep waiting until the target stops. In
- asynchronous mode, always return to the event loop. */
-
- do
- {
- event_ptid = remote_wait_as (ptid, status);
- }
- while (status->kind == TARGET_WAITKIND_IGNORE
- && !target_can_async_p ());
- }
+ event_ptid = remote_wait_as (ptid, status, options);
if (target_can_async_p ())
{
\f
static void
-remote_kill (void)
+remote_kill (struct target_ops *ops)
{
/* Use catch_errors so the user can quit from gdb even when we
aren't on speaking terms with the remote system. */
}
static void
-extended_remote_kill (void)
+extended_remote_kill (struct target_ops *ops)
{
int res;
int pid = ptid_get_pid (inferior_ptid);
{
unpush_target (target);
- /* remote_close takes care of cleaning up. */
-}
-
-static int
-select_new_thread_callback (struct thread_info *th, void* data)
-{
- if (!is_exited (th->ptid))
- {
- switch_to_thread (th->ptid);
- printf_filtered (_("[Switching to %s]\n"),
- target_pid_to_str (inferior_ptid));
- return 1;
- }
- return 0;
+ /* remote_close takes care of doing most of the clean up. */
+ generic_mourn_inferior ();
}
static void
/* Call common code to mark the inferior as not running. */
generic_mourn_inferior ();
- if (have_inferiors ())
- {
- extern void nullify_last_target_wait_ptid ();
- /* Multi-process case. The current process has exited, but
- there are other processes to debug. Switch to the first
- available. */
- iterate_over_threads (select_new_thread_callback, NULL);
- nullify_last_target_wait_ptid ();
- }
- else
+ if (!have_inferiors ())
{
if (!remote_multi_process_p (rs))
{
/* Now, if we have thread information, update inferior_ptid. */
inferior_ptid = remote_current_thread (inferior_ptid);
- remote_add_inferior (ptid_get_pid (inferior_ptid));
+ remote_add_inferior (ptid_get_pid (inferior_ptid), 0);
add_thread_silent (inferior_ptid);
/* Get updated offsets, if the stub uses qOffsets. */
add_packet_config_cmd (&remote_protocol_packets[PACKET_vKill],
"vKill", "kill", 0);
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_qAttached],
+ "qAttached", "query-attached", 0);
+
/* Keep the old ``set remote Z-packet ...'' working. Each individual
Z sub-packet has its own set and show commands, but users may
have sets to this variable in their .gdbinit files (or in their