static void remote_prepare_to_store (struct regcache *regcache);
-static void remote_fetch_registers (struct regcache *regcache, int regno);
-
-static void remote_resume (ptid_t ptid, int step,
- enum target_signal siggnal);
static void remote_open (char *name, int from_tty);
static void extended_remote_open (char *name, int from_tty);
static void remote_close (int quitting);
-static void remote_store_registers (struct regcache *regcache, int regno);
-
static void remote_mourn (struct target_ops *ops);
static void extended_remote_restart (void);
static int readchar (int timeout);
-static void remote_kill (void);
+static void remote_kill (struct target_ops *ops);
static int tohex (int nib);
static void set_general_thread (struct ptid ptid);
static void set_continue_thread (struct ptid ptid);
-static int remote_thread_alive (ptid_t);
-
static void get_offsets (void);
static void skip_frame (void);
PACKET_vRun,
PACKET_QStartNoAckMode,
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. 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, 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 (rs->extended)
+ target_mark_running (&extended_remote_ops);
+ else
+ target_mark_running (&remote_ops);
+ }
+
+ return inf;
+}
+
+/* Add thread PTID to GDB's thread list. Tag it as executing/running
+ according to RUNNING. */
+
static void
-notice_new_inferiors (ptid_t currthread)
+remote_add_thread (ptid_t ptid, int running)
{
+ add_thread (ptid);
+
+ set_executing (ptid, running);
+ set_running (ptid, running);
+}
+
+/* Come here when we learn about a thread id from the remote target.
+ It may be the first time we hear about such thread, so take the
+ opportunity to add it to GDB's thread list. In case this is the
+ first time we're noticing its corresponding inferior, add it to
+ GDB's inferior list as well. */
+
+static void
+remote_notice_new_inferior (ptid_t currthread, int running)
+{
+ struct remote_state *rs = get_remote_state ();
+
/* If this is a new thread, add it to GDB's thread list.
If we leave it up to WFI to do this, bad things will happen. */
{
/* We're seeing an event on a thread id we knew had exited.
This has to be a new thread reusing the old id. Add it. */
- add_thread (currthread);
+ remote_add_thread (currthread, running);
return;
}
if (!in_thread_list (currthread))
{
- if (ptid_equal (pid_to_ptid (ptid_get_pid (currthread)), inferior_ptid))
+ struct inferior *inf = NULL;
+ int pid = ptid_get_pid (currthread);
+
+ 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)))
- add_inferior (ptid_get_pid (currthread));
+ inf = remote_add_inferior (ptid_get_pid (currthread), -1);
/* This is really a new thread. Add it. */
- add_thread (currthread);
+ remote_add_thread (currthread, running);
+
+ /* If we found a new inferior, let the common code do whatever
+ it needs to with it (e.g., read shared libraries, insert
+ breakpoints). */
+ if (inf != NULL)
+ notice_new_inferior (currthread, running, 0);
}
}
/* We're just invalidating the local thread mirror. */
return;
- notice_new_inferiors (currthread);
+ remote_notice_new_inferior (currthread, 0);
}
static char *last_pass_packet;
system. */
static int
-remote_thread_alive (ptid_t ptid)
+remote_thread_alive (struct target_ops *ops, ptid_t ptid)
{
struct remote_state *rs = get_remote_state ();
int tid = ptid_get_tid (ptid);
*/
static void
-remote_threads_info (void)
+remote_threads_info (struct target_ops *ops)
{
struct remote_state *rs = get_remote_state ();
char *bufp;
do
{
new_thread = read_ptid (bufp, &bufp);
- if (!ptid_equal (new_thread, null_ptid)
- && (!in_thread_list (new_thread)
- || is_exited (new_thread)))
+ if (!ptid_equal (new_thread, null_ptid))
{
- /* When connected to a multi-process aware stub,
- "info threads" may show up threads of
- inferiors we didn't know about yet. Add them
- now, and before adding any of its child
- threads, so notifications are emitted in a
- sensible order. */
- if (!in_inferior_list (ptid_get_pid (new_thread)))
- add_inferior (ptid_get_pid (new_thread));
-
- add_thread (new_thread);
-
/* In non-stop mode, we assume new found threads
- are running until we proven otherwise with a
+ are running until proven otherwise with a
stop reply. In all-stop, we can only get
here if all threads are stopped. */
- set_executing (new_thread, non_stop ? 1 : 0);
- set_running (new_thread, non_stop ? 1 : 0);
+ int running = non_stop ? 1 : 0;
+
+ remote_notice_new_inferior (new_thread, running);
}
}
while (*bufp++ == ','); /* comma-separated list */
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. */
controlling. We default to adding them in the running state.
The '?' query below will then tell us about which threads are
stopped. */
- remote_threads_info ();
+ remote_threads_info (args->target);
}
else if (rs->non_stop_aware)
{
}
else
{
- if (args->extended_p)
- target_mark_running (args->target);
-
/* Save the reply for later. */
wait_status = alloca (strlen (rs->buf) + 1);
strcpy (wait_status, rs->buf);
/* Now, if we have thread information, update inferior_ptid. */
inferior_ptid = remote_current_thread (inferior_ptid);
- 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
PACKET_QStartNoAckMode },
{ "multiprocess", PACKET_DISABLE, remote_multi_process_feature, -1 },
{ "QNonStop", PACKET_DISABLE, remote_non_stop_feature, -1 },
+ { "qXfer:siginfo:read", PACKET_DISABLE, remote_supported_packet,
+ PACKET_qXfer_siginfo_read },
+ { "qXfer:siginfo:write", PACKET_DISABLE, remote_supported_packet,
+ PACKET_qXfer_siginfo_write },
};
static void
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)));
- target_mark_running (target);
+ 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 = 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 ();
+ 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)
+ /* 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)
{
- /* 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");
+ /* Step inferior_ptid, with or without signal. */
+ p = append_resumption (p, endp, inferior_ptid, step, siggnal);
}
- 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)
- {
- /* 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");
- }
- 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 ());
static int last_sent_step;
static void
-remote_resume (ptid_t ptid, int step, enum target_signal siggnal)
+remote_resume (struct target_ops *ops,
+ ptid_t ptid, int step, enum target_signal siggnal)
{
struct remote_state *rs = get_remote_state ();
char *buf;
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))
}
else
{
- if (query ("Interrupted while waiting for the program.\n\
-Give up (and stop debugging it)? "))
+ if (query (_("Interrupted while waiting for the program.\n\
+Give up (and stop debugging it)? ")))
{
pop_target ();
deprecated_throw_reason (RETURN_QUIT);
if (status->kind != TARGET_WAITKIND_EXITED
&& status->kind != TARGET_WAITKIND_SIGNALLED)
{
- notice_new_inferiors (ptid);
-
/* Expedited registers. */
if (stop_reply->regcache)
{
remote_stopped_by_watchpoint_p = stop_reply->stopped_by_watchpoint_p;
remote_watch_data_address = stop_reply->watch_data_address;
+
+ remote_notice_new_inferior (ptid, 0);
}
stop_reply_xfree (stop_reply);
}
static void
-remote_fetch_registers (struct regcache *regcache, int regnum)
+remote_fetch_registers (struct target_ops *ops,
+ struct regcache *regcache, int regnum)
{
struct remote_state *rs = get_remote_state ();
struct remote_arch_state *rsa = get_remote_arch_state ();
of the register cache buffer. FIXME: ignores errors. */
static void
-remote_store_registers (struct regcache *regcache, int regnum)
+remote_store_registers (struct target_ops *ops,
+ struct regcache *regcache, int regnum)
{
struct remote_state *rs = get_remote_state ();
struct remote_arch_state *rsa = get_remote_arch_state ();
FORMAT and the remaining arguments, then gets the reply. Returns
whether the packet was a success, a failure, or unknown. */
-enum packet_result
+static enum packet_result
remote_send_printf (const char *format, ...)
{
struct remote_state *rs = get_remote_state ();
\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);
- add_inferior (ptid_get_pid (inferior_ptid));
+ remote_add_inferior (ptid_get_pid (inferior_ptid), 0);
add_thread_silent (inferior_ptid);
- target_mark_running (&extended_remote_ops);
-
/* Get updated offsets, if the stub uses qOffsets. */
get_offsets ();
}
[PACKET_qXfer_spu_write]);
}
+ /* Handle extra signal info using qxfer packets. */
+ if (object == TARGET_OBJECT_SIGNAL_INFO)
+ {
+ if (readbuf)
+ return remote_read_qxfer (ops, "siginfo", annex, readbuf, offset, len,
+ &remote_protocol_packets
+ [PACKET_qXfer_siginfo_read]);
+ else
+ return remote_write_qxfer (ops, "siginfo", annex, writebuf, offset, len,
+ &remote_protocol_packets
+ [PACKET_qXfer_siginfo_write]);
+ }
+
/* Only handle flash writes. */
if (writebuf != NULL)
{
add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_osdata],
"qXfer:osdata:read", "osdata", 0);
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_siginfo_read],
+ "qXfer:siginfo:read", "read-siginfo-object", 0);
+
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_siginfo_write],
+ "qXfer:siginfo:write", "write-siginfo-object", 0);
+
add_packet_config_cmd (&remote_protocol_packets[PACKET_qGetTLSAddr],
"qGetTLSAddr", "get-thread-local-storage-address",
0);
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