/* Remote target communications for serial-line targets in custom GDB protocol
Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
- 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+ 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
Free Software Foundation, Inc.
This file is part of GDB.
#include "gdbcore.h" /* for exec_bfd */
#include "remote-fileio.h"
+#include "gdb/fileio.h"
+#include "gdb_stat.h"
#include "memory-map.h"
static void remote_resume (ptid_t ptid, int step,
enum target_signal siggnal);
-static void remote_async_resume (ptid_t ptid, int step,
- enum target_signal siggnal);
static void remote_open (char *name, int from_tty);
-static void remote_async_open (char *name, int from_tty);
static void extended_remote_open (char *name, int from_tty);
-static void extended_remote_async_open (char *name, int from_tty);
-static void remote_open_1 (char *, int, struct target_ops *, int extended_p,
- int async_p);
+static void remote_open_1 (char *, int, struct target_ops *, int extended_p);
static void remote_close (int quitting);
static void remote_store_registers (struct regcache *regcache, int regno);
static void remote_mourn (void);
-static void remote_async_mourn (void);
static void extended_remote_restart (void);
static int readchar (int timeout);
static ptid_t remote_wait (ptid_t ptid,
- struct target_waitstatus *status);
-static ptid_t remote_async_wait (ptid_t ptid,
- struct target_waitstatus *status);
+ struct target_waitstatus *status);
static void remote_kill (void);
-static void remote_async_kill (void);
static int tohex (int nib);
+static int remote_can_async_p (void);
+
+static int remote_is_async_p (void);
+
+static void remote_async (void (*callback) (enum inferior_event_type event_type,
+ void *context), void *context);
+
+static int remote_async_mask (int new_mask);
+
static void remote_detach (char *args, int from_tty);
static void remote_interrupt (int signo);
static void interrupt_query (void);
-static void set_thread (int, int);
+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 init_extended_remote_ops (void);
-static void remote_stop (void);
+static void remote_stop (ptid_t);
static int ishex (int ch, int *val);
static void remote_find_new_threads (void);
-static void record_currthread (int currthread);
+static void record_currthread (ptid_t currthread);
static int fromhex (int a);
void _initialize_remote (void);
+/* For "remote". */
+
+static struct cmd_list_element *remote_cmdlist;
+
/* For "set remote" and "show remote". */
static struct cmd_list_element *remote_set_cmdlist;
a buffer in the stub), this will be set to that packet size.
Otherwise zero, meaning to use the guessed size. */
long explicit_packet_size;
+
+ /* remote_wait is normally called when the target is running and
+ waits for a stop reply packet. But sometimes we need to call it
+ when the target is already stopped. We can send a "?" packet
+ and have remote_wait read the response. Or, if we already have
+ the response, we can stash it in BUF and tell remote_wait to
+ 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;
};
/* This data could be associated with a target, but we do not always
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. */
/* Use the architecture to build a regnum<->pnum table, which will be
1:1 unless a feature set specifies otherwise. */
rsa->regs = GDBARCH_OBSTACK_CALLOC (gdbarch,
- gdbarch_num_regs (current_gdbarch),
+ gdbarch_num_regs (gdbarch),
struct packet_reg);
- for (regnum = 0; regnum < gdbarch_num_regs (current_gdbarch); regnum++)
+ for (regnum = 0; regnum < gdbarch_num_regs (gdbarch); regnum++)
{
struct packet_reg *r = &rsa->regs[regnum];
- if (register_size (current_gdbarch, regnum) == 0)
+ if (register_size (gdbarch, regnum) == 0)
/* Do not try to fetch zero-sized (placeholder) registers. */
r->pnum = -1;
else
with a remote protocol number, in order of ascending protocol
number. */
- remote_regs = alloca (gdbarch_num_regs (current_gdbarch)
- * sizeof (struct packet_reg *));
+ remote_regs = alloca (gdbarch_num_regs (gdbarch)
+ * sizeof (struct packet_reg *));
for (num_remote_regs = 0, regnum = 0;
- regnum < gdbarch_num_regs (current_gdbarch);
+ regnum < gdbarch_num_regs (gdbarch);
regnum++)
if (rsa->regs[regnum].pnum != -1)
remote_regs[num_remote_regs++] = &rsa->regs[regnum];
{
remote_regs[regnum]->in_g_packet = 1;
remote_regs[regnum]->offset = offset;
- offset += register_size (current_gdbarch, remote_regs[regnum]->regnum);
+ offset += register_size (gdbarch, remote_regs[regnum]->regnum);
}
/* Record the maximum possible size of the g packet - it may turn out
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)
static struct target_ops extended_remote_ops;
-/* Temporary target ops. Just like the remote_ops and
- extended_remote_ops, but with asynchronous support. */
-static struct target_ops remote_async_ops;
-
-static struct target_ops extended_async_remote_ops;
+static int remote_async_mask_value = 1;
/* FIXME: cagney/1999-09-23: Even though getpkt was called with
``forever'' still use the normal timeout mechanism. This is
static int remote_address_size;
-/* Tempoary to track who currently owns the terminal. See
- target_async_terminal_* for more details. */
+/* Temporary to track who currently owns the terminal. See
+ remote_terminal_* for more details. */
static int remote_async_terminal_ours_p;
+/* The executable file to use for "run" on the remote side. */
+
+static char *remote_exec_file = "";
+
\f
/* User configurable variables for the number of characters in a
memory read/write packet. MIN (rsa->remote_packet_size,
PACKET_Z2,
PACKET_Z3,
PACKET_Z4,
+ PACKET_vFile_open,
+ PACKET_vFile_pread,
+ PACKET_vFile_pwrite,
+ PACKET_vFile_close,
+ PACKET_vFile_unlink,
PACKET_qXfer_auxv,
PACKET_qXfer_features,
PACKET_qXfer_libraries,
PACKET_qGetTLSAddr,
PACKET_qSupported,
PACKET_QPassSignals,
+ PACKET_qSearch_memory,
+ PACKET_vAttach,
+ PACKET_vRun,
+ PACKET_QStartNoAckMode,
PACKET_MAX
};
static struct async_signal_handler *sigint_remote_twice_token;
static struct async_signal_handler *sigint_remote_token;
-/* These are pointers to hook functions that may be set in order to
- modify resume/wait behavior for a particular architecture. */
-
-void (*deprecated_target_resume_hook) (void);
-void (*deprecated_target_wait_loop_hook) (void);
\f
+static ptid_t magic_null_ptid;
+static ptid_t not_sent_ptid;
+static ptid_t any_thread_ptid;
+
+/* These are the threads which we last sent to the remote system. The
+ TID member will be -1 for all or -2 for not sent yet. */
+
+static ptid_t general_thread;
+static ptid_t continue_thread;
-/* These are the threads which we last sent to the remote system.
- -1 for all or -2 for not sent yet. */
-static int general_thread;
-static int continue_thread;
/* Call this function as a result of
1) A halt indication (T packet) containing a thread id
*/
static void
-record_currthread (int currthread)
+record_currthread (ptid_t currthread)
{
general_thread = 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 (pid_to_ptid (currthread)))
+ if (!in_thread_list (currthread))
{
- add_thread (pid_to_ptid (currthread));
- ui_out_text (uiout, "[New ");
- ui_out_text (uiout, target_pid_to_str (pid_to_ptid (currthread)));
- ui_out_text (uiout, "]\n");
+ if (ptid_equal (pid_to_ptid (ptid_get_pid (currthread)), 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. */
+ struct thread_info *th = find_thread_pid (inferior_ptid);
+ inferior_ptid = th->ptid = currthread;
+ }
+ else 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;
+ }
+ else
+ /* This is really a new thread. Add it. */
+ add_thread (currthread);
}
}
}
}
-#define MAGIC_NULL_PID 42000
-
+/* If PTID is MAGIC_NULL_PTID, don't set any thread. If PTID is
+ MINUS_ONE_PTID, set the thread to -1, so the stub returns the
+ thread. If GEN is set, set the general thread, if not, then set
+ the step/continue thread. */
static void
-set_thread (int th, int gen)
+set_thread (struct ptid ptid, int gen)
{
struct remote_state *rs = get_remote_state ();
+ ptid_t state = gen ? general_thread : continue_thread;
char *buf = rs->buf;
- int state = gen ? general_thread : continue_thread;
+ char *endbuf = rs->buf + get_remote_packet_size ();
- if (state == th)
+ if (ptid_equal (state, ptid))
return;
- buf[0] = 'H';
- buf[1] = gen ? 'g' : 'c';
- if (th == MAGIC_NULL_PID)
+ *buf++ = 'H';
+ *buf++ = gen ? 'g' : 'c';
+ if (ptid_equal (ptid, magic_null_ptid))
+ xsnprintf (buf, endbuf - buf, "0");
+ else if (ptid_equal (ptid, any_thread_ptid))
+ xsnprintf (buf, endbuf - buf, "0");
+ else if (ptid_equal (ptid, minus_one_ptid))
+ xsnprintf (buf, endbuf - buf, "-1");
+ else
{
- buf[2] = '0';
- buf[3] = '\0';
+ int tid = ptid_get_tid (ptid);
+ if (tid < 0)
+ xsnprintf (buf, endbuf - buf, "-%x", -tid);
+ else
+ xsnprintf (buf, endbuf - buf, "%x", tid);
}
- else if (th < 0)
- xsnprintf (&buf[2], get_remote_packet_size () - 2, "-%x", -th);
- else
- xsnprintf (&buf[2], get_remote_packet_size () - 2, "%x", th);
- putpkt (buf);
+ putpkt (rs->buf);
getpkt (&rs->buf, &rs->buf_size, 0);
if (gen)
- general_thread = th;
+ general_thread = ptid;
else
- continue_thread = th;
+ continue_thread = ptid;
+}
+
+static void
+set_general_thread (struct ptid ptid)
+{
+ set_thread (ptid, 1);
+}
+
+static void
+set_continue_thread (struct ptid ptid)
+{
+ set_thread (ptid, 0);
}
+
\f
-/* Return nonzero if the thread TH is still alive on the remote system. */
+/* Return nonzero if the thread PTID is still alive on the remote
+ system. */
static int
remote_thread_alive (ptid_t ptid)
{
struct remote_state *rs = get_remote_state ();
- int tid = PIDGET (ptid);
+ int tid = ptid_get_tid (ptid);
+
+ if (ptid_equal (ptid, magic_null_ptid))
+ /* The main thread is always alive. */
+ return 1;
+
+ if (ptid_get_pid (ptid) != 0 && ptid_get_tid (ptid) == 0)
+ /* The main thread is always alive. This can happen after a
+ vAttach, if the remote side doesn't support
+ multi-threading. */
+ return 1;
if (tid < 0)
xsnprintf (rs->buf, get_remote_packet_size (), "T-%08x", -tid);
static char *
unpack_nibble (char *buf, int *val)
{
- ishex (*buf++, val);
+ *val = fromhex (*buf++);
return buf;
}
putpkt (rs->buf);
getpkt (&rs->buf, &rs->buf_size, 0);
- *result_count =
- parse_threadlist_response (rs->buf + 2, result_limit, &echo_nextthread,
- threadlist, done);
+ if (*rs->buf == '\0')
+ *result_count = 0;
+ else
+ *result_count =
+ parse_threadlist_response (rs->buf + 2, result_limit, &echo_nextthread,
+ threadlist, done);
if (!threadmatch (&echo_nextthread, nextthread))
{
/* remote_find_new_threads retrieves the thread list and for each
thread in the list, looks up the thread in GDB's internal list,
- ading the thread if it does not already exist. This involves
+ adding the thread if it does not already exist. This involves
getting partial thread lists from the remote target so, polling the
quit_flag is required. */
static int
remote_newthread_step (threadref *ref, void *context)
{
- ptid_t ptid;
-
- ptid = pid_to_ptid (threadref_to_int (ref));
+ int pid = ptid_get_pid (inferior_ptid);
+ ptid_t ptid = ptid_build (pid, 0, threadref_to_int (ref));
if (!in_thread_list (ptid))
add_thread (ptid);
remote_current_thread (ptid_t oldpid)
{
struct remote_state *rs = get_remote_state ();
+ char *p = rs->buf;
+ int tid;
+ int pid;
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. */
- return pid_to_ptid (strtoul (&rs->buf[2], NULL, 16));
+ {
+ /* 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);
+ }
else
return oldpid;
}
{
remote_threadlist_iterator (remote_newthread_step, 0,
CRAZY_MAX_THREADS);
- if (PIDGET (inferior_ptid) == MAGIC_NULL_PID) /* ack ack ack */
- inferior_ptid = remote_current_thread (inferior_ptid);
}
/*
struct remote_state *rs = get_remote_state ();
char *bufp;
int tid;
+ int pid;
+ ptid_t new_thread;
if (remote_desc == 0) /* paranoia */
error (_("Command can only be used when connected to the remote target."));
positive numbers out of range for signed 'long',
and return LONG_MAX to indicate an overflow. */
tid = strtoul (bufp, &bufp, 16);
- if (tid != 0 && !in_thread_list (pid_to_ptid (tid)))
- add_thread (pid_to_ptid (tid));
+ 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);
}
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,%x",
- PIDGET (tp->ptid));
+ xsnprintf (rs->buf, get_remote_packet_size (), "qThreadExtraInfo,%lx",
+ ptid_get_tid (tp->ptid));
putpkt (rs->buf);
getpkt (&rs->buf, &rs->buf_size, 0);
if (rs->buf[0] != 0)
use_threadextra_query = 0;
set = TAG_THREADID | TAG_EXISTS | TAG_THREADNAME
| TAG_MOREDISPLAY | TAG_DISPLAY;
- int_to_threadref (&id, PIDGET (tp->ptid));
+ int_to_threadref (&id, ptid_get_tid (tp->ptid));
if (remote_get_threadinfo (&id, set, &threadinfo))
if (threadinfo.active)
{
putpkt (rs->buf);
remote_fileio_reset ();
-
- /* Now query for status so this looks just like we restarted
- gdbserver from scratch. */
- putpkt ("?");
- getpkt (&rs->buf, &rs->buf_size, 0);
}
\f
/* Clean up connection to a remote debugger. */
segments[1] = data->segment_bases[1] + data_addr;
num_segments = 2;
}
+ /* If the object file has only one segment, assume that it is text
+ rather than data; main programs with no writable data are rare,
+ but programs with no code are useless. Of course the code might
+ have ended up in the data segment... to detect that we would need
+ the permissions here. */
+ else if (data && data->num_segments == 1)
+ {
+ segments[0] = data->segment_bases[0] + text_addr;
+ num_segments = 1;
+ }
/* There's no way to relocate by segment. */
else
do_segments = 0;
/* Stub for catch_exception. */
+struct start_remote_args
+{
+ int from_tty;
+
+ /* The current target. */
+ struct target_ops *target;
+
+ /* Non-zero if this is an extended-remote target. */
+ int extended_p;
+};
+
static void
-remote_start_remote (struct ui_out *uiout, void *from_tty_p)
+remote_start_remote (struct ui_out *uiout, void *opaque)
{
- int from_tty = * (int *) from_tty_p;
+ struct remote_state *rs = get_remote_state ();
+ struct start_remote_args *args = opaque;
+ 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);
+ /* Check whether the target is running now. */
+ putpkt ("?");
+ getpkt (&rs->buf, &rs->buf_size, 0);
- /* Let the stub know that we want it to return the thread. */
- set_thread (-1, 0);
+ if (rs->buf[0] == 'W' || rs->buf[0] == 'X')
+ {
+ if (args->extended_p)
+ {
+ /* We're connected, but not running. Drop out before we
+ call start_remote. */
+ target_mark_exited (args->target);
+ return;
+ }
+ else
+ error (_("The target is not running (try extended-remote?)"));
+ }
+ 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);
+ }
+
+ /* Start afresh. */
+ init_thread_list ();
+
+ /* Let the stub know that we want it to return the thread. */
+ set_continue_thread (minus_one_ptid);
+
+ /* Without this, some commands which require an active target
+ (such as kill) won't work. This variable serves (at least)
+ double duty as both the pid of the target process (if it has
+ such), and as a flag indicating that a target is active.
+ These functions should be split out into seperate variables,
+ especially since GDB will someday have a notion of debugging
+ several processes. */
+ inferior_ptid = magic_null_ptid;
+
+ /* Now, if we have thread information, update inferior_ptid. */
inferior_ptid = remote_current_thread (inferior_ptid);
+ /* Always add the main thread. */
+ add_thread_silent (inferior_ptid);
+
get_offsets (); /* Get text, data & bss offsets. */
- putpkt ("?"); /* Initiate a query from remote machine. */
- immediate_quit--;
+ /* Use the previously fetched status. */
+ gdb_assert (wait_status != NULL);
+ strcpy (rs->buf, wait_status);
+ rs->cached_wait_status = 1;
- start_remote (from_tty); /* Initialize gdb process mechanisms. */
+ immediate_quit--;
+ start_remote (args->from_tty); /* Initialize gdb process mechanisms. */
}
/* Open a connection to a remote debugger.
static void
remote_open (char *name, int from_tty)
{
- remote_open_1 (name, from_tty, &remote_ops, 0, 0);
-}
-
-/* Just like remote_open, but with asynchronous support. */
-static void
-remote_async_open (char *name, int from_tty)
-{
- remote_open_1 (name, from_tty, &remote_async_ops, 0, 1);
+ remote_open_1 (name, from_tty, &remote_ops, 0);
}
/* Open a connection to a remote debugger using the extended
static void
extended_remote_open (char *name, int from_tty)
{
- remote_open_1 (name, from_tty, &extended_remote_ops, 1 /*extended_p */,
- 0 /* async_p */);
-}
-
-/* Just like extended_remote_open, but with asynchronous support. */
-static void
-extended_remote_async_open (char *name, int from_tty)
-{
- remote_open_1 (name, from_tty, &extended_async_remote_ops,
- 1 /*extended_p */, 1 /* async_p */);
+ remote_open_1 (name, from_tty, &extended_remote_ops, 1 /*extended_p */);
}
/* Generic code for opening a connection to a remote target. */
/* 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);
PACKET_qXfer_spu_write },
{ "QPassSignals", PACKET_DISABLE, remote_supported_packet,
PACKET_QPassSignals },
+ { "QStartNoAckMode", PACKET_DISABLE, remote_supported_packet,
+ PACKET_QStartNoAckMode },
};
static void
static void
-remote_open_1 (char *name, int from_tty, struct target_ops *target,
- int extended_p, int async_p)
+remote_open_1 (char *name, int from_tty, struct target_ops *target, int extended_p)
{
struct remote_state *rs = get_remote_state ();
+ struct packet_config *noack_config;
+
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 (!async_p)
+ if (!target_async_permitted)
wait_forever_enabled_p = 1;
+ /* If we're connected to a running target, target_preopen will kill it.
+ But if we're connected to a target system with no running process,
+ then we will still be connected when it returns. Ask this question
+ first, before target_preopen has a chance to kill anything. */
+ if (remote_desc != NULL && !target_has_execution)
+ {
+ if (!from_tty
+ || query (_("Already connected to a remote target. Disconnect? ")))
+ pop_target ();
+ else
+ error (_("Still connected."));
+ }
+
target_preopen (from_tty);
unpush_target (target);
+ /* This time without a query. If we were connected to an
+ extended-remote target and target_preopen killed the running
+ process, we may still be connected. If we are starting "target
+ remote" now, the extended-remote target will not have been
+ removed by unpush_target. */
+ if (remote_desc != NULL && !target_has_execution)
+ pop_target ();
+
/* Make sure we send the passed signals list the next time we resume. */
xfree (last_pass_packet);
last_pass_packet = NULL;
}
push_target (target); /* Switch to using remote target now. */
+ /* Assume that the target is running, unless we learn otherwise. */
+ target_mark_running (target);
+
/* Reset the target state; these things will be queried either by
remote_query_supported or as they are needed. */
init_all_packet_configs ();
rs->explicit_packet_size = 0;
+ rs->noack_mode = 0;
- general_thread = -2;
- continue_thread = -2;
+ general_thread = not_sent_ptid;
+ continue_thread = not_sent_ptid;
/* Probe for ability to use "ThreadInfo" query, as required. */
use_threadinfo_query = 1;
use_threadextra_query = 1;
+ /* 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;
+ }
+
/* Next, if the target can specify a description, read it. We do
this before anything involving memory or registers. */
target_find_description ();
- /* Without this, some commands which require an active target (such
- as kill) won't work. This variable serves (at least) double duty
- as both the pid of the target process (if it has such), and as a
- flag indicating that a target is active. These functions should
- be split out into seperate variables, especially since GDB will
- someday have a notion of debugging several processes. */
-
- inferior_ptid = pid_to_ptid (MAGIC_NULL_PID);
-
- if (async_p)
+ if (target_async_permitted)
{
/* With this target we start out by owning the terminal. */
remote_async_terminal_ours_p = 1;
all the ``target ....'' commands to share a common callback
function. See cli-dump.c. */
{
- struct gdb_exception ex
- = catch_exception (uiout, remote_start_remote, &from_tty,
- RETURN_MASK_ALL);
+ struct gdb_exception ex;
+ struct start_remote_args args;
+
+ args.from_tty = from_tty;
+ args.target = target;
+ args.extended_p = extended_p;
+
+ ex = catch_exception (uiout, remote_start_remote, &args, RETURN_MASK_ALL);
if (ex.reason < 0)
{
pop_target ();
- if (async_p)
+ if (target_async_permitted)
wait_forever_enabled_p = 1;
throw_exception (ex);
}
}
- if (async_p)
+ if (target_async_permitted)
wait_forever_enabled_p = 1;
if (extended_p)
getpkt (&rs->buf, &rs->buf_size, 0);
}
- if (exec_bfd) /* No use without an exec file. */
- remote_check_symbols (symfile_objfile);
+ /* 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
die when it hits one. */
static void
-remote_detach (char *args, int from_tty)
+remote_detach_1 (char *args, int from_tty, int extended)
{
struct remote_state *rs = get_remote_state ();
if (args)
error (_("Argument given to \"detach\" when remotely debugging."));
+ if (!target_has_execution)
+ error (_("No process to detach from."));
+
/* Tell the remote target to detach. */
strcpy (rs->buf, "D");
putpkt (rs->buf);
target_mourn_inferior ();
if (from_tty)
- puts_filtered ("Ending remote debugging.\n");
+ {
+ if (extended)
+ puts_filtered ("Detached from remote process.\n");
+ else
+ puts_filtered ("Ending remote debugging.\n");
+ }
+}
+
+static void
+remote_detach (char *args, int from_tty)
+{
+ remote_detach_1 (args, from_tty, 0);
+}
+
+static void
+extended_remote_detach (char *args, int from_tty)
+{
+ remote_detach_1 (args, from_tty, 1);
}
/* Same as remote_detach, but don't send the "D" packet; just disconnect. */
remote_disconnect (struct target_ops *target, char *args, int from_tty)
{
if (args)
- error (_("Argument given to \"detach\" when remotely debugging."));
+ 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);
- target_mourn_inferior ();
+ /* 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. */
+ remote_mourn_1 (target);
+
if (from_tty)
puts_filtered ("Ending remote debugging.\n");
}
+/* Attach to the process specified by ARGS. If FROM_TTY is non-zero,
+ be chatty about it. */
+
+static void
+extended_remote_attach_1 (struct target_ops *target, char *args, int from_tty)
+{
+ struct remote_state *rs = get_remote_state ();
+ int pid;
+ char *dummy;
+ char *wait_status = NULL;
+
+ if (!args)
+ error_no_arg (_("process-id to attach"));
+
+ dummy = args;
+ pid = strtol (args, &dummy, 0);
+ /* Some targets don't set errno on errors, grrr! */
+ if (pid == 0 && args == dummy)
+ error (_("Illegal process-id: %s."), args);
+
+ if (remote_protocol_packets[PACKET_vAttach].support == PACKET_DISABLE)
+ error (_("This target does not support attaching to a process"));
+
+ sprintf (rs->buf, "vAttach;%x", pid);
+ putpkt (rs->buf);
+ getpkt (&rs->buf, &rs->buf_size, 0);
+
+ if (packet_ok (rs->buf, &remote_protocol_packets[PACKET_vAttach]) == PACKET_OK)
+ {
+ if (from_tty)
+ printf_unfiltered (_("Attached to %s\n"),
+ target_pid_to_str (pid_to_ptid (pid)));
+
+ /* Save the reply for later. */
+ wait_status = alloca (strlen (rs->buf) + 1);
+ strcpy (wait_status, rs->buf);
+ }
+ else if (remote_protocol_packets[PACKET_vAttach].support == PACKET_DISABLE)
+ error (_("This target does not support attaching to a process"));
+ else
+ error (_("Attaching to %s failed"),
+ target_pid_to_str (pid_to_ptid (pid)));
+
+ target_mark_running (target);
+ inferior_ptid = pid_to_ptid (pid);
+
+ /* Now, if we have thread information, update inferior_ptid. */
+ inferior_ptid = remote_current_thread (inferior_ptid);
+
+ /* 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 ();
+
+ /* Use the previously fetched status. */
+ gdb_assert (wait_status != NULL);
+ strcpy (rs->buf, wait_status);
+ rs->cached_wait_status = 1;
+}
+
+static void
+extended_remote_attach (char *args, int from_tty)
+{
+ extended_remote_attach_1 (&extended_remote_ops, args, from_tty);
+}
+
/* Convert hex digit A to a number. */
static int
/* 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's
- PID is -1, then all threads are resumed; the thread to be stepped and/or
- signalled is given in the global INFERIOR_PTID. This function returns
- non-zero iff it resumes the inferior.
+ resumed thread should be single-stepped and/or signalled. If PTID
+ equals minus_one_ptid, then all threads are resumed; the thread to
+ be stepped and/or signalled is given in the global INFERIOR_PTID.
+ This function returns non-zero iff it resumes the inferior.
This function issues a strict subset of all possible vCont commands at the
moment. */
remote_vcont_resume (ptid_t ptid, int step, enum target_signal siggnal)
{
struct remote_state *rs = get_remote_state ();
- int pid = PIDGET (ptid);
- char *buf = NULL, *outbuf;
+ char *outbuf;
struct cleanup *old_cleanup;
if (remote_protocol_packets[PACKET_vCont].support == PACKET_SUPPORT_UNKNOWN)
about overflowing BUF. Should there be a generic
"multi-part-packet" packet? */
- if (PIDGET (inferior_ptid) == MAGIC_NULL_PID)
+ 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 PID numbers the inferior will understand. Make sure
- to only send forms that do not specify a PID. */
+ /* 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)
outbuf = xstrprintf ("vCont;S%02x", siggnal);
else if (step)
else
outbuf = xstrprintf ("vCont;c");
}
- else if (pid == -1)
+ 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,
- PIDGET (inferior_ptid));
+ outbuf = xstrprintf ("vCont;S%02x:%x;c", siggnal, tid);
else if (step)
- outbuf = xstrprintf ("vCont;s:%x;c", PIDGET (inferior_ptid));
+ outbuf = xstrprintf ("vCont;s:%x;c", tid);
else if (siggnal != TARGET_SIGNAL_0)
- outbuf = xstrprintf ("vCont;C%02x:%x;c", siggnal,
- PIDGET (inferior_ptid));
+ outbuf = xstrprintf ("vCont;C%02x:%x;c", siggnal, tid);
else
outbuf = xstrprintf ("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, pid);
+ outbuf = xstrprintf ("vCont;S%02x:%x", siggnal, tid);
else if (step)
- outbuf = xstrprintf ("vCont;s:%x", pid);
+ outbuf = xstrprintf ("vCont;s:%x", tid);
else if (siggnal != TARGET_SIGNAL_0)
- outbuf = xstrprintf ("vCont;C%02x:%x", siggnal, pid);
+ outbuf = xstrprintf ("vCont;C%02x:%x", siggnal, tid);
else
- outbuf = xstrprintf ("vCont;c:%x", pid);
+ outbuf = xstrprintf ("vCont;c:%x", tid);
}
gdb_assert (outbuf && strlen (outbuf) < get_remote_packet_size ());
{
struct remote_state *rs = get_remote_state ();
char *buf;
- int pid = PIDGET (ptid);
last_sent_signal = siggnal;
last_sent_step = step;
- /* A hook for when we need to do something at the last moment before
- resumption. */
- if (deprecated_target_resume_hook)
- (*deprecated_target_resume_hook) ();
-
/* Update the inferior on signals to silently pass, if they've changed. */
remote_pass_signals ();
/* The vCont packet doesn't need to specify threads via Hc. */
if (remote_vcont_resume (ptid, step, siggnal))
- return;
+ goto done;
- /* All other supported resume packets do use Hc, so call set_thread. */
- if (pid == -1)
- set_thread (0, 0); /* Run any thread. */
+ /* All other supported resume packets do use Hc, so set the continue
+ thread. */
+ if (ptid_equal (ptid, minus_one_ptid))
+ set_continue_thread (any_thread_ptid);
else
- set_thread (pid, 0); /* Run this thread. */
+ set_continue_thread (ptid);
buf = rs->buf;
if (siggnal != TARGET_SIGNAL_0)
strcpy (buf, step ? "s" : "c");
putpkt (buf);
-}
-
-/* Same as remote_resume, but with async support. */
-static void
-remote_async_resume (ptid_t ptid, int step, enum target_signal siggnal)
-{
- remote_resume (ptid, step, siggnal);
+ done:
/* We are about to start executing the inferior, let's register it
with the event loop. NOTE: this is the one place where all the
execution commands end up. We could alternatively do this in each
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;
}
\f
static void
initialize_sigint_signal_handler (void)
{
- sigint_remote_token =
- create_async_signal_handler (async_remote_interrupt, NULL);
signal (SIGINT, handle_remote_sigint);
}
handle_remote_sigint (int sig)
{
signal (sig, handle_remote_sigint_twice);
- sigint_remote_twice_token =
- create_async_signal_handler (async_remote_interrupt_twice, NULL);
mark_async_signal_handler_wrapper (sigint_remote_token);
}
static void
handle_remote_sigint_twice (int sig)
{
- signal (sig, handle_sigint);
- sigint_remote_twice_token =
- create_async_signal_handler (inferior_event_handler_wrapper, NULL);
+ signal (sig, handle_remote_sigint);
mark_async_signal_handler_wrapper (sigint_remote_twice_token);
}
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
{
if (remote_debug)
fprintf_unfiltered (gdb_stdlog, "remote_interrupt_twice called\n");
- /* Do something only if the target was not killed by the previous
- cntl-C. */
- if (target_executing)
- {
- interrupt_query ();
- signal (SIGINT, handle_remote_sigint);
- }
+
+ interrupt_query ();
}
/* Reinstall the usual SIGINT handlers, after the target has
cleanup_sigint_signal_handler (void *dummy)
{
signal (SIGINT, handle_sigint);
- if (sigint_remote_twice_token)
- delete_async_signal_handler (&sigint_remote_twice_token);
- if (sigint_remote_token)
- delete_async_signal_handler (&sigint_remote_token);
}
/* Send ^C to target to halt it. Target will respond, and send us a
/* If this doesn't work, try more severe steps. */
signal (signo, remote_interrupt_twice);
- if (remote_debug)
- fprintf_unfiltered (gdb_stdlog, "remote_interrupt called\n");
-
- target_stop ();
+ gdb_call_async_signal_handler (sigint_remote_token, 1);
}
/* The user typed ^C twice. */
remote_interrupt_twice (int signo)
{
signal (signo, ofunc);
- interrupt_query ();
+ gdb_call_async_signal_handler (sigint_remote_twice_token, 1);
signal (signo, remote_interrupt);
}
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)
Give up (and stop debugging it)? "))
{
target_mourn_inferior ();
+ signal (SIGINT, handle_sigint);
deprecated_throw_reason (RETURN_QUIT);
}
is required. */
static void
-remote_async_terminal_inferior (void)
+remote_terminal_inferior (void)
{
+ if (!target_async_permitted)
+ /* Nothing to do. */
+ return;
+
/* FIXME: cagney/1999-09-27: Shouldn't need to test for
sync_execution here. This function should only be called when
GDB is resuming the inferior in the forground. A background
}
static void
-remote_async_terminal_ours (void)
+remote_terminal_ours (void)
{
- /* See FIXME in remote_async_terminal_inferior. */
+ if (!target_async_permitted)
+ /* Nothing to do. */
+ return;
+
+ /* See FIXME in remote_terminal_inferior. */
if (!sync_execution)
return;
- /* See FIXME in remote_async_terminal_inferior. */
+ /* See FIXME in remote_terminal_inferior. */
if (remote_async_terminal_ours_p)
return;
cleanup_sigint_signal_handler (NULL);
remote_async_terminal_ours_p = 1;
}
-/* If nonzero, ignore the next kill. */
-
-int kill_kludge;
-
void
remote_console_output (char *msg)
{
}
/* Wait until the remote machine stops, then return,
- storing status in STATUS just as `wait' would.
- Returns "pid", which in the case of a multi-threaded
- remote OS, is the thread-id. */
+ storing status in STATUS just as `wait' would. */
static ptid_t
remote_wait (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;
ULONGEST addr;
int solibs_changed = 0;
{
char *buf, *p;
- ofunc = signal (SIGINT, remote_interrupt);
- getpkt (&rs->buf, &rs->buf_size, 1);
- signal (SIGINT, ofunc);
+ if (rs->cached_wait_status)
+ /* Use the cached wait status, but only once. */
+ rs->cached_wait_status = 0;
+ else
+ {
+ 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)
+ {
+ 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);
+ }
buf = rs->buf;
- /* This is a hook for when we need to do something (perhaps the
- collection of trace data) every time the target stops. */
- if (deprecated_target_wait_loop_hook)
- (*deprecated_target_wait_loop_hook) ();
-
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);
- continue;
+ 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;
int fieldsize;
LONGEST pnum = 0;
- /* 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 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 this packet is an awatch packet, don't parse the
'a' as a register number. */
if (strncmp (p, "thread", p1 - p) == 0)
{
p_temp = unpack_varlen_hex (++p1, &thread_num);
- record_currthread (thread_num);
p = p_temp;
}
else if ((strncmp (p, "watch", p1 - p) == 0)
struct packet_reg *reg = packet_reg_from_pnum (rsa, pnum);
p = p1;
- if (*p++ != ':')
+ if (*p != ':')
error (_("Malformed packet(b) (missing colon): %s\n\
Packet: '%s'\n"),
p, buf);
+ ++p;
if (reg == NULL)
error (_("Remote sent bad register number %s: %s\n\
phex_nz (pnum, 0), p, buf);
fieldsize = hex2bin (p, regs,
- register_size (current_gdbarch,
+ register_size (target_gdbarch,
reg->regnum));
p += 2 * fieldsize;
- if (fieldsize < register_size (current_gdbarch,
+ 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++ != ';')
+ if (*p != ';')
error (_("Remote register badly formatted: %s\nhere: %s"),
buf, p);
+ ++p;
}
}
/* fall through */
status->value.sig = (enum target_signal)
(((fromhex (buf[1])) << 4) + (fromhex (buf[2])));
}
-
- if (buf[3] == 'p')
- {
- thread_num = strtol ((const char *) &buf[4], NULL, 16);
- record_currthread (thread_num);
- }
goto got_status;
case 'W': /* Target exited. */
{
status->kind = TARGET_WAITKIND_SIGNALLED;
status->value.sig = (enum target_signal)
(((fromhex (buf[1])) << 4) + (fromhex (buf[2])));
- kill_kludge = 1;
goto got_status;
case 'O': /* Console output. */
remote_console_output (buf + 1);
- continue;
+ 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)
{
got_status:
if (thread_num != -1)
{
- return pid_to_ptid (thread_num);
+ ptid_t ptid;
+ ptid = ptid_build (ptid_get_pid (inferior_ptid), 0, thread_num);
+ record_currthread (ptid);
+ return ptid;
}
+
return inferior_ptid;
}
-/* Async version of remote_wait. */
-static ptid_t
-remote_async_wait (ptid_t ptid, struct target_waitstatus *status)
+/* Fetch a single register using a 'p' packet. */
+
+static int
+fetch_register_using_p (struct regcache *regcache, struct packet_reg *reg)
{
struct remote_state *rs = get_remote_state ();
- struct remote_arch_state *rsa = get_remote_arch_state ();
- ULONGEST thread_num = -1;
- ULONGEST addr;
- int solibs_changed = 0;
+ char *buf, *p;
+ char regp[MAX_REGISTER_SIZE];
+ int i;
- status->kind = TARGET_WAITKIND_EXITED;
- status->value.integer = 0;
+ if (remote_protocol_packets[PACKET_p].support == PACKET_DISABLE)
+ return 0;
- remote_stopped_by_watchpoint_p = 0;
+ if (reg->pnum == -1)
+ return 0;
- while (1)
- {
- char *buf, *p;
+ p = rs->buf;
+ *p++ = 'p';
+ p += hexnumstr (p, reg->pnum);
+ *p++ = '\0';
+ remote_send (&rs->buf, &rs->buf_size);
- if (!target_is_async_p ())
- ofunc = signal (SIGINT, remote_interrupt);
- /* 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;
+ switch (packet_ok (buf, &remote_protocol_packets[PACKET_p]))
+ {
+ case PACKET_OK:
+ break;
+ case PACKET_UNKNOWN:
+ return 0;
+ case PACKET_ERROR:
+ error (_("Could not fetch register \"%s\""),
+ gdbarch_register_name (get_regcache_arch (regcache), reg->regnum));
+ }
- /* This is a hook for when we need to do something (perhaps the
- collection of trace data) every time the target stops. */
- if (deprecated_target_wait_loop_hook)
- (*deprecated_target_wait_loop_hook) ();
-
- switch (buf[0])
- {
- case 'E': /* Error of some sort. */
- warning (_("Remote failure reply: %s"), buf);
- continue;
- case 'F': /* File-I/O request. */
- remote_fileio_request (buf);
- continue;
- case 'T': /* Status with PC, SP, FP, ... */
- {
- gdb_byte regs[MAX_REGISTER_SIZE];
-
- /* 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;
- long pnum = 0;
-
- /* 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 this packet is an awatch packet, don't parse the 'a'
- as a register number. */
-
- if (strncmp (p, "awatch", strlen("awatch")) != 0)
- {
- /* Read the 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)
- {
- p_temp = unpack_varlen_hex (++p1, &thread_num);
- record_currthread (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;
- }
- }
-
- else
- {
- struct packet_reg *reg = packet_reg_from_pnum (rsa, pnum);
- p = p1;
- if (*p++ != ':')
- error (_("Malformed packet(b) (missing colon): %s\n\
-Packet: '%s'\n"),
- p, buf);
-
- if (reg == NULL)
- error (_("Remote sent bad register number %ld: %s\n\
-Packet: '%s'\n"),
- pnum, 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);
- }
- }
- /* 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])));
- }
-
- if (buf[3] == 'p')
- {
- thread_num = strtol ((const char *) &buf[4], NULL, 16);
- record_currthread (thread_num);
- }
- goto got_status;
- case 'W': /* Target exited. */
- {
- /* The remote process exited. */
- status->kind = TARGET_WAITKIND_EXITED;
- status->value.integer = (fromhex (buf[1]) << 4) + fromhex (buf[2]);
- goto got_status;
- }
- case 'X':
- status->kind = TARGET_WAITKIND_SIGNALLED;
- status->value.sig = (enum target_signal)
- (((fromhex (buf[1])) << 4) + (fromhex (buf[2])));
- kill_kludge = 1;
-
- goto got_status;
- case 'O': /* Console output. */
- remote_console_output (buf + 1);
- /* 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;
- 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;
- }
- }
-got_status:
- if (thread_num != -1)
- {
- return pid_to_ptid (thread_num);
- }
- return inferior_ptid;
-}
-
-/* Fetch a single register using a 'p' packet. */
-
-static int
-fetch_register_using_p (struct regcache *regcache, struct packet_reg *reg)
-{
- struct remote_state *rs = get_remote_state ();
- char *buf, *p;
- char regp[MAX_REGISTER_SIZE];
- int i;
-
- if (remote_protocol_packets[PACKET_p].support == PACKET_DISABLE)
- return 0;
-
- if (reg->pnum == -1)
- return 0;
-
- p = rs->buf;
- *p++ = 'p';
- p += hexnumstr (p, reg->pnum);
- *p++ = '\0';
- remote_send (&rs->buf, &rs->buf_size);
-
- buf = rs->buf;
-
- switch (packet_ok (buf, &remote_protocol_packets[PACKET_p]))
- {
- case PACKET_OK:
- break;
- case PACKET_UNKNOWN:
- return 0;
- case PACKET_ERROR:
- error (_("Could not fetch register \"%s\""),
- gdbarch_register_name (current_gdbarch, reg->regnum));
- }
-
- /* If this register is unfetchable, tell the regcache. */
- if (buf[0] == 'x')
- {
- regcache_raw_supply (regcache, reg->regnum, NULL);
- return 1;
- }
+ /* If this register is unfetchable, tell the regcache. */
+ if (buf[0] == 'x')
+ {
+ regcache_raw_supply (regcache, reg->regnum, NULL);
+ return 1;
+ }
/* Otherwise, parse and supply the value. */
p = buf;
static void
process_g_packet (struct regcache *regcache)
{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
struct remote_state *rs = get_remote_state ();
struct remote_arch_state *rsa = get_remote_arch_state ();
int i, buf_len;
{
rsa->sizeof_g_packet = buf_len / 2;
- for (i = 0; i < gdbarch_num_regs (current_gdbarch); i++)
+ for (i = 0; i < gdbarch_num_regs (gdbarch); i++)
{
if (rsa->regs[i].pnum == -1)
continue;
{
int i;
- for (i = 0; i < gdbarch_num_regs (current_gdbarch); i++)
+ for (i = 0; i < gdbarch_num_regs (gdbarch); i++)
{
struct packet_reg *r = &rsa->regs[i];
if (r->in_g_packet)
struct remote_arch_state *rsa = get_remote_arch_state ();
int i;
- set_thread (PIDGET (inferior_ptid), 1);
+ set_general_thread (inferior_ptid);
if (regnum >= 0)
{
fetch_registers_using_g (regcache);
- for (i = 0; i < gdbarch_num_regs (current_gdbarch); i++)
+ for (i = 0; i < gdbarch_num_regs (get_regcache_arch (regcache)); i++)
if (!rsa->regs[i].in_g_packet)
if (!fetch_register_using_p (regcache, &rsa->regs[i]))
{
case PACKET_DISABLE:
case PACKET_SUPPORT_UNKNOWN:
/* Make sure all the necessary registers are cached. */
- for (i = 0; i < gdbarch_num_regs (current_gdbarch); i++)
+ for (i = 0; i < gdbarch_num_regs (get_regcache_arch (regcache)); i++)
if (rsa->regs[i].in_g_packet)
regcache_raw_read (regcache, rsa->regs[i].regnum, buf);
break;
static int
store_register_using_P (const struct regcache *regcache, struct packet_reg *reg)
{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
struct remote_state *rs = get_remote_state ();
struct remote_arch_state *rsa = get_remote_arch_state ();
/* Try storing a single register. */
xsnprintf (buf, get_remote_packet_size (), "P%s=", phex_nz (reg->pnum, 0));
p = buf + strlen (buf);
regcache_raw_collect (regcache, reg->regnum, regp);
- bin2hex (regp, p, register_size (current_gdbarch, reg->regnum));
+ bin2hex (regp, p, register_size (gdbarch, reg->regnum));
remote_send (&rs->buf, &rs->buf_size);
switch (packet_ok (rs->buf, &remote_protocol_packets[PACKET_P]))
return 1;
case PACKET_ERROR:
error (_("Could not write register \"%s\""),
- gdbarch_register_name (current_gdbarch, reg->regnum));
+ gdbarch_register_name (gdbarch, reg->regnum));
case PACKET_UNKNOWN:
return 0;
default:
int i;
regs = alloca (rsa->sizeof_g_packet);
memset (regs, 0, rsa->sizeof_g_packet);
- for (i = 0; i < gdbarch_num_regs (current_gdbarch); i++)
+ for (i = 0; i < gdbarch_num_regs (get_regcache_arch (regcache)); i++)
{
struct packet_reg *r = &rsa->regs[i];
if (r->in_g_packet)
struct remote_arch_state *rsa = get_remote_arch_state ();
int i;
- set_thread (PIDGET (inferior_ptid), 1);
+ set_general_thread (inferior_ptid);
if (regnum >= 0)
{
store_registers_using_G (regcache);
- for (i = 0; i < gdbarch_num_regs (current_gdbarch); i++)
+ for (i = 0; i < gdbarch_num_regs (get_regcache_arch (regcache)); i++)
if (!rsa->regs[i].in_g_packet)
if (!store_register_using_P (regcache, &rsa->regs[i]))
/* See above for why we do not issue an error here. */
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))
static int
putpkt_binary (char *buf, int cnt)
{
+ struct remote_state *rs = get_remote_state ();
int i;
unsigned char csum = 0;
char *buf2 = alloca (cnt + 6);
int tcount = 0;
char *p;
+ /* We're sending out a new packet. Make sure we don't look at a
+ stale cached response. */
+ rs->cached_wait_status = 0;
+
/* Copy the packet into buffer BUF2, encapsulating it
and giving it a checksum. */
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;
static int
getpkt_sane (char **buf, long *sizeof_buf, int forever)
{
+ struct remote_state *rs = get_remote_state ();
int c;
int tries;
int timeout;
int val;
+ /* We're reading a new response. Make sure we don't look at a
+ previously cached response. */
+ rs->cached_wait_status = 0;
+
strcpy (*buf, "timeout");
if (forever)
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)
-{
- /* For some mysterious reason, wait_for_inferior calls kill instead of
- mourn after it gets TARGET_WAITKIND_SIGNALLED. Work around it. */
- if (kill_kludge)
- {
- kill_kludge = 0;
- target_mourn_inferior ();
- return;
- }
-
- /* 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);
-
- /* 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. */
- target_mourn_inferior ();
-}
-
-/* Async version of remote_kill. */
-static void
-remote_async_kill (void)
{
/* Unregister the file descriptor from the event loop. */
if (target_is_async_p ())
serial_async (remote_desc, NULL, 0);
- /* For some mysterious reason, wait_for_inferior calls kill instead of
- mourn after it gets TARGET_WAITKIND_SIGNALLED. Work around it. */
- if (kill_kludge)
- {
- kill_kludge = 0;
- target_mourn_inferior ();
- return;
- }
-
/* 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);
remote_mourn_1 (&remote_ops);
}
-static void
-remote_async_mourn (void)
-{
- remote_mourn_1 (&remote_async_ops);
-}
-
-static void
-extended_remote_mourn (void)
-{
- /* We do _not_ want to mourn the target like this; this will
- remove the extended remote target from the target stack,
- and the next time the user says "run" it'll fail.
-
- FIXME: What is the right thing to do here? */
-#if 0
- remote_mourn_1 (&extended_remote_ops);
-#endif
-}
-
/* Worker function for remote_mourn. */
static void
remote_mourn_1 (struct target_ops *target)
generic_mourn_inferior ();
}
-/* In the extended protocol we want to be able to do things like
- "run" and have them basically work as expected. So we need
- a special create_inferior function.
-
- FIXME: One day add support for changing the exec file
- we're debugging, arguments and an environment. */
-
static void
-extended_remote_create_inferior (char *exec_file, char *args,
- char **env, int from_tty)
+extended_remote_mourn_1 (struct target_ops *target)
{
- /* Rip out the breakpoints; we'll reinsert them after restarting
- the remote server. */
- remove_breakpoints ();
-
- /* Now restart the remote server. */
- extended_remote_restart ();
+ struct remote_state *rs = get_remote_state ();
- /* NOTE: We don't need to recheck for a target description here; but
- if we gain the ability to switch the remote executable we may
- need to, if for instance we are running a process which requested
- different emulated hardware from the operating system. A
- concrete example of this is ARM GNU/Linux, where some binaries
- will have a legacy FPA coprocessor emulated and others may have
- access to a hardware VFP unit. */
+ /* Unlike "target remote", we do not want to unpush the target; then
+ the next time the user says "run", we won't be connected. */
- /* Now put the breakpoints back in. This way we're safe if the
- restart function works via a unix fork on the remote side. */
- insert_breakpoints ();
+ /* Call common code to mark the inferior as not running. */
+ generic_mourn_inferior ();
- /* Clean up from the last time we were running. */
- clear_proceed_status ();
-}
+ /* Check whether the target is running now - some remote stubs
+ automatically restart after kill. */
+ putpkt ("?");
+ getpkt (&rs->buf, &rs->buf_size, 0);
-/* Async version of extended_remote_create_inferior. */
-static void
-extended_remote_async_create_inferior (char *exec_file, char *args,
- char **env, int from_tty)
-{
- /* Rip out the breakpoints; we'll reinsert them after restarting
- the remote server. */
- remove_breakpoints ();
+ 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 = remote_current_thread (magic_null_ptid);
+ add_thread_silent (inferior_ptid);
+ }
+ else
+ {
+ /* Mark this (still pushed) target as not executable until we
+ restart it. */
+ target_mark_exited (target);
+ }
+}
+
+static void
+extended_remote_mourn (void)
+{
+ extended_remote_mourn_1 (&extended_remote_ops);
+}
+
+static int
+extended_remote_run (char *args)
+{
+ struct remote_state *rs = get_remote_state ();
+ char *p;
+ int len;
+
+ /* If the user has disabled vRun support, or we have detected that
+ support is not available, do not try it. */
+ if (remote_protocol_packets[PACKET_vRun].support == PACKET_DISABLE)
+ return -1;
+
+ strcpy (rs->buf, "vRun;");
+ len = strlen (rs->buf);
+
+ if (strlen (remote_exec_file) * 2 + len >= get_remote_packet_size ())
+ error (_("Remote file name too long for run packet"));
+ len += 2 * bin2hex ((gdb_byte *) remote_exec_file, rs->buf + len, 0);
+
+ if (*args)
+ {
+ struct cleanup *back_to;
+ int i;
+ char **argv;
+
+ argv = buildargv (args);
+ back_to = make_cleanup ((void (*) (void *)) freeargv, argv);
+ for (i = 0; argv[i] != NULL; i++)
+ {
+ if (strlen (argv[i]) * 2 + 1 + len >= get_remote_packet_size ())
+ error (_("Argument list too long for run packet"));
+ rs->buf[len++] = ';';
+ len += 2 * bin2hex ((gdb_byte *) argv[i], rs->buf + len, 0);
+ }
+ do_cleanups (back_to);
+ }
+ rs->buf[len++] = '\0';
+
+ putpkt (rs->buf);
+ getpkt (&rs->buf, &rs->buf_size, 0);
+
+ if (packet_ok (rs->buf, &remote_protocol_packets[PACKET_vRun]) == PACKET_OK)
+ {
+ /* We have a wait response; we don't need it, though. All is well. */
+ return 0;
+ }
+ else if (remote_protocol_packets[PACKET_vRun].support == PACKET_DISABLE)
+ /* It wasn't disabled before, but it is now. */
+ return -1;
+ else
+ {
+ if (remote_exec_file[0] == '\0')
+ error (_("Running the default executable on the remote target failed; "
+ "try \"set remote exec-file\"?"));
+ else
+ error (_("Running \"%s\" on the remote target failed"),
+ remote_exec_file);
+ }
+}
+
+/* In the extended protocol we want to be able to do things like
+ "run" and have them basically work as expected. So we need
+ a special create_inferior function. We support changing the
+ executable file and the command line arguments, but not the
+ environment. */
+
+static void
+extended_remote_create_inferior_1 (char *exec_file, char *args,
+ char **env, int from_tty)
+{
/* If running asynchronously, register the target file descriptor
with the event loop. */
if (target_can_async_p ())
target_async (inferior_event_handler, 0);
/* Now restart the remote server. */
- extended_remote_restart ();
+ if (extended_remote_run (args) == -1)
+ {
+ /* vRun was not supported. Fail if we need it to do what the
+ user requested. */
+ if (remote_exec_file[0])
+ error (_("Remote target does not support \"set remote exec-file\""));
+ if (args[0])
+ error (_("Remote target does not support \"set args\" or run <ARGS>"));
+
+ /* Fall back to "R". */
+ extended_remote_restart ();
+ }
- /* NOTE: We don't need to recheck for a target description here; but
- if we gain the ability to switch the remote executable we may
- need to, if for instance we are running a process which requested
- different emulated hardware from the operating system. A
- concrete example of this is ARM GNU/Linux, where some binaries
- will have a legacy FPA coprocessor emulated and others may have
- access to a hardware VFP unit. */
+ /* Clean up from the last time we ran, before we mark the target
+ running again. This will mark breakpoints uninserted, and
+ get_offsets may insert breakpoints. */
+ init_thread_list ();
+ init_wait_for_inferior ();
- /* Now put the breakpoints back in. This way we're safe if the
- restart function works via a unix fork on the remote side. */
- insert_breakpoints ();
+ /* Now mark the inferior as running before we do anything else. */
+ attach_flag = 0;
+ inferior_ptid = magic_null_ptid;
- /* Clean up from the last time we were running. */
- clear_proceed_status ();
+ add_thread_silent (inferior_ptid);
+
+ target_mark_running (&extended_remote_ops);
+
+ /* Get updated offsets, if the stub uses qOffsets. */
+ get_offsets ();
+}
+
+static void
+extended_remote_create_inferior (char *exec_file, char *args,
+ char **env, int from_tty)
+{
+ extended_remote_create_inferior_1 (exec_file, args, env, from_tty);
}
\f
static int
remote_insert_breakpoint (struct bp_target_info *bp_tgt)
{
- CORE_ADDR addr = bp_tgt->placed_address;
- struct remote_state *rs = get_remote_state ();
-
/* Try the "Z" s/w breakpoint packet if it is not already disabled.
If it succeeds, then set the support to PACKET_ENABLE. If it
fails, and the user has explicitly requested the Z support then
if (remote_protocol_packets[PACKET_Z0].support != PACKET_DISABLE)
{
- char *p = rs->buf;
+ CORE_ADDR addr = bp_tgt->placed_address;
+ struct remote_state *rs;
+ char *p;
+ int bpsize;
+
+ gdbarch_breakpoint_from_pc (target_gdbarch, &addr, &bpsize);
+
+ rs = get_remote_state ();
+ p = rs->buf;
*(p++) = 'Z';
*(p++) = '0';
*(p++) = ',';
- gdbarch_breakpoint_from_pc
- (current_gdbarch, &bp_tgt->placed_address, &bp_tgt->placed_size);
- addr = (ULONGEST) remote_address_masked (bp_tgt->placed_address);
+ addr = (ULONGEST) remote_address_masked (addr);
p += hexnumstr (p, addr);
- sprintf (p, ",%d", bp_tgt->placed_size);
+ sprintf (p, ",%d", bpsize);
putpkt (rs->buf);
getpkt (&rs->buf, &rs->buf_size, 0);
case PACKET_ERROR:
return -1;
case PACKET_OK:
+ bp_tgt->placed_address = addr;
+ bp_tgt->placed_size = bpsize;
return 0;
case PACKET_UNKNOWN:
break;
remote_insert_hw_breakpoint (struct bp_target_info *bp_tgt)
{
CORE_ADDR addr;
- struct remote_state *rs = get_remote_state ();
- char *p = rs->buf;
+ struct remote_state *rs;
+ char *p;
/* The length field should be set to the size of a breakpoint
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;
+ rs = get_remote_state ();
+ p = rs->buf;
+
*(p++) = 'Z';
*(p++) = '1';
*(p++) = ',';
int xfered;
errno = 0;
+ /* If the remote target is connected but not running, we should
+ pass this request down to a lower stratum (e.g. the executable
+ file). */
+ if (!target_has_execution)
+ return 0;
+
if (writebuf != NULL)
xfered = remote_write_bytes (offset, writebuf, len);
else
return strlen ((char *) readbuf);
}
+static int
+remote_search_memory (struct target_ops* ops,
+ CORE_ADDR start_addr, ULONGEST search_space_len,
+ const gdb_byte *pattern, ULONGEST pattern_len,
+ CORE_ADDR *found_addrp)
+{
+ struct remote_state *rs = get_remote_state ();
+ int max_size = get_memory_write_packet_size ();
+ struct packet_config *packet =
+ &remote_protocol_packets[PACKET_qSearch_memory];
+ /* number of packet bytes used to encode the pattern,
+ this could be more than PATTERN_LEN due to escape characters */
+ int escaped_pattern_len;
+ /* amount of pattern that was encodable in the packet */
+ int used_pattern_len;
+ int i;
+ int found;
+ ULONGEST found_addr;
+
+ /* Don't go to the target if we don't have to.
+ This is done before checking packet->support to avoid the possibility that
+ a success for this edge case means the facility works in general. */
+ if (pattern_len > search_space_len)
+ return 0;
+ if (pattern_len == 0)
+ {
+ *found_addrp = start_addr;
+ return 1;
+ }
+
+ /* If we already know the packet isn't supported, fall back to the simple
+ way of searching memory. */
+
+ if (packet->support == PACKET_DISABLE)
+ {
+ /* Target doesn't provided special support, fall back and use the
+ standard support (copy memory and do the search here). */
+ return simple_search_memory (ops, start_addr, search_space_len,
+ pattern, pattern_len, found_addrp);
+ }
+
+ /* Insert header. */
+ i = snprintf (rs->buf, max_size,
+ "qSearch:memory:%s;%s;",
+ paddr_nz (start_addr),
+ phex_nz (search_space_len, sizeof (search_space_len)));
+ max_size -= (i + 1);
+
+ /* Escape as much data as fits into rs->buf. */
+ escaped_pattern_len =
+ remote_escape_output (pattern, pattern_len, (rs->buf + i),
+ &used_pattern_len, max_size);
+
+ /* Bail if the pattern is too large. */
+ if (used_pattern_len != pattern_len)
+ error ("Pattern is too large to transmit to remote target.");
+
+ if (putpkt_binary (rs->buf, i + escaped_pattern_len) < 0
+ || getpkt_sane (&rs->buf, &rs->buf_size, 0) < 0
+ || packet_ok (rs->buf, packet) != PACKET_OK)
+ {
+ /* The request may not have worked because the command is not
+ supported. If so, fall back to the simple way. */
+ if (packet->support == PACKET_DISABLE)
+ {
+ return simple_search_memory (ops, start_addr, search_space_len,
+ pattern, pattern_len, found_addrp);
+ }
+ return -1;
+ }
+
+ if (rs->buf[0] == '0')
+ found = 0;
+ else if (rs->buf[0] == '1')
+ {
+ found = 1;
+ if (rs->buf[1] != ',')
+ error (_("Unknown qSearch:memory reply: %s"), rs->buf);
+ unpack_varlen_hex (rs->buf + 2, &found_addr);
+ *found_addrp = found_addr;
+ }
+ else
+ error (_("Unknown qSearch:memory reply: %s"), rs->buf);
+
+ return found;
+}
+
static void
remote_rcmd (char *command,
struct ui_file *outbuf)
int sample_thread = SAMPLE_THREAD;
printf_filtered (_("Remote threadset test\n"));
- set_thread (sample_thread, 1);
+ set_general_thread (sample_thread);
}
threadalive_test (char *cmd, int tty)
{
int sample_thread = SAMPLE_THREAD;
+ int pid = ptid_get_pid (inferior_ptid);
+ ptid_t ptid = ptid_build (pid, 0, sample_thread);
- if (remote_thread_alive (pid_to_ptid (sample_thread)))
+ if (remote_thread_alive (ptid))
printf_filtered ("PASS: Thread alive test\n");
else
printf_filtered ("FAIL: Thread alive test\n");
static char *
remote_pid_to_str (ptid_t ptid)
{
- static char buf[32];
+ static char buf[64];
- xsnprintf (buf, sizeof buf, "Thread %d", ptid_get_pid (ptid));
- return buf;
+ if (ptid_equal (magic_null_ptid, ptid))
+ {
+ xsnprintf (buf, sizeof buf, "Thread <main>");
+ return buf;
+ }
+ else if (ptid_get_tid (ptid) != 0)
+ {
+ xsnprintf (buf, sizeof buf, "Thread %ld",
+ ptid_get_tid (ptid));
+ return buf;
+ }
+
+ return normal_pid_to_str (ptid);
}
/* Get the address of the thread local variable in OBJFILE which is
strcpy (p, "qGetTLSAddr:");
p += strlen (p);
- p += hexnumstr (p, PIDGET (ptid));
+ p += hexnumstr (p, ptid_get_tid (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))
{
return NULL;
}
+/* Remote file transfer support. This is host-initiated I/O, not
+ target-initiated; for target-initiated, see remote-fileio.c. */
+
+/* If *LEFT is at least the length of STRING, copy STRING to
+ *BUFFER, update *BUFFER to point to the new end of the buffer, and
+ decrease *LEFT. Otherwise raise an error. */
+
+static void
+remote_buffer_add_string (char **buffer, int *left, char *string)
+{
+ int len = strlen (string);
+
+ if (len > *left)
+ error (_("Packet too long for target."));
+
+ memcpy (*buffer, string, len);
+ *buffer += len;
+ *left -= len;
+
+ /* NUL-terminate the buffer as a convenience, if there is
+ room. */
+ if (*left)
+ **buffer = '\0';
+}
+
+/* If *LEFT is large enough, hex encode LEN bytes from BYTES into
+ *BUFFER, update *BUFFER to point to the new end of the buffer, and
+ decrease *LEFT. Otherwise raise an error. */
+
+static void
+remote_buffer_add_bytes (char **buffer, int *left, const gdb_byte *bytes,
+ int len)
+{
+ if (2 * len > *left)
+ error (_("Packet too long for target."));
+
+ bin2hex (bytes, *buffer, len);
+ *buffer += 2 * len;
+ *left -= 2 * len;
+
+ /* NUL-terminate the buffer as a convenience, if there is
+ room. */
+ if (*left)
+ **buffer = '\0';
+}
+
+/* If *LEFT is large enough, convert VALUE to hex and add it to
+ *BUFFER, update *BUFFER to point to the new end of the buffer, and
+ decrease *LEFT. Otherwise raise an error. */
+
+static void
+remote_buffer_add_int (char **buffer, int *left, ULONGEST value)
+{
+ int len = hexnumlen (value);
+
+ if (len > *left)
+ error (_("Packet too long for target."));
+
+ hexnumstr (*buffer, value);
+ *buffer += len;
+ *left -= len;
+
+ /* NUL-terminate the buffer as a convenience, if there is
+ room. */
+ if (*left)
+ **buffer = '\0';
+}
+
+/* Parse an I/O result packet from BUFFER. Set RETCODE to the return
+ value, *REMOTE_ERRNO to the remote error number or zero if none
+ was included, and *ATTACHMENT to point to the start of the annex
+ if any. The length of the packet isn't needed here; there may
+ be NUL bytes in BUFFER, but they will be after *ATTACHMENT.
+
+ Return 0 if the packet could be parsed, -1 if it could not. If
+ -1 is returned, the other variables may not be initialized. */
+
+static int
+remote_hostio_parse_result (char *buffer, int *retcode,
+ int *remote_errno, char **attachment)
+{
+ char *p, *p2;
+
+ *remote_errno = 0;
+ *attachment = NULL;
+
+ if (buffer[0] != 'F')
+ return -1;
+
+ errno = 0;
+ *retcode = strtol (&buffer[1], &p, 16);
+ if (errno != 0 || p == &buffer[1])
+ return -1;
+
+ /* Check for ",errno". */
+ if (*p == ',')
+ {
+ errno = 0;
+ *remote_errno = strtol (p + 1, &p2, 16);
+ if (errno != 0 || p + 1 == p2)
+ return -1;
+ p = p2;
+ }
+
+ /* Check for ";attachment". If there is no attachment, the
+ packet should end here. */
+ if (*p == ';')
+ {
+ *attachment = p + 1;
+ return 0;
+ }
+ else if (*p == '\0')
+ return 0;
+ else
+ return -1;
+}
+
+/* Send a prepared I/O packet to the target and read its response.
+ The prepared packet is in the global RS->BUF before this function
+ is called, and the answer is there when we return.
+
+ COMMAND_BYTES is the length of the request to send, which may include
+ binary data. WHICH_PACKET is the packet configuration to check
+ before attempting a packet. If an error occurs, *REMOTE_ERRNO
+ is set to the error number and -1 is returned. Otherwise the value
+ returned by the function is returned.
+
+ ATTACHMENT and ATTACHMENT_LEN should be non-NULL if and only if an
+ attachment is expected; an error will be reported if there's a
+ mismatch. If one is found, *ATTACHMENT will be set to point into
+ the packet buffer and *ATTACHMENT_LEN will be set to the
+ attachment's length. */
+
+static int
+remote_hostio_send_command (int command_bytes, int which_packet,
+ int *remote_errno, char **attachment,
+ int *attachment_len)
+{
+ struct remote_state *rs = get_remote_state ();
+ int ret, bytes_read;
+ char *attachment_tmp;
+
+ if (!remote_desc
+ || remote_protocol_packets[which_packet].support == PACKET_DISABLE)
+ {
+ *remote_errno = FILEIO_ENOSYS;
+ return -1;
+ }
+
+ putpkt_binary (rs->buf, command_bytes);
+ bytes_read = getpkt_sane (&rs->buf, &rs->buf_size, 0);
+
+ /* If it timed out, something is wrong. Don't try to parse the
+ buffer. */
+ if (bytes_read < 0)
+ {
+ *remote_errno = FILEIO_EINVAL;
+ return -1;
+ }
+
+ switch (packet_ok (rs->buf, &remote_protocol_packets[which_packet]))
+ {
+ case PACKET_ERROR:
+ *remote_errno = FILEIO_EINVAL;
+ return -1;
+ case PACKET_UNKNOWN:
+ *remote_errno = FILEIO_ENOSYS;
+ return -1;
+ case PACKET_OK:
+ break;
+ }
+
+ if (remote_hostio_parse_result (rs->buf, &ret, remote_errno,
+ &attachment_tmp))
+ {
+ *remote_errno = FILEIO_EINVAL;
+ return -1;
+ }
+
+ /* Make sure we saw an attachment if and only if we expected one. */
+ if ((attachment_tmp == NULL && attachment != NULL)
+ || (attachment_tmp != NULL && attachment == NULL))
+ {
+ *remote_errno = FILEIO_EINVAL;
+ return -1;
+ }
+
+ /* If an attachment was found, it must point into the packet buffer;
+ work out how many bytes there were. */
+ if (attachment_tmp != NULL)
+ {
+ *attachment = attachment_tmp;
+ *attachment_len = bytes_read - (*attachment - rs->buf);
+ }
+
+ return ret;
+}
+
+/* Open FILENAME on the remote target, using FLAGS and MODE. Return a
+ remote file descriptor, or -1 if an error occurs (and set
+ *REMOTE_ERRNO). */
+
+static int
+remote_hostio_open (const char *filename, int flags, int mode,
+ int *remote_errno)
+{
+ struct remote_state *rs = get_remote_state ();
+ char *p = rs->buf;
+ int left = get_remote_packet_size () - 1;
+
+ remote_buffer_add_string (&p, &left, "vFile:open:");
+
+ remote_buffer_add_bytes (&p, &left, (const gdb_byte *) filename,
+ strlen (filename));
+ remote_buffer_add_string (&p, &left, ",");
+
+ remote_buffer_add_int (&p, &left, flags);
+ remote_buffer_add_string (&p, &left, ",");
+
+ remote_buffer_add_int (&p, &left, mode);
+
+ return remote_hostio_send_command (p - rs->buf, PACKET_vFile_open,
+ remote_errno, NULL, NULL);
+}
+
+/* Write up to LEN bytes from WRITE_BUF to FD on the remote target.
+ Return the number of bytes written, or -1 if an error occurs (and
+ set *REMOTE_ERRNO). */
+
+static int
+remote_hostio_pwrite (int fd, const gdb_byte *write_buf, int len,
+ ULONGEST offset, int *remote_errno)
+{
+ struct remote_state *rs = get_remote_state ();
+ char *p = rs->buf;
+ int left = get_remote_packet_size ();
+ int out_len;
+
+ remote_buffer_add_string (&p, &left, "vFile:pwrite:");
+
+ remote_buffer_add_int (&p, &left, fd);
+ remote_buffer_add_string (&p, &left, ",");
+
+ remote_buffer_add_int (&p, &left, offset);
+ remote_buffer_add_string (&p, &left, ",");
+
+ p += remote_escape_output (write_buf, len, p, &out_len,
+ get_remote_packet_size () - (p - rs->buf));
+
+ return remote_hostio_send_command (p - rs->buf, PACKET_vFile_pwrite,
+ remote_errno, NULL, NULL);
+}
+
+/* Read up to LEN bytes FD on the remote target into READ_BUF
+ Return the number of bytes read, or -1 if an error occurs (and
+ set *REMOTE_ERRNO). */
+
+static int
+remote_hostio_pread (int fd, gdb_byte *read_buf, int len,
+ ULONGEST offset, int *remote_errno)
+{
+ struct remote_state *rs = get_remote_state ();
+ char *p = rs->buf;
+ char *attachment;
+ int left = get_remote_packet_size ();
+ int ret, attachment_len;
+ int read_len;
+
+ remote_buffer_add_string (&p, &left, "vFile:pread:");
+
+ remote_buffer_add_int (&p, &left, fd);
+ remote_buffer_add_string (&p, &left, ",");
+
+ remote_buffer_add_int (&p, &left, len);
+ remote_buffer_add_string (&p, &left, ",");
+
+ remote_buffer_add_int (&p, &left, offset);
+
+ ret = remote_hostio_send_command (p - rs->buf, PACKET_vFile_pread,
+ remote_errno, &attachment,
+ &attachment_len);
+
+ if (ret < 0)
+ return ret;
+
+ read_len = remote_unescape_input (attachment, attachment_len,
+ read_buf, len);
+ if (read_len != ret)
+ error (_("Read returned %d, but %d bytes."), ret, (int) read_len);
+
+ return ret;
+}
+
+/* Close FD on the remote target. Return 0, or -1 if an error occurs
+ (and set *REMOTE_ERRNO). */
+
+static int
+remote_hostio_close (int fd, int *remote_errno)
+{
+ struct remote_state *rs = get_remote_state ();
+ char *p = rs->buf;
+ int left = get_remote_packet_size () - 1;
+
+ remote_buffer_add_string (&p, &left, "vFile:close:");
+
+ remote_buffer_add_int (&p, &left, fd);
+
+ return remote_hostio_send_command (p - rs->buf, PACKET_vFile_close,
+ remote_errno, NULL, NULL);
+}
+
+/* Unlink FILENAME on the remote target. Return 0, or -1 if an error
+ occurs (and set *REMOTE_ERRNO). */
+
+static int
+remote_hostio_unlink (const char *filename, int *remote_errno)
+{
+ struct remote_state *rs = get_remote_state ();
+ char *p = rs->buf;
+ int left = get_remote_packet_size () - 1;
+
+ remote_buffer_add_string (&p, &left, "vFile:unlink:");
+
+ remote_buffer_add_bytes (&p, &left, (const gdb_byte *) filename,
+ strlen (filename));
+
+ return remote_hostio_send_command (p - rs->buf, PACKET_vFile_unlink,
+ remote_errno, NULL, NULL);
+}
+
+static int
+remote_fileio_errno_to_host (int errnum)
+{
+ switch (errnum)
+ {
+ case FILEIO_EPERM:
+ return EPERM;
+ case FILEIO_ENOENT:
+ return ENOENT;
+ case FILEIO_EINTR:
+ return EINTR;
+ case FILEIO_EIO:
+ return EIO;
+ case FILEIO_EBADF:
+ return EBADF;
+ case FILEIO_EACCES:
+ return EACCES;
+ case FILEIO_EFAULT:
+ return EFAULT;
+ case FILEIO_EBUSY:
+ return EBUSY;
+ case FILEIO_EEXIST:
+ return EEXIST;
+ case FILEIO_ENODEV:
+ return ENODEV;
+ case FILEIO_ENOTDIR:
+ return ENOTDIR;
+ case FILEIO_EISDIR:
+ return EISDIR;
+ case FILEIO_EINVAL:
+ return EINVAL;
+ case FILEIO_ENFILE:
+ return ENFILE;
+ case FILEIO_EMFILE:
+ return EMFILE;
+ case FILEIO_EFBIG:
+ return EFBIG;
+ case FILEIO_ENOSPC:
+ return ENOSPC;
+ case FILEIO_ESPIPE:
+ return ESPIPE;
+ case FILEIO_EROFS:
+ return EROFS;
+ case FILEIO_ENOSYS:
+ return ENOSYS;
+ case FILEIO_ENAMETOOLONG:
+ return ENAMETOOLONG;
+ }
+ return -1;
+}
+
+static char *
+remote_hostio_error (int errnum)
+{
+ int host_error = remote_fileio_errno_to_host (errnum);
+
+ if (host_error == -1)
+ error (_("Unknown remote I/O error %d"), errnum);
+ else
+ error (_("Remote I/O error: %s"), safe_strerror (host_error));
+}
+
+static void
+fclose_cleanup (void *file)
+{
+ fclose (file);
+}
+
+static void
+remote_hostio_close_cleanup (void *opaque)
+{
+ int fd = *(int *) opaque;
+ int remote_errno;
+
+ 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, *close_cleanup;
+ int retcode, fd, remote_errno, bytes, io_size;
+ FILE *file;
+ gdb_byte *buffer;
+ int bytes_in_buffer;
+ int saw_eof;
+ ULONGEST offset;
+
+ if (!remote_desc)
+ error (_("command can only be used with remote target"));
+
+ file = fopen (local_file, "rb");
+ if (file == NULL)
+ perror_with_name (local_file);
+ back_to = make_cleanup (fclose_cleanup, file);
+
+ fd = remote_hostio_open (remote_file, (FILEIO_O_WRONLY | FILEIO_O_CREAT
+ | FILEIO_O_TRUNC),
+ 0700, &remote_errno);
+ if (fd == -1)
+ remote_hostio_error (remote_errno);
+
+ /* Send up to this many bytes at once. They won't all fit in the
+ remote packet limit, so we'll transfer slightly fewer. */
+ io_size = get_remote_packet_size ();
+ buffer = xmalloc (io_size);
+ make_cleanup (xfree, buffer);
+
+ close_cleanup = make_cleanup (remote_hostio_close_cleanup, &fd);
+
+ bytes_in_buffer = 0;
+ saw_eof = 0;
+ offset = 0;
+ while (bytes_in_buffer || !saw_eof)
+ {
+ if (!saw_eof)
+ {
+ bytes = fread (buffer + bytes_in_buffer, 1, io_size - bytes_in_buffer,
+ file);
+ if (bytes == 0)
+ {
+ if (ferror (file))
+ error (_("Error reading %s."), local_file);
+ else
+ {
+ /* EOF. Unless there is something still in the
+ buffer from the last iteration, we are done. */
+ saw_eof = 1;
+ if (bytes_in_buffer == 0)
+ break;
+ }
+ }
+ }
+ else
+ bytes = 0;
+
+ bytes += bytes_in_buffer;
+ bytes_in_buffer = 0;
+
+ retcode = remote_hostio_pwrite (fd, buffer, bytes, offset, &remote_errno);
+
+ if (retcode < 0)
+ remote_hostio_error (remote_errno);
+ else if (retcode == 0)
+ error (_("Remote write of %d bytes returned 0!"), bytes);
+ else if (retcode < bytes)
+ {
+ /* Short write. Save the rest of the read data for the next
+ write. */
+ bytes_in_buffer = bytes - retcode;
+ memmove (buffer, buffer + retcode, bytes_in_buffer);
+ }
+
+ offset += retcode;
+ }
+
+ discard_cleanups (close_cleanup);
+ if (remote_hostio_close (fd, &remote_errno))
+ remote_hostio_error (remote_errno);
+
+ if (from_tty)
+ printf_filtered (_("Successfully sent file \"%s\".\n"), local_file);
+ do_cleanups (back_to);
+}
+
+void
+remote_file_get (const char *remote_file, const char *local_file, int from_tty)
+{
+ struct cleanup *back_to, *close_cleanup;
+ int retcode, fd, remote_errno, bytes, io_size;
+ FILE *file;
+ gdb_byte *buffer;
+ ULONGEST offset;
+
+ if (!remote_desc)
+ error (_("command can only be used with remote target"));
+
+ fd = remote_hostio_open (remote_file, FILEIO_O_RDONLY, 0, &remote_errno);
+ if (fd == -1)
+ remote_hostio_error (remote_errno);
+
+ file = fopen (local_file, "wb");
+ if (file == NULL)
+ perror_with_name (local_file);
+ back_to = make_cleanup (fclose_cleanup, file);
+
+ /* Send up to this many bytes at once. They won't all fit in the
+ remote packet limit, so we'll transfer slightly fewer. */
+ io_size = get_remote_packet_size ();
+ buffer = xmalloc (io_size);
+ make_cleanup (xfree, buffer);
+
+ close_cleanup = make_cleanup (remote_hostio_close_cleanup, &fd);
+
+ offset = 0;
+ while (1)
+ {
+ bytes = remote_hostio_pread (fd, buffer, io_size, offset, &remote_errno);
+ if (bytes == 0)
+ /* Success, but no bytes, means end-of-file. */
+ break;
+ if (bytes == -1)
+ remote_hostio_error (remote_errno);
+
+ offset += bytes;
+
+ bytes = fwrite (buffer, 1, bytes, file);
+ if (bytes == 0)
+ perror_with_name (local_file);
+ }
+
+ discard_cleanups (close_cleanup);
+ if (remote_hostio_close (fd, &remote_errno))
+ remote_hostio_error (remote_errno);
+
+ if (from_tty)
+ printf_filtered (_("Successfully fetched file \"%s\".\n"), remote_file);
+ do_cleanups (back_to);
+}
+
+void
+remote_file_delete (const char *remote_file, int from_tty)
+{
+ int retcode, remote_errno;
+
+ if (!remote_desc)
+ error (_("command can only be used with remote target"));
+
+ retcode = remote_hostio_unlink (remote_file, &remote_errno);
+ if (retcode == -1)
+ remote_hostio_error (remote_errno);
+
+ if (from_tty)
+ printf_filtered (_("Successfully deleted file \"%s\".\n"), remote_file);
+}
+
+static void
+remote_put_command (char *args, int from_tty)
+{
+ struct cleanup *back_to;
+ char **argv;
+
+ argv = buildargv (args);
+ if (argv == NULL)
+ nomem (0);
+ back_to = make_cleanup_freeargv (argv);
+ if (argv[0] == NULL || argv[1] == NULL || argv[2] != NULL)
+ error (_("Invalid parameters to remote put"));
+
+ remote_file_put (argv[0], argv[1], from_tty);
+
+ do_cleanups (back_to);
+}
+
+static void
+remote_get_command (char *args, int from_tty)
+{
+ struct cleanup *back_to;
+ char **argv;
+
+ argv = buildargv (args);
+ if (argv == NULL)
+ nomem (0);
+ back_to = make_cleanup_freeargv (argv);
+ if (argv[0] == NULL || argv[1] == NULL || argv[2] != NULL)
+ error (_("Invalid parameters to remote get"));
+
+ remote_file_get (argv[0], argv[1], from_tty);
+
+ do_cleanups (back_to);
+}
+
+static void
+remote_delete_command (char *args, int from_tty)
+{
+ struct cleanup *back_to;
+ char **argv;
+
+ argv = buildargv (args);
+ if (argv == NULL)
+ nomem (0);
+ back_to = make_cleanup_freeargv (argv);
+ if (argv[0] == NULL || argv[1] != NULL)
+ error (_("Invalid parameters to remote delete"));
+
+ remote_file_delete (argv[0], from_tty);
+
+ do_cleanups (back_to);
+}
+
+static void
+remote_command (char *args, int from_tty)
+{
+ help_list (remote_cmdlist, "remote ", -1, gdb_stdout);
+}
+
static void
init_remote_ops (void)
{
remote_ops.to_stop = remote_stop;
remote_ops.to_xfer_partial = remote_xfer_partial;
remote_ops.to_rcmd = remote_rcmd;
+ remote_ops.to_log_command = serial_log_command;
remote_ops.to_get_thread_local_address = remote_get_thread_local_address;
remote_ops.to_stratum = process_stratum;
remote_ops.to_has_all_memory = 1;
remote_ops.to_flash_erase = remote_flash_erase;
remote_ops.to_flash_done = remote_flash_done;
remote_ops.to_read_description = remote_read_description;
+ remote_ops.to_search_memory = remote_search_memory;
+ remote_ops.to_can_async_p = remote_can_async_p;
+ remote_ops.to_is_async_p = remote_is_async_p;
+ remote_ops.to_async = remote_async;
+ remote_ops.to_async_mask = remote_async_mask;
+ remote_ops.to_terminal_inferior = remote_terminal_inferior;
+ remote_ops.to_terminal_ours = remote_terminal_ours;
}
/* Set up the extended remote vector by making a copy of the standard
"Extended remote serial target in gdb-specific protocol";
extended_remote_ops.to_doc =
"Use a remote computer via a serial line, using a gdb-specific protocol.\n\
-Specify the serial device it is connected to (e.g. /dev/ttya).",
- extended_remote_ops.to_open = extended_remote_open;
+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;
}
static int
remote_can_async_p (void)
{
+ if (!target_async_permitted)
+ /* We only enable async when the user specifically asks for it. */
+ return 0;
+
/* We're async whenever the serial device is. */
- return (current_target.to_async_mask_value) && serial_can_async_p (remote_desc);
+ return remote_async_mask_value && serial_can_async_p (remote_desc);
}
static int
remote_is_async_p (void)
{
+ if (!target_async_permitted)
+ /* We only enable async when the user specifically asks for it. */
+ return 0;
+
/* We're async whenever the serial device is. */
- return (current_target.to_async_mask_value) && serial_is_async_p (remote_desc);
+ return remote_async_mask_value && serial_is_async_p (remote_desc);
}
/* Pass the SERIAL event on and up to the client. One day this code
remote_async (void (*callback) (enum inferior_event_type event_type,
void *context), void *context)
{
- if (current_target.to_async_mask_value == 0)
+ if (remote_async_mask_value == 0)
internal_error (__FILE__, __LINE__,
_("Calling remote_async when async is masked"));
serial_async (remote_desc, NULL, NULL);
}
-/* Target async and target extended-async.
-
- This are temporary targets, until it is all tested. Eventually
- async support will be incorporated int the usual 'remote'
- target. */
-
-static void
-init_remote_async_ops (void)
-{
- remote_async_ops.to_shortname = "async";
- remote_async_ops.to_longname =
- "Remote serial target in async version of the gdb-specific protocol";
- remote_async_ops.to_doc =
- "Use a remote computer via a serial line, using a gdb-specific protocol.\n\
-Specify the serial device it is connected to (e.g. /dev/ttya).";
- remote_async_ops.to_open = remote_async_open;
- remote_async_ops.to_close = remote_close;
- remote_async_ops.to_detach = remote_detach;
- remote_async_ops.to_disconnect = remote_disconnect;
- remote_async_ops.to_resume = remote_async_resume;
- remote_async_ops.to_wait = remote_async_wait;
- remote_async_ops.to_fetch_registers = remote_fetch_registers;
- remote_async_ops.to_store_registers = remote_store_registers;
- remote_async_ops.to_prepare_to_store = remote_prepare_to_store;
- remote_async_ops.deprecated_xfer_memory = remote_xfer_memory;
- remote_async_ops.to_files_info = remote_files_info;
- remote_async_ops.to_insert_breakpoint = remote_insert_breakpoint;
- remote_async_ops.to_remove_breakpoint = remote_remove_breakpoint;
- remote_async_ops.to_can_use_hw_breakpoint = remote_check_watch_resources;
- remote_async_ops.to_insert_hw_breakpoint = remote_insert_hw_breakpoint;
- remote_async_ops.to_remove_hw_breakpoint = remote_remove_hw_breakpoint;
- remote_async_ops.to_insert_watchpoint = remote_insert_watchpoint;
- remote_async_ops.to_remove_watchpoint = remote_remove_watchpoint;
- remote_async_ops.to_stopped_by_watchpoint = remote_stopped_by_watchpoint;
- remote_async_ops.to_stopped_data_address = remote_stopped_data_address;
- remote_async_ops.to_terminal_inferior = remote_async_terminal_inferior;
- remote_async_ops.to_terminal_ours = remote_async_terminal_ours;
- remote_async_ops.to_kill = remote_async_kill;
- remote_async_ops.to_load = generic_load;
- remote_async_ops.to_mourn_inferior = remote_async_mourn;
- remote_async_ops.to_thread_alive = remote_thread_alive;
- remote_async_ops.to_find_new_threads = remote_threads_info;
- remote_async_ops.to_pid_to_str = remote_pid_to_str;
- remote_async_ops.to_extra_thread_info = remote_threads_extra_info;
- remote_async_ops.to_stop = remote_stop;
- remote_async_ops.to_xfer_partial = remote_xfer_partial;
- remote_async_ops.to_rcmd = remote_rcmd;
- remote_async_ops.to_stratum = process_stratum;
- remote_async_ops.to_has_all_memory = 1;
- remote_async_ops.to_has_memory = 1;
- remote_async_ops.to_has_stack = 1;
- remote_async_ops.to_has_registers = 1;
- remote_async_ops.to_has_execution = 1;
- remote_async_ops.to_has_thread_control = tc_schedlock; /* can lock scheduler */
- remote_async_ops.to_can_async_p = remote_can_async_p;
- remote_async_ops.to_is_async_p = remote_is_async_p;
- remote_async_ops.to_async = remote_async;
- remote_async_ops.to_async_mask_value = 1;
- remote_async_ops.to_magic = OPS_MAGIC;
- remote_async_ops.to_memory_map = remote_memory_map;
- remote_async_ops.to_flash_erase = remote_flash_erase;
- remote_async_ops.to_flash_done = remote_flash_done;
- remote_async_ops.to_read_description = remote_read_description;
-}
-
-/* Set up the async extended remote vector by making a copy of the standard
- remote vector and adding to it. */
-
-static void
-init_extended_async_remote_ops (void)
+static int
+remote_async_mask (int new_mask)
{
- extended_async_remote_ops = remote_async_ops;
-
- extended_async_remote_ops.to_shortname = "extended-async";
- extended_async_remote_ops.to_longname =
- "Extended remote serial target in async gdb-specific protocol";
- extended_async_remote_ops.to_doc =
- "Use a remote computer via a serial line, using an async gdb-specific protocol.\n\
-Specify the serial device it is connected to (e.g. /dev/ttya).",
- extended_async_remote_ops.to_open = extended_remote_async_open;
- extended_async_remote_ops.to_create_inferior = extended_remote_async_create_inferior;
- extended_async_remote_ops.to_mourn_inferior = extended_remote_mourn;
+ int curr_mask = remote_async_mask_value;
+ remote_async_mask_value = new_mask;
+ return curr_mask;
}
static void
init_extended_remote_ops ();
add_target (&extended_remote_ops);
- init_remote_async_ops ();
- add_target (&remote_async_ops);
-
- init_extended_async_remote_ops ();
- add_target (&extended_async_remote_ops);
-
/* Hook into new objfile notification. */
observer_attach_new_objfile (remote_new_objfile);
+ /* Set up signal handlers. */
+ sigint_remote_token =
+ create_async_signal_handler (async_remote_interrupt, NULL);
+ sigint_remote_twice_token =
+ create_async_signal_handler (inferior_event_handler_wrapper, NULL);
+
#if 0
init_remote_threadtests ();
#endif
add_packet_config_cmd (&remote_protocol_packets[PACKET_qSupported],
"qSupported", "supported-packets", 0);
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_qSearch_memory],
+ "qSearch:memory", "search-memory", 0);
+
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_vFile_open],
+ "vFile:open", "hostio-open", 0);
+
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_vFile_pread],
+ "vFile:pread", "hostio-pread", 0);
+
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_vFile_pwrite],
+ "vFile:pwrite", "hostio-pwrite", 0);
+
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_vFile_close],
+ "vFile:close", "hostio-close", 0);
+
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_vFile_unlink],
+ "vFile:unlink", "hostio-unlink", 0);
+
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_vAttach],
+ "vAttach", "attach", 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);
+
/* 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_remote_protocol_Z_packet_cmd, /* FIXME: i18n: Use of remote protocol `Z' packets is %s. */
&remote_set_cmdlist, &remote_show_cmdlist);
+ add_prefix_cmd ("remote", class_files, remote_command, _("\
+Manipulate files on the remote system\n\
+Transfer files to and from the remote target system."),
+ &remote_cmdlist, "remote ",
+ 0 /* allow-unknown */, &cmdlist);
+
+ add_cmd ("put", class_files, remote_put_command,
+ _("Copy a local file to the remote system."),
+ &remote_cmdlist);
+
+ add_cmd ("get", class_files, remote_get_command,
+ _("Copy a remote file to the local system."),
+ &remote_cmdlist);
+
+ add_cmd ("delete", class_files, remote_delete_command,
+ _("Delete a remote file."),
+ &remote_cmdlist);
+
+ remote_exec_file = xstrdup ("");
+ add_setshow_string_noescape_cmd ("exec-file", class_files,
+ &remote_exec_file, _("\
+Set the remote pathname for \"run\""), _("\
+Show the remote pathname for \"run\""), NULL, NULL, NULL,
+ &remote_set_cmdlist, &remote_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);
}