#include "remote-fileio.h"
#include "gdb/fileio.h"
+#include "gdb_stat.h"
#include "memory-map.h"
static void init_extended_remote_ops (void);
-static void remote_stop (void);
+static void remote_stop (ptid_t);
static int ishex (int ch, int *val);
struct cmd_list_element *c,
const char *value);
-void _initialize_remote (void);
-
-/* Controls if async mode is permitted. */
-static int remote_async_permitted = 0;
+static char *write_ptid (char *buf, const char *endbuf, ptid_t ptid);
+static ptid_t read_ptid (char *buf, char **obuf);
-static int remote_async_permitted_set = 0;
+static void remote_query_supported (void);
-static void
-set_maintenance_remote_async_permitted (char *args, int from_tty,
- struct cmd_list_element *c)
-{
- if (target_has_execution)
- {
- remote_async_permitted_set = remote_async_permitted; /* revert */
- error (_("Cannot change this setting while the inferior is running."));
- }
+static void remote_check_symbols (struct objfile *objfile);
- remote_async_permitted = remote_async_permitted_set;
-}
-
-static void
-show_maintenance_remote_async_permitted (struct ui_file *file, int from_tty,
- struct cmd_list_element *c, const char *value)
-{
- fprintf_filtered (file, _("\
-Controlling the remote inferior in asynchronous mode is %s.\n"),
- value);
-}
+void _initialize_remote (void);
/* For "remote". */
skip calling getpkt. This flag is set when BUF contains a
stop reply packet and the target is not waiting. */
int cached_wait_status;
+
+ /* True, if in no ack mode. That is, neither GDB nor the stub will
+ expect acks from each other. The connection is assumed to be
+ reliable. */
+ int noack_mode;
+
+ /* True if we're connected in extended remote mode. */
+ int extended;
+
+ /* True if the stub reported support for multi-process
+ extensions. */
+ int multi_process_aware;
+
+ /* True if we resumed the target and we're waiting for the target to
+ stop. In the mean time, we can't start another command/query.
+ The remote server wouldn't be ready to process it, so we'd
+ timeout waiting for a reply that would never come and eventually
+ we'd close the connection. This can happen in asynchronous mode
+ because we allow GDB commands while the target is running. */
+ int waiting_for_stop_reply;
};
+/* Returns true if the multi-process extensions are in effect. */
+static int
+remote_multi_process_p (struct remote_state *rs)
+{
+ return rs->extended && rs->multi_process_aware;
+}
+
/* This data could be associated with a target, but we do not always
have access to the current target when we need it, so for now it is
static. This will be fine for as long as only one target is in use
long regnum; /* GDB's internal register number. */
LONGEST pnum; /* Remote protocol register number. */
int in_g_packet; /* Always part of G packet. */
- /* long size in bytes; == register_size (current_gdbarch, regnum);
+ /* long size in bytes; == register_size (target_gdbarch, regnum);
at present. */
- /* char *name; == gdbarch_register_name (current_gdbarch, regnum);
+ /* char *name; == gdbarch_register_name (target_gdbarch, regnum);
at present. */
};
static struct remote_arch_state *
get_remote_arch_state (void)
{
- return gdbarch_data (current_gdbarch, remote_gdbarch_data_handle);
+ return gdbarch_data (target_gdbarch, remote_gdbarch_data_handle);
}
/* Fetch the global remote target state. */
static struct packet_reg *
packet_reg_from_regnum (struct remote_arch_state *rsa, long regnum)
{
- if (regnum < 0 && regnum >= gdbarch_num_regs (current_gdbarch))
+ if (regnum < 0 && regnum >= gdbarch_num_regs (target_gdbarch))
return NULL;
else
{
packet_reg_from_pnum (struct remote_arch_state *rsa, LONGEST pnum)
{
int i;
- for (i = 0; i < gdbarch_num_regs (current_gdbarch); i++)
+ for (i = 0; i < gdbarch_num_regs (target_gdbarch); i++)
{
struct packet_reg *r = &rsa->regs[i];
if (r->pnum == pnum)
PACKET_qSearch_memory,
PACKET_vAttach,
PACKET_vRun,
+ PACKET_QStartNoAckMode,
+ PACKET_vKill,
PACKET_MAX
};
{
general_thread = currthread;
+ /* When connecting to a target remote, or to a target
+ extended-remote which already was debugging an inferior, we 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));
+
/* 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. */
+
+ if (in_thread_list (currthread) && is_exited (currthread))
+ {
+ /* 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);
+ return;
+ }
+
if (!in_thread_list (currthread))
{
if (ptid_equal (pid_to_ptid (ptid_get_pid (currthread)), inferior_ptid))
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. */
- struct thread_info *th = find_thread_pid (inferior_ptid);
- inferior_ptid = th->ptid = currthread;
+ thread_change_ptid (inferior_ptid, currthread);
+ return;
}
- else if (ptid_equal (magic_null_ptid, inferior_ptid))
+
+ if (ptid_equal (magic_null_ptid, inferior_ptid))
{
/* inferior_ptid is not set yet. This can happen with the
vRun -> 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. */
- struct thread_info *th = find_thread_pid (inferior_ptid);
- inferior_ptid = th->ptid = currthread;
+ thread_change_ptid (inferior_ptid, currthread);
+ return;
}
- else
- /* This is really a new thread. Add it. */
- add_thread (currthread);
+
+ /* This is really a new thread. Add it. */
+ add_thread (currthread);
}
}
else if (ptid_equal (ptid, minus_one_ptid))
xsnprintf (buf, endbuf - buf, "-1");
else
- {
- int tid = ptid_get_tid (ptid);
- if (tid < 0)
- xsnprintf (buf, endbuf - buf, "-%x", -tid);
- else
- xsnprintf (buf, endbuf - buf, "%x", tid);
- }
+ write_ptid (buf, endbuf, ptid);
putpkt (rs->buf);
getpkt (&rs->buf, &rs->buf_size, 0);
if (gen)
set_thread (ptid, 0);
}
+/* Change the remote current process. Which thread within the process
+ ends up selected isn't important, as long as it is the same process
+ as what INFERIOR_PTID points to.
+
+ This comes from that fact that there is no explicit notion of
+ "selected process" in the protocol. The selected process for
+ general operations is the process the selected general thread
+ belongs to. */
+
+static void
+set_general_process (void)
+{
+ struct remote_state *rs = get_remote_state ();
+
+ /* If the remote can't handle multiple processes, don't bother. */
+ if (!remote_multi_process_p (rs))
+ return;
+
+ /* We only need to change the remote current thread if it's pointing
+ at some other process. */
+ if (ptid_get_pid (general_thread) != ptid_get_pid (inferior_ptid))
+ set_general_thread (inferior_ptid);
+}
+
\f
/* Return nonzero if the thread PTID is still alive on the remote
system. */
{
struct remote_state *rs = get_remote_state ();
int tid = ptid_get_tid (ptid);
+ char *p, *endp;
if (ptid_equal (ptid, magic_null_ptid))
/* The main thread is always alive. */
multi-threading. */
return 1;
- if (tid < 0)
- xsnprintf (rs->buf, get_remote_packet_size (), "T-%08x", -tid);
- else
- xsnprintf (rs->buf, get_remote_packet_size (), "T%08x", tid);
+ p = rs->buf;
+ endp = rs->buf + get_remote_packet_size ();
+
+ *p++ = 'T';
+ write_ptid (p, endp, ptid);
+
putpkt (rs->buf);
getpkt (&rs->buf, &rs->buf_size, 0);
return (rs->buf[0] == 'O' && rs->buf[1] == 'K');
static int remote_newthread_step (threadref *ref, void *context);
+
+/* Write a PTID to BUF. ENDBUF points to one-passed-the-end of the
+ buffer we're allowed to write to. Returns
+ BUF+CHARACTERS_WRITTEN. */
+
+static char *
+write_ptid (char *buf, const char *endbuf, ptid_t ptid)
+{
+ int pid, tid;
+ struct remote_state *rs = get_remote_state ();
+
+ if (remote_multi_process_p (rs))
+ {
+ pid = ptid_get_pid (ptid);
+ if (pid < 0)
+ buf += xsnprintf (buf, endbuf - buf, "p-%x.", -pid);
+ else
+ buf += xsnprintf (buf, endbuf - buf, "p%x.", pid);
+ }
+ tid = ptid_get_tid (ptid);
+ if (tid < 0)
+ buf += xsnprintf (buf, endbuf - buf, "-%x", -tid);
+ else
+ buf += xsnprintf (buf, endbuf - buf, "%x", tid);
+
+ return buf;
+}
+
+/* Extract a PTID from BUF. If non-null, OBUF is set to the to one
+ passed the last parsed char. Returns null_ptid on error. */
+
+static ptid_t
+read_ptid (char *buf, char **obuf)
+{
+ char *p = buf;
+ char *pp;
+ ULONGEST pid = 0, tid = 0;
+ ptid_t ptid;
+
+ if (*p == 'p')
+ {
+ /* Multi-process ptid. */
+ pp = unpack_varlen_hex (p + 1, &pid);
+ if (*pp != '.')
+ error (_("invalid remote ptid: %s\n"), p);
+
+ p = pp;
+ pp = unpack_varlen_hex (p + 1, &tid);
+ if (obuf)
+ *obuf = pp;
+ return ptid_build (pid, 0, tid);
+ }
+
+ /* No multi-process. Just a tid. */
+ pp = unpack_varlen_hex (p, &tid);
+
+ /* Since the stub is not sending a process id, then default to
+ what's in inferior_ptid. */
+ pid = ptid_get_pid (inferior_ptid);
+
+ if (obuf)
+ *obuf = pp;
+ return ptid_build (pid, 0, tid);
+}
+
/* Encode 64 bits in 16 chars of hex. */
static const char hexchars[] = "0123456789abcdef";
pack_threadinfo_request (rs->buf, fieldset, threadid);
putpkt (rs->buf);
getpkt (&rs->buf, &rs->buf_size, 0);
+
+ if (rs->buf[0] == '\0')
+ return 0;
+
result = remote_unpack_thread_info_response (rs->buf + 2,
threadid, info);
return result;
putpkt ("qC");
getpkt (&rs->buf, &rs->buf_size, 0);
if (rs->buf[0] == 'Q' && rs->buf[1] == 'C')
- {
- /* Use strtoul here, so we'll correctly parse values whose
- highest bit is set. The protocol carries them as a simple
- series of hex digits; in the absence of a sign, strtol will
- see such values as positive numbers out of range for signed
- 'long', and return LONG_MAX to indicate an overflow. */
- tid = strtoul (&rs->buf[2], NULL, 16);
- pid = ptid_get_pid (oldpid);
- return ptid_build (pid, 0, tid);
- }
+ return read_ptid (&rs->buf[2], NULL);
else
return oldpid;
}
{
struct remote_state *rs = get_remote_state ();
char *bufp;
- int tid;
- int pid;
ptid_t new_thread;
if (remote_desc == 0) /* paranoia */
{
do
{
- /* Use strtoul here, so we'll correctly parse values
- whose highest bit is set. The protocol carries
- them as a simple series of hex digits; in the
- absence of a sign, strtol will see such values as
- positive numbers out of range for signed 'long',
- and return LONG_MAX to indicate an overflow. */
- tid = strtoul (bufp, &bufp, 16);
- pid = ptid_get_pid (inferior_ptid);
- new_thread = ptid_build (pid, 0, tid);
- if (tid != 0 && !in_thread_list (new_thread))
- add_thread (new_thread);
+ new_thread = read_ptid (bufp, &bufp);
+ if (!ptid_equal (new_thread, null_ptid)
+ && (!in_thread_list (new_thread)
+ || is_exited (new_thread)))
+ {
+ /* 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);
+ }
}
while (*bufp++ == ','); /* comma-separated list */
putpkt ("qsThreadInfo");
internal_error (__FILE__, __LINE__,
_("remote_threads_extra_info"));
+ if (ptid_equal (tp->ptid, magic_null_ptid)
+ || (ptid_get_pid (tp->ptid) != 0 && ptid_get_tid (tp->ptid) == 0))
+ /* This is the main thread which was added by GDB. The remote
+ server doesn't know about it. */
+ return NULL;
+
if (use_threadextra_query)
{
- xsnprintf (rs->buf, get_remote_packet_size (), "qThreadExtraInfo,%lx",
- ptid_get_tid (tp->ptid));
+ char *b = rs->buf;
+ char *endb = rs->buf + get_remote_packet_size ();
+
+ xsnprintf (b, endb - b, "qThreadExtraInfo,");
+ b += strlen (b);
+ write_ptid (b, endb, tp->ptid);
+
putpkt (rs->buf);
getpkt (&rs->buf, &rs->buf_size, 0);
if (rs->buf[0] != 0)
remote_close (int quitting)
{
if (remote_desc)
- serial_close (remote_desc);
- remote_desc = NULL;
+ {
+ /* Unregister the file descriptor from the event loop. */
+ if (target_is_async_p ())
+ target_async (NULL, 0);
+ serial_close (remote_desc);
+ remote_desc = NULL;
+ }
+
+ /* Make sure we don't leave the async SIGINT signal handler
+ installed. */
+ signal (SIGINT, handle_sigint);
+
+ /* We don't have a connection to the remote stub anymore. Get rid
+ of all the inferiors and their threads we were controlling. */
+ discard_all_inferiors ();
+
+ generic_mourn_inferior ();
}
/* Query the remote side for the text, data and bss offsets. */
static void
remote_start_remote (struct ui_out *uiout, void *opaque)
{
- struct remote_state *rs = get_remote_state ();
struct start_remote_args *args = opaque;
+ struct remote_state *rs = get_remote_state ();
+ struct packet_config *noack_config;
char *wait_status = NULL;
immediate_quit++; /* Allow user to interrupt it. */
/* Ack any packet which the remote side has already sent. */
serial_write (remote_desc, "+", 1);
+ /* The first packet we send to the target is the optional "supported
+ packets" request. If the target can answer this, it will tell us
+ which later probes to skip. */
+ remote_query_supported ();
+
+ /* Next, we possibly activate noack mode.
+
+ If the QStartNoAckMode packet configuration is set to AUTO,
+ enable noack mode if the stub reported a wish for it with
+ qSupported.
+
+ If set to TRUE, then enable noack mode even if the stub didn't
+ report it in qSupported. If the stub doesn't reply OK, the
+ session ends with an error.
+
+ If FALSE, then don't activate noack mode, regardless of what the
+ stub claimed should be the default with qSupported. */
+
+ noack_config = &remote_protocol_packets[PACKET_QStartNoAckMode];
+
+ if (noack_config->detect == AUTO_BOOLEAN_TRUE
+ || (noack_config->detect == AUTO_BOOLEAN_AUTO
+ && noack_config->support == PACKET_ENABLE))
+ {
+ putpkt ("QStartNoAckMode");
+ getpkt (&rs->buf, &rs->buf_size, 0);
+ if (packet_ok (rs->buf, noack_config) == PACKET_OK)
+ rs->noack_mode = 1;
+ }
+
+ if (args->extended_p)
+ {
+ /* Tell the remote that we are using the extended protocol. */
+ putpkt ("!");
+ getpkt (&rs->buf, &rs->buf_size, 0);
+ }
+
+ /* Next, if the target can specify a description, read it. We do
+ this before anything involving memory or registers. */
+ target_find_description ();
+
/* Check whether the target is running now. */
putpkt ("?");
getpkt (&rs->buf, &rs->buf_size, 0);
/* Now, if we have thread information, update inferior_ptid. */
inferior_ptid = remote_current_thread (inferior_ptid);
+ add_inferior (ptid_get_pid (inferior_ptid));
+
/* Always add the main thread. */
add_thread_silent (inferior_ptid);
immediate_quit--;
start_remote (args->from_tty); /* Initialize gdb process mechanisms. */
+
+ /* If we connected to a live target, do some additional setup. */
+ if (target_has_execution)
+ {
+ if (exec_bfd) /* No use without an exec file. */
+ remote_check_symbols (symfile_objfile);
+ }
}
/* Open a connection to a remote debugger.
if (remote_protocol_packets[PACKET_qSymbol].support == PACKET_DISABLE)
return;
+ /* Make sure the remote is pointing at the right process. */
+ set_general_process ();
+
/* Allocate a message buffer. We can't reuse the input buffer in RS,
because we need both at the same time. */
msg = alloca (get_remote_packet_size ());
/* If this is a function address, return the start of code
instead of any data function descriptor. */
- sym_addr = gdbarch_convert_from_func_ptr_addr (current_gdbarch,
+ sym_addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch,
sym_addr,
¤t_target);
rs->explicit_packet_size = packet_size;
}
+static void
+remote_multi_process_feature (const struct protocol_feature *feature,
+ enum packet_support support, const char *value)
+{
+ struct remote_state *rs = get_remote_state ();
+ rs->multi_process_aware = (support == PACKET_ENABLE);
+}
+
static struct protocol_feature remote_protocol_features[] = {
{ "PacketSize", PACKET_DISABLE, remote_packet_size, -1 },
{ "qXfer:auxv:read", PACKET_DISABLE, remote_supported_packet,
PACKET_qXfer_spu_write },
{ "QPassSignals", PACKET_DISABLE, remote_supported_packet,
PACKET_QPassSignals },
+ { "QStartNoAckMode", PACKET_DISABLE, remote_supported_packet,
+ PACKET_QStartNoAckMode },
+ { "multiprocess", PACKET_DISABLE, remote_multi_process_feature, -1 },
};
static void
rs->buf[0] = 0;
if (remote_protocol_packets[PACKET_qSupported].support != PACKET_DISABLE)
{
- putpkt ("qSupported");
+ if (rs->extended)
+ putpkt ("qSupported:multiprocess+");
+ else
+ putpkt ("qSupported");
+
getpkt (&rs->buf, &rs->buf_size, 0);
/* If an error occured, warn, but do not return - just reset the
remote_open_1 (char *name, int from_tty, struct target_ops *target, int extended_p)
{
struct remote_state *rs = get_remote_state ();
+
if (name == 0)
error (_("To open a remote debug connection, you need to specify what\n"
"serial device is attached to the remote system\n"
"(e.g. /dev/ttyS0, /dev/ttya, COM1, etc.)."));
/* See FIXME above. */
- if (!remote_async_permitted)
+ if (!target_async_permitted)
wait_forever_enabled_p = 1;
/* If we're connected to a running target, target_preopen will kill it.
remote_query_supported or as they are needed. */
init_all_packet_configs ();
rs->explicit_packet_size = 0;
+ rs->noack_mode = 0;
+ rs->multi_process_aware = 0;
+ rs->extended = extended_p;
+ rs->waiting_for_stop_reply = 0;
general_thread = not_sent_ptid;
continue_thread = not_sent_ptid;
use_threadinfo_query = 1;
use_threadextra_query = 1;
- /* The first packet we send to the target is the optional "supported
- packets" request. If the target can answer this, it will tell us
- which later probes to skip. */
- remote_query_supported ();
-
- /* Next, if the target can specify a description, read it. We do
- this before anything involving memory or registers. */
- target_find_description ();
-
- if (remote_async_permitted)
+ if (target_async_permitted)
{
/* With this target we start out by owning the terminal. */
remote_async_terminal_ours_p = 1;
ex = catch_exception (uiout, remote_start_remote, &args, RETURN_MASK_ALL);
if (ex.reason < 0)
{
- pop_target ();
- if (remote_async_permitted)
+ /* Pop the partially set up target - unless something else did
+ already before throwing the exception. */
+ if (remote_desc != NULL)
+ pop_target ();
+ if (target_async_permitted)
wait_forever_enabled_p = 1;
throw_exception (ex);
}
}
- if (remote_async_permitted)
+ if (target_async_permitted)
wait_forever_enabled_p = 1;
-
- if (extended_p)
- {
- /* Tell the remote that we are using the extended protocol. */
- putpkt ("!");
- getpkt (&rs->buf, &rs->buf_size, 0);
- }
-
- /* If we connected to a live target, do some additional setup. */
- if (target_has_execution)
- {
- if (exec_bfd) /* No use without an exec file. */
- remote_check_symbols (symfile_objfile);
- }
}
/* This takes a program previously attached to and detaches it. After
static void
remote_detach_1 (char *args, int from_tty, int extended)
{
+ int pid = ptid_get_pid (inferior_ptid);
struct remote_state *rs = get_remote_state ();
if (args)
error (_("No process to detach from."));
/* Tell the remote target to detach. */
- strcpy (rs->buf, "D");
+ if (remote_multi_process_p (rs))
+ sprintf (rs->buf, "D;%x", pid);
+ else
+ strcpy (rs->buf, "D");
+
putpkt (rs->buf);
getpkt (&rs->buf, &rs->buf_size, 0);
- if (rs->buf[0] == 'E')
+ if (rs->buf[0] == 'O' && rs->buf[1] == 'K')
+ ;
+ else if (rs->buf[0] == '\0')
+ error (_("Remote doesn't know how to detach"));
+ else
error (_("Can't detach process."));
- /* Unregister the file descriptor from the event loop. */
- if (target_is_async_p ())
- serial_async (remote_desc, NULL, 0);
-
- target_mourn_inferior ();
if (from_tty)
{
- if (extended)
- puts_filtered ("Detached from remote process.\n");
+ if (remote_multi_process_p (rs))
+ printf_filtered (_("Detached from remote %s.\n"),
+ target_pid_to_str (pid_to_ptid (pid)));
else
- puts_filtered ("Ending remote debugging.\n");
+ {
+ if (extended)
+ puts_filtered (_("Detached from remote process.\n"));
+ else
+ puts_filtered (_("Ending remote debugging.\n"));
+ }
}
+
+ detach_inferior (pid);
+ target_mourn_inferior ();
}
static void
if (args)
error (_("Argument given to \"disconnect\" when remotely debugging."));
- /* Unregister the file descriptor from the event loop. */
- if (target_is_async_p ())
- serial_async (remote_desc, NULL, 0);
-
/* Make sure we unpush even the extended remote targets; mourn
won't do it. So call remote_mourn_1 directly instead of
target_mourn_inferior. */
int pid;
char *dummy;
char *wait_status = NULL;
+ struct inferior *inf;
if (!args)
error_no_arg (_("process-id to attach"));
/* Now, if we have thread information, update inferior_ptid. */
inferior_ptid = remote_current_thread (inferior_ptid);
+ inf = add_inferior (pid);
+ inf->attach_flag = 1;
+
/* Now, add the main thread to the thread list. */
add_thread_silent (inferior_ptid);
- attach_flag = 1;
-
/* Next, if the target can specify a description, read it. We do
this before anything involving memory or registers. */
target_find_description ();
remote_vcont_resume (ptid_t ptid, int step, enum target_signal siggnal)
{
struct remote_state *rs = get_remote_state ();
- char *outbuf;
- struct cleanup *old_cleanup;
+ char *p;
+ char *endp;
if (remote_protocol_packets[PACKET_vCont].support == PACKET_SUPPORT_UNKNOWN)
remote_vcont_probe (rs);
if (remote_protocol_packets[PACKET_vCont].support == PACKET_DISABLE)
return 0;
+ p = rs->buf;
+ endp = rs->buf + get_remote_packet_size ();
+
/* If we could generate a wider range of packets, we'd have to worry
about overflowing BUF. Should there be a generic
"multi-part-packet" packet? */
understand. Make sure to only send forms that do not specify
a TID. */
if (step && siggnal != TARGET_SIGNAL_0)
- outbuf = xstrprintf ("vCont;S%02x", siggnal);
+ xsnprintf (p, endp - p, "vCont;S%02x", siggnal);
else if (step)
- outbuf = xstrprintf ("vCont;s");
+ xsnprintf (p, endp - p, "vCont;s");
else if (siggnal != TARGET_SIGNAL_0)
- outbuf = xstrprintf ("vCont;C%02x", siggnal);
+ xsnprintf (p, endp - p, "vCont;C%02x", siggnal);
else
- outbuf = xstrprintf ("vCont;c");
+ xsnprintf (p, endp - p, "vCont;c");
}
else if (ptid_equal (ptid, minus_one_ptid))
{
/* Resume all threads, with preference for INFERIOR_PTID. */
- int tid = ptid_get_tid (inferior_ptid);
if (step && siggnal != TARGET_SIGNAL_0)
- outbuf = xstrprintf ("vCont;S%02x:%x;c", siggnal, tid);
+ {
+ /* 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)
- outbuf = xstrprintf ("vCont;s:%x;c", tid);
+ {
+ /* 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)
- outbuf = xstrprintf ("vCont;C%02x:%x;c", siggnal, tid);
+ {
+ /* 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
- outbuf = xstrprintf ("vCont;c");
+ xsnprintf (p, endp - p, "vCont;c");
}
else
{
/* Scheduler locking; resume only PTID. */
- int tid = ptid_get_tid (ptid);
if (step && siggnal != TARGET_SIGNAL_0)
- outbuf = xstrprintf ("vCont;S%02x:%x", siggnal, tid);
+ {
+ /* Step ptid with signal. */
+ p += xsnprintf (p, endp - p, "vCont;S%02x:", siggnal);
+ p = write_ptid (p, endp, ptid);
+ }
else if (step)
- outbuf = xstrprintf ("vCont;s:%x", tid);
+ {
+ /* Step ptid. */
+ p += xsnprintf (p, endp - p, "vCont;s:");
+ p = write_ptid (p, endp, ptid);
+ }
else if (siggnal != TARGET_SIGNAL_0)
- outbuf = xstrprintf ("vCont;C%02x:%x", siggnal, tid);
+ {
+ /* Continue ptid with signal. */
+ p += xsnprintf (p, endp - p, "vCont;C%02x:", siggnal);
+ p = write_ptid (p, endp, ptid);
+ }
else
- outbuf = xstrprintf ("vCont;c:%x", tid);
+ {
+ /* Continue ptid. */
+ p += xsnprintf (p, endp - p, "vCont;c:");
+ p = write_ptid (p, endp, ptid);
+ }
}
- gdb_assert (outbuf && strlen (outbuf) < get_remote_packet_size ());
- old_cleanup = make_cleanup (xfree, outbuf);
-
- putpkt (outbuf);
-
- do_cleanups (old_cleanup);
+ gdb_assert (strlen (rs->buf) < get_remote_packet_size ());
+ putpkt (rs->buf);
return 1;
}
set_continue_thread (ptid);
buf = rs->buf;
- if (siggnal != TARGET_SIGNAL_0)
+ if (execution_direction == EXEC_REVERSE)
+ {
+ /* We don't pass signals to the target in reverse exec mode. */
+ if (info_verbose && siggnal != TARGET_SIGNAL_0)
+ warning (" - Can't pass signal %d to target in reverse: ignored.\n",
+ siggnal);
+ strcpy (buf, step ? "bs" : "bc");
+ }
+ else if (siggnal != TARGET_SIGNAL_0)
{
buf[0] = step ? 'S' : 'C';
buf[1] = tohex (((int) siggnal >> 4) & 0xf);
NOT asynchronously. */
if (target_can_async_p ())
target_async (inferior_event_handler, 0);
- /* Tell the world that the target is now executing. */
- /* FIXME: cagney/1999-09-23: Is it the targets responsibility to set
- this? Instead, should the client of target just assume (for
- async targets) that the target is going to start executing? Is
- this information already found in the continuation block? */
- if (target_is_async_p ())
- target_executing = 1;
+
+ /* We've just told the target to resume. The remote server will
+ wait for the inferior to stop, and then send a stop reply. In
+ the mean time, we can't start another command/query ourselves
+ because the stub wouldn't be ready to process it. */
+ rs->waiting_for_stop_reply = 1;
}
\f
if (remote_debug)
fprintf_unfiltered (gdb_stdlog, "remote_interrupt called\n");
- target_stop ();
+ target_stop (inferior_ptid);
}
/* Perform interrupt, if the first attempt did not succeed. Just give
interrupt is requested, either by the command line or the GUI, we
will eventually end up here. */
static void
-remote_stop (void)
+remote_stop (ptid_t ptid)
{
/* Send a break or a ^C, depending on user preference. */
if (remote_debug)
if (query ("Interrupted while waiting for the program.\n\
Give up (and stop debugging it)? "))
{
- target_mourn_inferior ();
- signal (SIGINT, handle_sigint);
+ pop_target ();
deprecated_throw_reason (RETURN_QUIT);
}
static void
remote_terminal_inferior (void)
{
- if (!remote_async_permitted)
+ if (!target_async_permitted)
/* Nothing to do. */
return;
static void
remote_terminal_ours (void)
{
- if (!remote_async_permitted)
+ if (!target_async_permitted)
/* Nothing to do. */
return;
storing status in STATUS just as `wait' would. */
static ptid_t
-remote_wait (ptid_t ptid, struct target_waitstatus *status)
+remote_wait_as (ptid_t ptid, struct target_waitstatus *status)
{
struct remote_state *rs = get_remote_state ();
struct remote_arch_state *rsa = get_remote_arch_state ();
- ULONGEST thread_num = -1;
- ULONGEST process_num = -1;
+ ptid_t event_ptid = null_ptid;
ULONGEST addr;
int solibs_changed = 0;
+ int replay_event = 0;
+ char *buf, *p;
- status->kind = TARGET_WAITKIND_EXITED;
+ status->kind = TARGET_WAITKIND_IGNORE;
status->value.integer = 0;
- while (1)
+ if (rs->cached_wait_status)
+ /* Use the cached wait status, but only once. */
+ rs->cached_wait_status = 0;
+ else
{
- char *buf, *p;
-
- if (rs->cached_wait_status)
- /* Use the cached wait status, but only once. */
- rs->cached_wait_status = 0;
- else
+ if (!target_is_async_p ())
{
- if (!target_is_async_p ())
+ ofunc = signal (SIGINT, remote_interrupt);
+ /* If the user hit C-c before this packet, or between
+ packets, pretend that it was hit right here. */
+ if (quit_flag)
{
- ofunc = signal (SIGINT, remote_interrupt);
- /* If the user hit C-c before this packet, or between packets,
- pretend that it was hit right here. */
- if (quit_flag)
- {
- quit_flag = 0;
- remote_interrupt (SIGINT);
- }
+ quit_flag = 0;
+ remote_interrupt (SIGINT);
}
- /* FIXME: cagney/1999-09-27: If we're in async mode we should
- _never_ wait for ever -> test on target_is_async_p().
- However, before we do that we need to ensure that the caller
- knows how to take the target into/out of async mode. */
- getpkt (&rs->buf, &rs->buf_size, wait_forever_enabled_p);
- if (!target_is_async_p ())
- signal (SIGINT, ofunc);
}
+ /* FIXME: cagney/1999-09-27: If we're in async mode we should
+ _never_ wait for ever -> test on target_is_async_p().
+ However, before we do that we need to ensure that the caller
+ knows how to take the target into/out of async mode. */
+ getpkt (&rs->buf, &rs->buf_size, wait_forever_enabled_p);
+ if (!target_is_async_p ())
+ signal (SIGINT, ofunc);
+ }
- buf = rs->buf;
+ buf = rs->buf;
- remote_stopped_by_watchpoint_p = 0;
+ remote_stopped_by_watchpoint_p = 0;
- switch (buf[0])
- {
- case 'E': /* Error of some sort. */
- /* We're out of sync with the target now. Did it continue or not?
- Not is more likely, so report a stop. */
- warning (_("Remote failure reply: %s"), buf);
- status->kind = TARGET_WAITKIND_STOPPED;
- status->value.sig = TARGET_SIGNAL_0;
- goto got_status;
- case 'F': /* File-I/O request. */
- remote_fileio_request (buf);
- continue;
- case 'T': /* Status with PC, SP, FP, ... */
- {
- gdb_byte regs[MAX_REGISTER_SIZE];
+ /* We got something. */
+ rs->waiting_for_stop_reply = 0;
- /* Expedited reply, containing Signal, {regno, reg} repeat. */
- /* format is: 'Tssn...:r...;n...:r...;n...:r...;#cc', where
- ss = signal number
- n... = register number
- r... = register contents
- */
- p = &buf[3]; /* after Txx */
+ switch (buf[0])
+ {
+ case 'E': /* Error of some sort. */
+ /* We're out of sync with the target now. Did it continue or
+ not? Not is more likely, so report a stop. */
+ warning (_("Remote failure reply: %s"), buf);
+ status->kind = TARGET_WAITKIND_STOPPED;
+ status->value.sig = TARGET_SIGNAL_0;
+ break;
+ case 'F': /* File-I/O request. */
+ remote_fileio_request (buf);
- while (*p)
- {
- char *p1;
- char *p_temp;
- int fieldsize;
- LONGEST pnum = 0;
+ /* This stop reply is special. We reply back to the stub,
+ and keep waiting for the target to stop. */
+ rs->waiting_for_stop_reply = 1;
+ break;
+ case 'T': /* Status with PC, SP, FP, ... */
+ {
+ gdb_byte regs[MAX_REGISTER_SIZE];
- /* If the packet contains a register number, save it
- in pnum and set p1 to point to the character
- following it. Otherwise p1 points to p. */
+ /* Expedited reply, containing Signal, {regno, reg} repeat. */
+ /* format is: 'Tssn...:r...;n...:r...;n...:r...;#cc', where
+ ss = signal number
+ n... = register number
+ r... = register contents
+ */
+ p = &buf[3]; /* after Txx */
+
+ while (*p)
+ {
+ char *p1;
+ char *p_temp;
+ int fieldsize;
+ LONGEST pnum = 0;
- /* If this packet is an awatch packet, don't parse the
- 'a' as a register number. */
+ /* If the packet contains a register number, save it in
+ pnum and set p1 to point to the character following it.
+ Otherwise p1 points to p. */
- if (strncmp (p, "awatch", strlen("awatch")) != 0)
+ /* If this packet is an awatch packet, don't parse the
+ 'a' as a register number. */
+
+ if (strncmp (p, "awatch", strlen("awatch")) != 0)
+ {
+ /* Read the ``P'' register number. */
+ pnum = strtol (p, &p_temp, 16);
+ p1 = p_temp;
+ }
+ else
+ p1 = p;
+
+ if (p1 == p) /* No register number present here. */
+ {
+ p1 = strchr (p, ':');
+ if (p1 == NULL)
+ error (_("Malformed packet(a) (missing colon): %s\n\
+Packet: '%s'\n"),
+ p, buf);
+ if (strncmp (p, "thread", p1 - p) == 0)
+ event_ptid = read_ptid (++p1, &p);
+ else if ((strncmp (p, "watch", p1 - p) == 0)
+ || (strncmp (p, "rwatch", p1 - p) == 0)
+ || (strncmp (p, "awatch", p1 - p) == 0))
{
- /* Read the ``P'' register number. */
- pnum = strtol (p, &p_temp, 16);
- p1 = p_temp;
+ remote_stopped_by_watchpoint_p = 1;
+ p = unpack_varlen_hex (++p1, &addr);
+ remote_watch_data_address = (CORE_ADDR)addr;
}
- else
- p1 = p;
+ else if (strncmp (p, "library", p1 - p) == 0)
+ {
+ p1++;
+ p_temp = p1;
+ while (*p_temp && *p_temp != ';')
+ p_temp++;
- if (p1 == p) /* No register number present here. */
+ solibs_changed = 1;
+ p = p_temp;
+ }
+ else if (strncmp (p, "replaylog", p1 - p) == 0)
{
- p1 = strchr (p, ':');
- if (p1 == NULL)
- error (_("Malformed packet(a) (missing colon): %s\n\
-Packet: '%s'\n"),
- p, buf);
- if (strncmp (p, "thread", p1 - p) == 0)
- {
- p_temp = unpack_varlen_hex (++p1, &thread_num);
- p = p_temp;
- }
- else if ((strncmp (p, "watch", p1 - p) == 0)
- || (strncmp (p, "rwatch", p1 - p) == 0)
- || (strncmp (p, "awatch", p1 - p) == 0))
- {
- remote_stopped_by_watchpoint_p = 1;
- p = unpack_varlen_hex (++p1, &addr);
- remote_watch_data_address = (CORE_ADDR)addr;
- }
- else if (strncmp (p, "library", p1 - p) == 0)
- {
- p1++;
- p_temp = p1;
- while (*p_temp && *p_temp != ';')
- p_temp++;
-
- solibs_changed = 1;
- p = p_temp;
- }
- else
- {
- /* Silently skip unknown optional info. */
- p_temp = strchr (p1 + 1, ';');
- if (p_temp)
- p = p_temp;
- }
+ /* NO_HISTORY event.
+ p1 will indicate "begin" or "end", but
+ it makes no difference for now, so ignore it. */
+ replay_event = 1;
+ p_temp = strchr (p1 + 1, ';');
+ if (p_temp)
+ p = p_temp;
}
else
{
- struct packet_reg *reg = packet_reg_from_pnum (rsa, pnum);
- p = p1;
+ /* Silently skip unknown optional info. */
+ p_temp = strchr (p1 + 1, ';');
+ if (p_temp)
+ p = p_temp;
+ }
+ }
+ else
+ {
+ struct packet_reg *reg = packet_reg_from_pnum (rsa, pnum);
+ p = p1;
- if (*p != ':')
- error (_("Malformed packet(b) (missing colon): %s\n\
+ if (*p != ':')
+ error (_("Malformed packet(b) (missing colon): %s\n\
Packet: '%s'\n"),
- p, buf);
- ++p;
+ p, buf);
+ ++p;
- if (reg == NULL)
- error (_("Remote sent bad register number %s: %s\n\
+ if (reg == NULL)
+ error (_("Remote sent bad register number %s: %s\n\
Packet: '%s'\n"),
- phex_nz (pnum, 0), p, buf);
-
- fieldsize = hex2bin (p, regs,
- register_size (current_gdbarch,
- reg->regnum));
- p += 2 * fieldsize;
- if (fieldsize < register_size (current_gdbarch,
- reg->regnum))
- warning (_("Remote reply is too short: %s"), buf);
- regcache_raw_supply (get_current_regcache (),
- reg->regnum, regs);
- }
-
- if (*p != ';')
- error (_("Remote register badly formatted: %s\nhere: %s"),
- buf, p);
- ++p;
+ phex_nz (pnum, 0), p, buf);
+
+ fieldsize = hex2bin (p, regs,
+ register_size (target_gdbarch,
+ reg->regnum));
+ p += 2 * fieldsize;
+ if (fieldsize < register_size (target_gdbarch,
+ reg->regnum))
+ warning (_("Remote reply is too short: %s"), buf);
+ regcache_raw_supply (get_current_regcache (),
+ reg->regnum, regs);
}
+
+ if (*p != ';')
+ error (_("Remote register badly formatted: %s\nhere: %s"),
+ buf, p);
+ ++p;
}
- /* fall through */
- case 'S': /* Old style status, just signal only. */
- if (solibs_changed)
- status->kind = TARGET_WAITKIND_LOADED;
- else
- {
- status->kind = TARGET_WAITKIND_STOPPED;
- status->value.sig = (enum target_signal)
- (((fromhex (buf[1])) << 4) + (fromhex (buf[2])));
- }
- goto got_status;
- case 'W': /* Target exited. */
+ }
+ /* fall through */
+ case 'S': /* Old style status, just signal only. */
+ if (solibs_changed)
+ status->kind = TARGET_WAITKIND_LOADED;
+ else if (replay_event)
+ status->kind = TARGET_WAITKIND_NO_HISTORY;
+ else
+ {
+ status->kind = TARGET_WAITKIND_STOPPED;
+ status->value.sig = (enum target_signal)
+ (((fromhex (buf[1])) << 4) + (fromhex (buf[2])));
+ }
+ break;
+ case 'W': /* Target exited. */
+ case 'X':
+ {
+ char *p;
+ int pid;
+ ULONGEST value;
+
+ /* GDB used to accept only 2 hex chars here. Stubs should
+ only send more if they detect GDB supports multi-process
+ support. */
+ p = unpack_varlen_hex (&buf[1], &value);
+
+ if (buf[0] == 'W')
{
/* The remote process exited. */
status->kind = TARGET_WAITKIND_EXITED;
- status->value.integer = (fromhex (buf[1]) << 4) + fromhex (buf[2]);
- goto got_status;
+ status->value.integer = value;
+ }
+ else
+ {
+ /* The remote process exited with a signal. */
+ status->kind = TARGET_WAITKIND_SIGNALLED;
+ status->value.sig = (enum target_signal) value;
}
- case 'X':
- status->kind = TARGET_WAITKIND_SIGNALLED;
- status->value.sig = (enum target_signal)
- (((fromhex (buf[1])) << 4) + (fromhex (buf[2])));
- goto got_status;
- case 'O': /* Console output. */
- remote_console_output (buf + 1);
- if (target_can_async_p ())
- {
- /* Return immediately to the event loop. The event loop
- will still be waiting on the inferior afterwards. */
- status->kind = TARGET_WAITKIND_IGNORE;
- goto got_status;
- }
- else
- continue;
- case '\0':
- if (last_sent_signal != TARGET_SIGNAL_0)
- {
- /* Zero length reply means that we tried 'S' or 'C' and
- the remote system doesn't support it. */
- target_terminal_ours_for_output ();
- printf_filtered
- ("Can't send signals to this remote system. %s not sent.\n",
- target_signal_to_name (last_sent_signal));
- last_sent_signal = TARGET_SIGNAL_0;
- target_terminal_inferior ();
-
- strcpy ((char *) buf, last_sent_step ? "s" : "c");
- putpkt ((char *) buf);
- continue;
- }
- /* else fallthrough */
- default:
- warning (_("Invalid remote reply: %s"), buf);
- continue;
+ /* If no process is specified, assume inferior_ptid. */
+ pid = ptid_get_pid (inferior_ptid);
+ if (*p == '\0')
+ ;
+ else if (*p == ';')
+ {
+ p++;
+
+ if (p == '\0')
+ ;
+ else if (strncmp (p,
+ "process:", sizeof ("process:") - 1) == 0)
+ {
+ ULONGEST upid;
+ p += sizeof ("process:") - 1;
+ unpack_varlen_hex (p, &upid);
+ pid = upid;
+ }
+ else
+ error (_("unknown stop reply packet: %s"), buf);
+ }
+ else
+ error (_("unknown stop reply packet: %s"), buf);
+ event_ptid = pid_to_ptid (pid);
+ break;
+ }
+ case 'O': /* Console output. */
+ remote_console_output (buf + 1);
+
+ /* The target didn't really stop; keep waiting. */
+ rs->waiting_for_stop_reply = 1;
+
+ break;
+ case '\0':
+ if (last_sent_signal != TARGET_SIGNAL_0)
+ {
+ /* Zero length reply means that we tried 'S' or 'C' and the
+ remote system doesn't support it. */
+ target_terminal_ours_for_output ();
+ printf_filtered
+ ("Can't send signals to this remote system. %s not sent.\n",
+ target_signal_to_name (last_sent_signal));
+ last_sent_signal = TARGET_SIGNAL_0;
+ target_terminal_inferior ();
+
+ strcpy ((char *) buf, last_sent_step ? "s" : "c");
+ putpkt ((char *) buf);
+
+ /* We just told the target to resume, so a stop reply is in
+ order. */
+ rs->waiting_for_stop_reply = 1;
+ break;
}
+ /* else fallthrough */
+ default:
+ warning (_("Invalid remote reply: %s"), buf);
+ /* Keep waiting. */
+ rs->waiting_for_stop_reply = 1;
+ break;
+ }
+
+ /* Nothing interesting happened. */
+ if (status->kind == TARGET_WAITKIND_IGNORE)
+ return minus_one_ptid;
+
+ if (status->kind == TARGET_WAITKIND_EXITED
+ || status->kind == TARGET_WAITKIND_SIGNALLED)
+ {
+ int pid = ptid_get_pid (event_ptid);
+ delete_inferior (pid);
}
-got_status:
- if (thread_num != -1)
+ else
+ {
+ if (!ptid_equal (event_ptid, null_ptid))
+ record_currthread (event_ptid);
+ else
+ event_ptid = inferior_ptid;
+ }
+
+ return event_ptid;
+}
+
+static ptid_t
+remote_wait (ptid_t ptid, struct target_waitstatus *status)
+{
+ ptid_t event_ptid;
+
+ /* In synchronous mode, keep waiting until the target stops. In
+ asynchronous mode, always return to the event loop. */
+
+ do
{
- ptid_t ptid;
- ptid = ptid_build (ptid_get_pid (inferior_ptid), 0, thread_num);
- record_currthread (ptid);
- return ptid;
+ event_ptid = remote_wait_as (ptid, status);
}
+ while (status->kind == TARGET_WAITKIND_IGNORE
+ && !target_can_async_p ());
- return inferior_ptid;
+ return event_ptid;
}
/* Fetch a single register using a 'p' packet. */
int address_size = remote_address_size;
/* If "remoteaddresssize" was not set, default to target address size. */
if (!address_size)
- address_size = gdbarch_addr_bit (current_gdbarch);
+ address_size = gdbarch_addr_bit (target_gdbarch);
if (address_size > 0
&& address_size < (sizeof (ULONGEST) * 8))
{
int res;
+ set_general_thread (inferior_ptid);
+
if (should_write)
res = remote_write_bytes (mem_addr, buffer, mem_len);
else
switch ((enum serial_rc) ch)
{
case SERIAL_EOF:
- target_mourn_inferior ();
+ pop_target ();
error (_("Remote connection closed"));
/* no return */
case SERIAL_ERROR:
int tcount = 0;
char *p;
+ /* Catch cases like trying to read memory or listing threads while
+ we're waiting for a stop reply. The remote server wouldn't be
+ ready to handle this request, so we'd hang and timeout. We don't
+ have to worry about this in synchronous mode, because in that
+ case it's not possible to issue a command while the target is
+ running. */
+ if (target_can_async_p () && rs->waiting_for_stop_reply)
+ error (_("Cannot execute this command while the target is running."));
+
/* We're sending out a new packet. Make sure we don't look at a
stale cached response. */
rs->cached_wait_status = 0;
if (serial_write (remote_desc, buf2, p - buf2))
perror_with_name (_("putpkt: write failed"));
+ /* If this is a no acks version of the remote protocol, send the
+ packet and move on. */
+ if (rs->noack_mode)
+ break;
+
/* Read until either a timeout occurs (-2) or '+' is read. */
while (1)
{
}
#endif
}
+ return 0;
}
/* Come here after finding the start of a frame when we expected an
long bc;
int c;
char *buf = *buf_p;
+ struct remote_state *rs = get_remote_state ();
csum = 0;
bc = 0;
return -1;
}
+ /* Don't recompute the checksum; with no ack packets we
+ don't have any way to indicate a packet retransmission
+ is necessary. */
+ if (rs->noack_mode)
+ return bc;
+
pktcsum = (fromhex (check_0) << 4) | fromhex (check_1);
if (csum == pktcsum)
return bc;
if (forever) /* Watchdog went off? Kill the target. */
{
QUIT;
- target_mourn_inferior ();
+ pop_target ();
error (_("Watchdog timeout has expired. Target detached."));
}
if (remote_debug)
fputstrn_unfiltered (*buf, val, 0, gdb_stdlog);
fprintf_unfiltered (gdb_stdlog, "\n");
}
- serial_write (remote_desc, "+", 1);
+
+ /* Skip the ack char if we're in no-ack mode. */
+ if (!rs->noack_mode)
+ serial_write (remote_desc, "+", 1);
return val;
}
/* Try the whole thing again. */
retry:
- serial_write (remote_desc, "-", 1);
+ /* Skip the nack char if we're in no-ack mode. */
+ if (!rs->noack_mode)
+ serial_write (remote_desc, "-", 1);
}
/* We have tried hard enough, and just can't receive the packet.
Give up. */
printf_unfiltered (_("Ignoring packet error, continuing...\n"));
- serial_write (remote_desc, "+", 1);
+
+ /* Skip the ack char if we're in no-ack mode. */
+ if (!rs->noack_mode)
+ serial_write (remote_desc, "+", 1);
return -1;
}
\f
static void
remote_kill (void)
{
- /* Unregister the file descriptor from the event loop. */
- if (target_is_async_p ())
- serial_async (remote_desc, NULL, 0);
-
/* Use catch_errors so the user can quit from gdb even when we
aren't on speaking terms with the remote system. */
catch_errors ((catch_errors_ftype *) putpkt, "k", "", RETURN_MASK_ERROR);
target_mourn_inferior ();
}
+static int
+remote_vkill (int pid, struct remote_state *rs)
+{
+ if (remote_protocol_packets[PACKET_vKill].support == PACKET_DISABLE)
+ return -1;
+
+ /* Tell the remote target to detach. */
+ sprintf (rs->buf, "vKill;%x", pid);
+ putpkt (rs->buf);
+ getpkt (&rs->buf, &rs->buf_size, 0);
+
+ if (packet_ok (rs->buf,
+ &remote_protocol_packets[PACKET_vKill]) == PACKET_OK)
+ return 0;
+ else if (remote_protocol_packets[PACKET_vKill].support == PACKET_DISABLE)
+ return -1;
+ else
+ return 1;
+}
+
+static void
+extended_remote_kill (void)
+{
+ int res;
+ int pid = ptid_get_pid (inferior_ptid);
+ struct remote_state *rs = get_remote_state ();
+
+ res = remote_vkill (pid, rs);
+ if (res == -1 && !remote_multi_process_p (rs))
+ {
+ /* 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
+ }
+
+ if (res != 0)
+ error (_("Can't kill process"));
+
+ delete_inferior (pid);
+ target_mourn_inferior ();
+}
+
static void
remote_mourn (void)
{
remote_mourn_1 (struct target_ops *target)
{
unpush_target (target);
- generic_mourn_inferior ();
+
+ /* remote_close takes care of cleaning up. */
+}
+
+static int
+select_new_thread_callback (struct thread_info *th, void* data)
+{
+ if (!ptid_equal (th->ptid, minus_one_ptid))
+ {
+ switch_to_thread (th->ptid);
+ printf_filtered (_("[Switching to %s]\n"),
+ target_pid_to_str (inferior_ptid));
+ return 1;
+ }
+ return 0;
}
static void
{
struct remote_state *rs = get_remote_state ();
+ /* In case we got here due to an error, but we're going to stay
+ connected. */
+ rs->waiting_for_stop_reply = 0;
+
/* 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. */
- generic_mourn_inferior ();
-
- /* Check whether the target is running now - some remote stubs
- automatically restart after kill. */
- putpkt ("?");
- getpkt (&rs->buf, &rs->buf_size, 0);
-
- if (rs->buf[0] == 'S' || rs->buf[0] == 'T')
+ if (have_inferiors ())
{
- /* Assume that the target has been restarted. Set inferior_ptid
- so that bits of core GDB realizes there's something here, e.g.,
- so that the user can say "kill" again. */
- inferior_ptid = remote_current_thread (magic_null_ptid);
- add_thread_silent (inferior_ptid);
+ 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
{
- /* Mark this (still pushed) target as not executable until we
- restart it. */
- target_mark_exited (target);
+ struct remote_state *rs = get_remote_state ();
+
+ /* Call common code to mark the inferior as not running. */
+ generic_mourn_inferior ();
+ if (!remote_multi_process_p (rs))
+ {
+ /* Check whether the target is running now - some remote stubs
+ automatically restart after kill. */
+ putpkt ("?");
+ getpkt (&rs->buf, &rs->buf_size, 0);
+
+ if (rs->buf[0] == 'S' || rs->buf[0] == 'T')
+ {
+ /* Assume that the target has been restarted. Set inferior_ptid
+ so that bits of core GDB realizes there's something here, e.g.,
+ so that the user can say "kill" again. */
+ inferior_ptid = magic_null_ptid;
+ }
+ else
+ {
+ /* Mark this (still pushed) target as not executable until we
+ restart it. */
+ target_mark_exited (target);
+ }
+ }
+ else
+ /* Always remove execution if this was the last process. */
+ target_mark_exited (target);
}
}
error (_("Remote file name too long for run packet"));
len += 2 * bin2hex ((gdb_byte *) remote_exec_file, rs->buf + len, 0);
+ gdb_assert (args != NULL);
if (*args)
{
struct cleanup *back_to;
int i;
char **argv;
- argv = buildargv (args);
+ argv = gdb_buildargv (args);
back_to = make_cleanup ((void (*) (void *)) freeargv, argv);
for (i = 0; argv[i] != NULL; i++)
{
init_wait_for_inferior ();
/* Now mark the inferior as running before we do anything else. */
- attach_flag = 0;
inferior_ptid = magic_null_ptid;
+ add_inferior (ptid_get_pid (inferior_ptid));
add_thread_silent (inferior_ptid);
target_mark_running (&extended_remote_ops);
char *p;
int bpsize;
- gdbarch_breakpoint_from_pc
- (current_gdbarch, &addr, &bpsize);
+ gdbarch_breakpoint_from_pc (target_gdbarch, &addr, &bpsize);
rs = get_remote_state ();
p = rs->buf;
static int
remote_stopped_by_watchpoint (void)
{
- return remote_stopped_by_watchpoint_p;
+ return remote_stopped_by_watchpoint_p;
}
static int
instruction, even though we aren't inserting one ourselves. */
gdbarch_breakpoint_from_pc
- (current_gdbarch, &bp_tgt->placed_address, &bp_tgt->placed_size);
+ (target_gdbarch, &bp_tgt->placed_address, &bp_tgt->placed_size);
if (remote_protocol_packets[PACKET_Z1].support == PACKET_DISABLE)
return -1;
_("remote_remove_hw_breakpoint: reached end of function"));
}
-/* Some targets are only capable of doing downloads, and afterwards
- they switch to the remote serial protocol. This function provides
- a clean way to get from the download target to the remote target.
- It's basically just a wrapper so that we don't have to expose any
- of the internal workings of remote.c.
-
- Prior to calling this routine, you should shutdown the current
- target code, else you will get the "A program is being debugged
- already..." message. Usually a call to pop_target() suffices. */
-
-void
-push_remote_target (char *name, int from_tty)
-{
- printf_filtered (_("Switching to remote protocol\n"));
- remote_open (name, from_tty);
-}
-
/* Table used by the crc32 function to calcuate the checksum. */
static unsigned long crc32_table[256] =
const char *annex, gdb_byte *readbuf,
const gdb_byte *writebuf, ULONGEST offset, LONGEST len)
{
- struct remote_state *rs = get_remote_state ();
+ struct remote_state *rs;
int i;
char *p2;
char query_type;
+ set_general_thread (inferior_ptid);
+
+ rs = get_remote_state ();
+
/* Handle memory using the standard memory routines. */
if (object == TARGET_OBJECT_MEMORY)
{
remote_pid_to_str (ptid_t ptid)
{
static char buf[64];
+ struct remote_state *rs = get_remote_state ();
if (ptid_equal (magic_null_ptid, ptid))
{
xsnprintf (buf, sizeof buf, "Thread <main>");
return buf;
}
+ else if (remote_multi_process_p (rs)
+ && ptid_get_tid (ptid) != 0 && ptid_get_pid (ptid) != 0)
+ {
+ xsnprintf (buf, sizeof buf, "Thread %d.%ld",
+ ptid_get_pid (ptid), ptid_get_tid (ptid));
+ return buf;
+ }
else if (ptid_get_tid (ptid) != 0)
{
xsnprintf (buf, sizeof buf, "Thread %ld",
{
struct remote_state *rs = get_remote_state ();
char *p = rs->buf;
+ char *endp = rs->buf + get_remote_packet_size ();
enum packet_result result;
strcpy (p, "qGetTLSAddr:");
p += strlen (p);
- p += hexnumstr (p, ptid_get_tid (ptid));
+ p = write_ptid (p, endp, ptid);
*p++ = ',';
p += hexnumstr (p, offset);
*p++ = ',';
remote_read_description (struct target_ops *target)
{
struct remote_g_packet_data *data
- = gdbarch_data (current_gdbarch, remote_g_packet_data_handle);
+ = gdbarch_data (target_gdbarch, remote_g_packet_data_handle);
if (!VEC_empty (remote_g_packet_guess_s, data->guesses))
{
int ret, bytes_read;
char *attachment_tmp;
- if (remote_protocol_packets[which_packet].support == PACKET_DISABLE)
+ if (!remote_desc
+ || remote_protocol_packets[which_packet].support == PACKET_DISABLE)
{
*remote_errno = FILEIO_ENOSYS;
return -1;
remote_hostio_close (fd, &remote_errno);
}
+
+static void *
+remote_bfd_iovec_open (struct bfd *abfd, void *open_closure)
+{
+ const char *filename = bfd_get_filename (abfd);
+ int fd, remote_errno;
+ int *stream;
+
+ gdb_assert (remote_filename_p (filename));
+
+ fd = remote_hostio_open (filename + 7, FILEIO_O_RDONLY, 0, &remote_errno);
+ if (fd == -1)
+ {
+ errno = remote_fileio_errno_to_host (remote_errno);
+ bfd_set_error (bfd_error_system_call);
+ return NULL;
+ }
+
+ stream = xmalloc (sizeof (int));
+ *stream = fd;
+ return stream;
+}
+
+static int
+remote_bfd_iovec_close (struct bfd *abfd, void *stream)
+{
+ int fd = *(int *)stream;
+ int remote_errno;
+
+ xfree (stream);
+
+ /* Ignore errors on close; these may happen if the remote
+ connection was already torn down. */
+ remote_hostio_close (fd, &remote_errno);
+
+ return 1;
+}
+
+static file_ptr
+remote_bfd_iovec_pread (struct bfd *abfd, void *stream, void *buf,
+ file_ptr nbytes, file_ptr offset)
+{
+ int fd = *(int *)stream;
+ int remote_errno;
+ file_ptr pos, bytes;
+
+ pos = 0;
+ while (nbytes > pos)
+ {
+ bytes = remote_hostio_pread (fd, (char *)buf + pos, nbytes - pos,
+ offset + pos, &remote_errno);
+ if (bytes == 0)
+ /* Success, but no bytes, means end-of-file. */
+ break;
+ if (bytes == -1)
+ {
+ errno = remote_fileio_errno_to_host (remote_errno);
+ bfd_set_error (bfd_error_system_call);
+ return -1;
+ }
+
+ pos += bytes;
+ }
+
+ return pos;
+}
+
+static int
+remote_bfd_iovec_stat (struct bfd *abfd, void *stream, struct stat *sb)
+{
+ /* FIXME: We should probably implement remote_hostio_stat. */
+ sb->st_size = INT_MAX;
+ return 0;
+}
+
+int
+remote_filename_p (const char *filename)
+{
+ return strncmp (filename, "remote:", 7) == 0;
+}
+
+bfd *
+remote_bfd_open (const char *remote_file, const char *target)
+{
+ return bfd_openr_iovec (remote_file, target,
+ remote_bfd_iovec_open, NULL,
+ remote_bfd_iovec_pread,
+ remote_bfd_iovec_close,
+ remote_bfd_iovec_stat);
+}
+
void
remote_file_put (const char *local_file, const char *remote_file, int from_tty)
{
struct cleanup *back_to;
char **argv;
- argv = buildargv (args);
- if (argv == NULL)
- nomem (0);
+ if (args == NULL)
+ error_no_arg (_("file to put"));
+
+ argv = gdb_buildargv (args);
back_to = make_cleanup_freeargv (argv);
if (argv[0] == NULL || argv[1] == NULL || argv[2] != NULL)
error (_("Invalid parameters to remote put"));
struct cleanup *back_to;
char **argv;
- argv = buildargv (args);
- if (argv == NULL)
- nomem (0);
+ if (args == NULL)
+ error_no_arg (_("file to get"));
+
+ argv = gdb_buildargv (args);
back_to = make_cleanup_freeargv (argv);
if (argv[0] == NULL || argv[1] == NULL || argv[2] != NULL)
error (_("Invalid parameters to remote get"));
struct cleanup *back_to;
char **argv;
- argv = buildargv (args);
- if (argv == NULL)
- nomem (0);
+ if (args == NULL)
+ error_no_arg (_("file to delete"));
+
+ argv = gdb_buildargv (args);
back_to = make_cleanup_freeargv (argv);
if (argv[0] == NULL || argv[1] != NULL)
error (_("Invalid parameters to remote delete"));
help_list (remote_cmdlist, "remote ", -1, gdb_stdout);
}
+static int remote_target_can_reverse = 1;
+
+static int
+remote_can_execute_reverse (void)
+{
+ return remote_target_can_reverse;
+}
+
static void
init_remote_ops (void)
{
remote_ops.to_has_registers = 1;
remote_ops.to_has_execution = 1;
remote_ops.to_has_thread_control = tc_schedlock; /* can lock scheduler */
+ remote_ops.to_can_execute_reverse = remote_can_execute_reverse;
remote_ops.to_magic = OPS_MAGIC;
remote_ops.to_memory_map = remote_memory_map;
remote_ops.to_flash_erase = remote_flash_erase;
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_kill = extended_remote_kill;
}
static int
remote_can_async_p (void)
{
- if (!remote_async_permitted)
+ if (!target_async_permitted)
/* We only enable async when the user specifically asks for it. */
return 0;
static int
remote_is_async_p (void)
{
- if (!remote_async_permitted)
+ if (!target_async_permitted)
/* We only enable async when the user specifically asks for it. */
return 0;
add_packet_config_cmd (&remote_protocol_packets[PACKET_vRun],
"vRun", "run", 0);
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_QStartNoAckMode],
+ "QStartNoAckMode", "noack", 0);
+
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_vKill],
+ "vKill", "kill", 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
Show the remote pathname for \"run\""), NULL, NULL, NULL,
&remote_set_cmdlist, &remote_show_cmdlist);
- add_setshow_boolean_cmd ("remote-async", class_maintenance,
- &remote_async_permitted_set, _("\
-Set whether gdb controls the remote inferior in asynchronous mode."), _("\
-Show whether gdb controls the remote inferior in asynchronous mode."), _("\
-Tells gdb whether to control the remote inferior in asynchronous mode."),
- set_maintenance_remote_async_permitted,
- show_maintenance_remote_async_permitted,
- &maintenance_set_cmdlist,
- &maintenance_show_cmdlist);
-
-
/* Eventually initialize fileio. See fileio.c */
initialize_remote_fileio (remote_set_cmdlist, remote_show_cmdlist);
/* Take advantage of the fact that the LWP field is not used, to tag
special ptids with it set to != 0. */
- magic_null_ptid = ptid_build (0, 1, -1);
- not_sent_ptid = ptid_build (0, 1, -2);
- any_thread_ptid = ptid_build (0, 1, 0);
+ magic_null_ptid = ptid_build (42000, 1, -1);
+ not_sent_ptid = ptid_build (42000, 1, -2);
+ any_thread_ptid = ptid_build (42000, 1, 0);
}