/* Remote target communications for serial-line targets in custom GDB protocol
- Copyright 1988, 1991, 1992, 1993 Free Software Foundation, Inc.
+ Copyright 1988, 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
This file is part of GDB.
$ <data> # CSUM1 CSUM2
<data> must be ASCII alphanumeric and cannot include characters
- '$' or '#'
+ '$' or '#'. If <data> starts with two characters followed by
+ ':', then the existing stubs interpret this as a sequence number.
CSUM1 and CSUM2 are ascii hex representation of an 8-bit
checksum of <data>, the most significant nibble is sent first.
- - if CSUM is incorrect
<data> is as follows:
- All values are encoded in ascii hex digits.
+ Most values are encoded in ascii hex digits. Signal numbers are according
+ to the numbering in target.h.
Request Packet
+ set thread Hct... Set thread for subsequent operations.
+ c = 'c' for thread used in step and
+ continue; t... can be -1 for all
+ threads.
+ c = 'g' for thread used in other
+ operations. If zero, pick a thread,
+ any thread.
+ reply OK for success
+ ENN for an error.
+
read registers g
reply XX....X Each byte of register data
is described by two hex digits.
reply OK for success
ENN for an error
+ write reg Pn...=r... Write register n... with value r...,
+ which contains two hex digits for each
+ byte in the register (target byte
+ order).
+ reply OK for success
+ ENN for an error
+ (not supported by all stubs).
+
read mem mAA..AA,LLLL AA..AA is address, LLLL is length.
reply XX..XX XX..XX is mem contents
Can be fewer bytes than requested
where only part of the data was
written).
- cont cAA..AA AA..AA is address to resume
+ continue cAA..AA AA..AA is address to resume
If AA..AA is omitted,
resume at same address.
If AA..AA is omitted,
resume at same address.
+ continue with Csig;AA Continue with signal sig (hex signal
+ signal number).
+
+ step with Ssig;AA Like 'C' but step not continue.
+ signal
+
last signal ? Reply the current reason for stopping.
This is the same reply as is generated
for step or cont : SAA where AA is the
There is no immediate reply to step or cont.
The reply comes when the machine stops.
- It is SAA AA is the "signal number"
+ It is SAA AA is the signal number.
- or... TAAn...:r...;n:r...;n...:r...;
+ or... TAAn...:r...;n...:r...;n...:r...;
AA = signal number
- n... = register number
- r... = register contents
- or... WAA The process extited, and AA is
+ n... = register number (hex)
+ r... = register contents
+ n... = `thread'
+ r... = thread process ID. This is
+ a hex integer.
+ n... = other string not starting
+ with valid hex digit.
+ gdb should ignore this n,r pair
+ and go on to the next. This way
+ we can extend the protocol.
+ or... WAA The process exited, and AA is
the exit status. This is only
applicable for certains sorts of
targets.
- or... NAATT;DD;BB Relocate the object file.
- AA = signal number
- TT = text address
- DD = data address
- BB = bss address
- This is used by the NLM stub,
- which is why it only has three
- addresses rather than one per
- section: the NLM stub always
- sees only three sections, even
- though gdb may see more.
+ or... XAA The process terminated with signal
+ AA.
+ or... Otext Send text to stdout. This can happen
+ at any time while the program is
+ running and the debugger should
+ continue to wait for 'W', 'T', etc.
kill request k
we can extend the protocol and GDB
can tell whether the stub it is
talking to uses the old or the new.
-*/
+ search tAA:PP,MM Search backwards starting at address
+ AA for a match with pattern PP and
+ mask MM. PP and MM are 4 bytes.
+ Not supported by all stubs.
+
+ general query qXXXX Request info about XXXX.
+ general set QXXXX=yyyy Set value of XXXX to yyyy.
+ query sect offs qOffsets Get section offsets. Reply is
+ Text=xxx;Data=yyy;Bss=zzz
+
+ Responses can be run-length encoded to save space. A '*' means that
+ the next character is an ASCII encoding giving a repeat count which
+ stands for that many repititions of the character preceding the '*'.
+ The encoding is n+29, yielding a printable character where n >=3
+ (which is where rle starts to win). Don't use an n > 126.
+
+ So
+ "0* " means the same as "0000". */
#include "defs.h"
#include <string.h>
#include "gdbcmd.h"
#include "objfiles.h"
#include "gdb-stabs.h"
+#include "thread.h"
#include "dcache.h"
-#include "remote-utils.h"
-#if !defined(DONT_USE_REMOTE)
#ifdef USG
#include <sys/types.h>
#endif
/* Prototypes for local functions */
-static int
-remote_write_bytes PARAMS ((CORE_ADDR memaddr, unsigned char *myaddr, int len));
+static int remote_write_bytes PARAMS ((CORE_ADDR memaddr,
+ char *myaddr, int len));
-static int
-remote_read_bytes PARAMS ((CORE_ADDR memaddr, unsigned char *myaddr, int len));
+static int remote_read_bytes PARAMS ((CORE_ADDR memaddr,
+ char *myaddr, int len));
-static void
-remote_files_info PARAMS ((struct target_ops *ignore));
+static void remote_files_info PARAMS ((struct target_ops *ignore));
-static int
-remote_xfer_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, int len,
- int should_write, struct target_ops *target));
+static int remote_xfer_memory PARAMS ((CORE_ADDR memaddr, char *myaddr,
+ int len, int should_write,
+ struct target_ops *target));
-static void
-remote_prepare_to_store PARAMS ((void));
+static void remote_prepare_to_store PARAMS ((void));
-static void
-remote_fetch_registers PARAMS ((int regno));
+static void remote_fetch_registers PARAMS ((int regno));
-static void
-remote_resume PARAMS ((int pid, int step, int siggnal));
+static void remote_resume PARAMS ((int pid, int step,
+ enum target_signal siggnal));
-static int
-remote_start_remote PARAMS ((char *dummy));
+static int remote_start_remote PARAMS ((char *dummy));
-static void
-remote_open PARAMS ((char *name, int from_tty));
+static void remote_open PARAMS ((char *name, int from_tty));
-static void
-remote_close PARAMS ((int quitting));
+static void remote_close PARAMS ((int quitting));
-static void
-remote_store_registers PARAMS ((int regno));
+static void remote_store_registers PARAMS ((int regno));
-static void
-getpkt PARAMS ((char *buf, int forever));
+static void getpkt PARAMS ((char *buf, int forever));
-static void
-putpkt PARAMS ((char *buf));
+static int putpkt PARAMS ((char *buf));
-static void
-remote_send PARAMS ((char *buf));
+static void remote_send PARAMS ((char *buf));
-static int
-readchar PARAMS ((void));
+static int readchar PARAMS ((int timeout));
-static int
-remote_wait PARAMS ((WAITTYPE *status));
+static int remote_wait PARAMS ((int pid, struct target_waitstatus *status));
-static int
-tohex PARAMS ((int nib));
+static void remote_kill PARAMS ((void));
-static int
-fromhex PARAMS ((int a));
+static int tohex PARAMS ((int nib));
-static void
-remote_detach PARAMS ((char *args, int from_tty));
+static int fromhex PARAMS ((int a));
-static void
-remote_interrupt PARAMS ((int signo));
+static void remote_detach PARAMS ((char *args, int from_tty));
-static void
-remote_interrupt_twice PARAMS ((int signo));
+static void remote_interrupt PARAMS ((int signo));
-static void
-interrupt_query PARAMS ((void));
+static void remote_interrupt_twice PARAMS ((int signo));
+
+static void interrupt_query PARAMS ((void));
extern struct target_ops remote_ops; /* Forward decl */
Unless this is going though some terminal server or multiplexer or
other form of hairy serial connection, I would think 2 seconds would
be plenty. */
-static int timeout = 2;
-#if 0
-int icache;
-#endif
+static int remote_timeout = 2;
/* Descriptor for I/O to remote machine. Initialize it to NULL so that
remote_open knows that we don't have a file open when the program
starts. */
serial_t remote_desc = NULL;
-#define PBUFSIZ 1024
+/* Having this larger than 400 causes us to be incompatible with m68k-stub.c
+ and i386-stub.c. Normally, no one would notice because it only matters
+ for writing large chunks of memory (e.g. in downloads). Also, this needs
+ to be more than 400 if required to hold the registers (see below, where
+ we round it up based on REGISTER_BYTES). */
+#define PBUFSIZ 400
/* Maximum number of bytes to read/write at once. The value here
is chosen to fill up a packet (the headers account for the 32). */
#define MAXBUFBYTES ((PBUFSIZ-32)/2)
/* Round up PBUFSIZ to hold all the registers, at least. */
+/* The blank line after the #if seems to be required to work around a
+ bug in HP's PA compiler. */
#if REGISTER_BYTES > MAXBUFBYTES
-#undef PBUFSIZ
+
+#undef PBUFSIZ
#define PBUFSIZ (REGISTER_BYTES * 2 + 32)
#endif
+
+/* Should we try the 'P' request? If this is set to one when the stub
+ doesn't support 'P', the only consequence is some unnecessary traffic. */
+static int stub_supports_P = 1;
+
+\f
+/* These are the threads which we last sent to the remote system. -1 for all
+ or -2 for not sent yet. */
+int general_thread;
+int cont_thread;
+
+static void
+set_thread (th, gen)
+ int th;
+ int gen;
+{
+ char buf[PBUFSIZ];
+ int state = gen ? general_thread : cont_thread;
+ if (state == th)
+ return;
+ buf[0] = 'H';
+ buf[1] = gen ? 'g' : 'c';
+ if (th == 42000)
+ {
+ buf[2] = '0';
+ buf[3] = '\0';
+ }
+ else if (th < 0)
+ sprintf (&buf[2], "-%x", -th);
+ else
+ sprintf (&buf[2], "%x", th);
+ putpkt (buf);
+ getpkt (buf, 0);
+ if (gen)
+ general_thread = th;
+ else
+ cont_thread = th;
+}
+\f
+/* Return nonzero if the thread TH is still alive on the remote system. */
+
+static int
+remote_thread_alive (th)
+ int th;
+{
+ char buf[PBUFSIZ];
+
+ buf[0] = 'T';
+ if (th < 0)
+ sprintf (&buf[1], "-%x", -th);
+ else
+ sprintf (&buf[1], "%x", th);
+ putpkt (buf);
+ getpkt (buf, 0);
+ return (buf[0] == 'O' && buf[1] == 'K');
+}
\f
/* Clean up connection to a remote debugger. */
remote_desc = NULL;
}
+/* Query the remote side for the text, data and bss offsets. */
+
+static void
+get_offsets ()
+{
+ char buf[PBUFSIZ];
+ int nvals;
+ CORE_ADDR text_addr, data_addr, bss_addr;
+ struct section_offsets *offs;
+
+ putpkt ("qOffsets");
+
+ getpkt (buf, 0);
+
+ if (buf[0] == '\000')
+ return; /* Return silently. Stub doesn't support this
+ command. */
+ if (buf[0] == 'E')
+ {
+ warning ("Remote failure reply: %s", buf);
+ return;
+ }
+
+ nvals = sscanf (buf, "Text=%lx;Data=%lx;Bss=%lx", &text_addr, &data_addr,
+ &bss_addr);
+ if (nvals != 3)
+ error ("Malformed response to offset query, %s", buf);
+
+ if (symfile_objfile == NULL)
+ return;
+
+ offs = (struct section_offsets *) alloca (sizeof (struct section_offsets)
+ + symfile_objfile->num_sections
+ * sizeof (offs->offsets));
+ memcpy (offs, symfile_objfile->section_offsets,
+ sizeof (struct section_offsets)
+ + symfile_objfile->num_sections
+ * sizeof (offs->offsets));
+
+ ANOFFSET (offs, SECT_OFF_TEXT) = text_addr;
+
+ /* This is a temporary kludge to force data and bss to use the same offsets
+ because that's what nlmconv does now. The real solution requires changes
+ to the stub and remote.c that I don't have time to do right now. */
+
+ ANOFFSET (offs, SECT_OFF_DATA) = data_addr;
+ ANOFFSET (offs, SECT_OFF_BSS) = data_addr;
+
+ objfile_relocate (symfile_objfile, offs);
+}
+
/* Stub for catch_errors. */
static int
immediate_quit = 1; /* Allow user to interrupt it */
/* Ack any packet which the remote side has already sent. */
- /* I'm not sure this \r is needed; we don't use it any other time we
- send an ack. */
- SERIAL_WRITE (remote_desc, "+\r", 2);
+ SERIAL_WRITE (remote_desc, "+", 1);
+
+ /* Let the stub know that we want it to return the thread. */
+ set_thread (-1, 0);
+
+ get_offsets (); /* Get text, data & bss offsets */
+
putpkt ("?"); /* initiate a query from remote machine */
immediate_quit = 0;
int from_tty;
{
if (name == 0)
- error (
-"To open a remote debug connection, you need to specify what serial\n\
+ error ("To open a remote debug connection, you need to specify what serial\n\
device is attached to the remote system (e.g. /dev/ttya).");
target_preopen (from_tty);
if (!remote_desc)
perror_with_name (name);
- if (SERIAL_SETBAUDRATE (remote_desc, sr_get_baud_rate()))
+ if (baud_rate != -1)
{
- SERIAL_CLOSE (remote_desc);
- perror_with_name (name);
+ if (SERIAL_SETBAUDRATE (remote_desc, baud_rate))
+ {
+ SERIAL_CLOSE (remote_desc);
+ perror_with_name (name);
+ }
}
+
SERIAL_RAW (remote_desc);
/* If there is something sitting in the buffer we might take it as a
}
push_target (&remote_ops); /* Switch to using remote target now */
+ /* Start out by trying the 'P' request to set registers. We set this each
+ time that we open a new target so that if the user switches from one
+ stub to another, we can (if the target is closed and reopened) cope. */
+ stub_supports_P = 1;
+
+ general_thread = -2;
+ cont_thread = -2;
+
+ /* 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_pid = 42000;
/* Start the remote connection; if error (0), discard this target.
In particular, if the user quits, be sure to discard it
(we'd be in an inconsistent state otherwise). */
if (!catch_errors (remote_start_remote, (char *)0,
- "Couldn't establish connection to remote target\n", RETURN_MASK_ALL))
+ "Couldn't establish connection to remote target\n", RETURN_MASK_ALL))
pop_target();
}
else if (a >= 'a' && a <= 'f')
return a - 'a' + 10;
else
- error ("Reply contains invalid hex digit");
- return -1;
+ error ("Reply contains invalid hex digit %d", a);
}
/* Convert number NIB to a hex digit. */
\f
/* Tell the remote machine to resume. */
+static enum target_signal last_sent_signal = TARGET_SIGNAL_0;
+int last_sent_step;
+
static void
remote_resume (pid, step, siggnal)
- int pid, step, siggnal;
+ int pid, step;
+ enum target_signal siggnal;
{
char buf[PBUFSIZ];
- if (siggnal)
- {
- char *name;
- target_terminal_ours_for_output ();
- printf_filtered ("Can't send signals to a remote system. ");
- name = strsigno (siggnal);
- if (name)
- printf_filtered (name);
- else
- printf_filtered ("Signal %d", siggnal);
- printf_filtered (" not sent.\n");
- target_terminal_inferior ();
- }
+ if (pid == -1)
+ set_thread (inferior_pid, 0);
+ else
+ set_thread (pid, 0);
dcache_flush (remote_dcache);
- strcpy (buf, step ? "s": "c");
+ last_sent_signal = siggnal;
+ last_sent_step = step;
+
+ if (siggnal != TARGET_SIGNAL_0)
+ {
+ buf[0] = step ? 'S' : 'C';
+ buf[1] = tohex (((int)siggnal >> 4) & 0xf);
+ buf[2] = tohex ((int)siggnal & 0xf);
+ buf[3] = '\0';
+ }
+ else
+ strcpy (buf, step ? "s": "c");
putpkt (buf);
}
/* If this doesn't work, try more severe steps. */
signal (signo, remote_interrupt_twice);
- if (sr_get_debug ())
- printf ("remote_interrupt called\n");
+ if (remote_debug)
+ printf_unfiltered ("remote_interrupt called\n");
SERIAL_WRITE (remote_desc, "\003", 1); /* Send a ^C */
}
target_terminal_inferior ();
}
+/* If nonzero, ignore the next kill. */
+int kill_kludge;
+
/* Wait until the remote machine stops, then return,
storing status in STATUS just as `wait' would.
Returns "pid" (though it's not clear what, if anything, that
means in the case of this target). */
static int
-remote_wait (status)
- WAITTYPE *status;
+remote_wait (pid, status)
+ int pid;
+ struct target_waitstatus *status;
{
unsigned char buf[PBUFSIZ];
+ int thread_num = -1;
- WSETEXIT ((*status), 0);
+ status->kind = TARGET_WAITKIND_EXITED;
+ status->value.integer = 0;
while (1)
{
getpkt ((char *) buf, 1);
signal (SIGINT, ofunc);
- if (buf[0] == 'E')
- warning ("Remote failure reply: %s", buf);
- else if (buf[0] == 'T')
+ switch (buf[0])
{
- int i;
- long regno;
- char regs[MAX_REGISTER_RAW_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)
- {
- unsigned char *p1;
-
- regno = strtol (p, &p1, 16); /* Read the register number */
-
- if (p1 == p)
- warning ("Remote sent badly formed register number: %s\nPacket: '%s'\n",
- p1, buf);
-
- p = p1;
-
- if (*p++ != ':')
- warning ("Malformed packet (missing colon): %s\nPacket: '%s'\n",
- p, buf);
+ case 'E': /* Error of some sort */
+ warning ("Remote failure reply: %s", buf);
+ continue;
+ case 'T': /* Status with PC, SP, FP, ... */
+ {
+ int i;
+ long regno;
+ char regs[MAX_REGISTER_RAW_SIZE];
- if (regno >= NUM_REGS)
- warning ("Remote sent bad register number %d: %s\nPacket: '%s'\n",
- regno, p, buf);
+ /* 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
+ */
- for (i = 0; i < REGISTER_RAW_SIZE (regno); i++)
- {
- if (p[0] == 0 || p[1] == 0)
- warning ("Remote reply is too short: %s", buf);
- regs[i] = fromhex (p[0]) * 16 + fromhex (p[1]);
- p += 2;
- }
+ p = &buf[3]; /* after Txx */
- if (*p++ != ';')
- warning ("Remote register badly formatted: %s", buf);
-
- supply_register (regno, regs);
- }
- break;
- }
- else if (buf[0] == 'N')
- {
- unsigned char *p1;
- bfd_vma text_addr, data_addr, bss_addr;
-
- /* Relocate object file. Format is NAATT;DD;BB where AA is
- the signal number, TT is the new text address, DD is the
- new data address, and BB is the new bss address. This is
- used by the NLM stub; gdb may see more sections. */
- p = &buf[3];
- text_addr = strtoul (p, &p1, 16);
- if (p1 == p || *p1 != ';')
- warning ("Malformed relocation packet: Packet '%s'", buf);
- p = p1 + 1;
- data_addr = strtoul (p, &p1, 16);
- if (p1 == p || *p1 != ';')
- warning ("Malformed relocation packet: Packet '%s'", buf);
- p = p1 + 1;
- bss_addr = strtoul (p, &p1, 16);
- if (p1 == p)
- warning ("Malformed relocation packet: Packet '%s'", buf);
-
- if (symfile_objfile != NULL
- && (ANOFFSET (symfile_objfile->section_offsets,
- SECT_OFF_TEXT) != text_addr
- || ANOFFSET (symfile_objfile->section_offsets,
- SECT_OFF_DATA) != data_addr
- || ANOFFSET (symfile_objfile->section_offsets,
- SECT_OFF_BSS) != bss_addr))
- {
- struct section_offsets *offs;
-
- /* FIXME: This code assumes gdb-stabs.h is being used;
- it's broken for xcoff, dwarf, sdb-coff, etc. But
- there is no simple canonical representation for this
- stuff. (Just what does "text" as seen by the stub
- mean, anyway?). */
-
- /* FIXME: Why don't the various symfile_offsets routines
- in the sym_fns vectors set this?
- (no good reason -kingdon). */
- if (symfile_objfile->num_sections == 0)
- symfile_objfile->num_sections = SECT_OFF_MAX;
-
- offs = ((struct section_offsets *)
- alloca (sizeof (struct section_offsets)
- + (symfile_objfile->num_sections
- * sizeof (offs->offsets))));
- memcpy (offs, symfile_objfile->section_offsets,
- (sizeof (struct section_offsets)
- + (symfile_objfile->num_sections
- * sizeof (offs->offsets))));
- ANOFFSET (offs, SECT_OFF_TEXT) = text_addr;
- ANOFFSET (offs, SECT_OFF_DATA) = data_addr;
- ANOFFSET (offs, SECT_OFF_BSS) = bss_addr;
-
- objfile_relocate (symfile_objfile, offs);
+ while (*p)
{
- struct obj_section *s;
- bfd *bfd;
+ unsigned char *p1;
+ char *p_temp;
- bfd = symfile_objfile->obfd;
+ regno = strtol (p, &p_temp, 16); /* Read the register number */
+ p1 = (unsigned char *)p_temp;
- for (s = symfile_objfile->sections;
- s < symfile_objfile->sections_end; ++s)
+ if (p1 == p)
{
- flagword flags;
-
- flags = bfd_get_section_flags (bfd, s->sec_ptr);
-
- if (flags & SEC_CODE)
- {
- s->addr += text_addr;
- s->endaddr += text_addr;
- }
- else if (flags & (SEC_DATA | SEC_LOAD))
+ p1 = (unsigned char *) strchr (p, ':');
+ if (p1 == NULL)
+ warning ("Malformed packet (missing colon): %s\n\
+Packet: '%s'\n",
+ p, buf);
+ if (strncmp (p, "thread", p1 - p) == 0)
{
- s->addr += data_addr;
- s->endaddr += data_addr;
+ thread_num = strtol (++p1, &p_temp, 16);
+ p = (unsigned char *)p_temp;
}
- else if (flags & SEC_ALLOC)
+ }
+ else
+ {
+ p = p1;
+
+ if (*p++ != ':')
+ warning ("Malformed packet (missing colon): %s\n\
+Packet: '%s'\n",
+ p, buf);
+
+ if (regno >= NUM_REGS)
+ warning ("Remote sent bad register number %d: %s\n\
+Packet: '%s'\n",
+ regno, p, buf);
+
+ for (i = 0; i < REGISTER_RAW_SIZE (regno); i++)
{
- s->addr += bss_addr;
- s->endaddr += bss_addr;
+ if (p[0] == 0 || p[1] == 0)
+ warning ("Remote reply is too short: %s", buf);
+ regs[i] = fromhex (p[0]) * 16 + fromhex (p[1]);
+ p += 2;
}
+ supply_register (regno, regs);
}
+
+ if (*p++ != ';')
+ warning ("Remote register badly formatted: %s", buf);
}
+ }
+ /* fall through */
+ case 'S': /* Old style status, just signal only */
+ status->kind = TARGET_WAITKIND_STOPPED;
+ status->value.sig = (enum target_signal)
+ (((fromhex (buf[1])) << 4) + (fromhex (buf[2])));
+
+ goto got_status;
+ case 'W': /* Target exited */
+ {
+ /* 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 */
+ fputs_filtered ((char *)(buf + 1), gdb_stdout);
+ continue;
+ case '\0':
+ if (last_sent_signal != TARGET_SIGNAL_0)
+ {
+ /* Zero length reply means that we tried 'S' or 'C' and
+ the remote system doesn't support it. */
+ target_terminal_ours_for_output ();
+ printf_filtered
+ ("Can't send signals to this remote system. %s not sent.\n",
+ target_signal_to_name (last_sent_signal));
+ last_sent_signal = TARGET_SIGNAL_0;
+ target_terminal_inferior ();
+
+ strcpy (buf, last_sent_step ? "s" : "c");
+ putpkt (buf);
+ continue;
}
- break;
+ /* else fallthrough */
+ default:
+ warning ("Invalid remote reply: %s", buf);
+ continue;
}
- else if (buf[0] == 'W')
+ }
+ got_status:
+ if (thread_num != -1)
+ {
+ /* Initial thread value can only be acquired via wait, so deal with
+ this marker which is used before the first thread value is
+ acquired. */
+ if (inferior_pid == 42000)
{
- /* The remote process exited. */
- WSETEXIT (*status, (fromhex (buf[1]) << 4) + fromhex (buf[2]));
- return 0;
+ inferior_pid = thread_num;
+ add_thread (inferior_pid);
}
- else if (buf[0] == 'S')
- break;
- else
- warning ("Invalid remote reply: %s", buf);
+ return thread_num;
}
-
- WSETSTOP ((*status), (((fromhex (buf[1])) << 4) + (fromhex (buf[2]))));
-
- return 0;
+ return inferior_pid;
}
/* Number of bytes of registers this stub implements. */
char *p;
char regs[REGISTER_BYTES];
+ set_thread (inferior_pid, 1);
+
sprintf (buf, "g");
remote_send (buf);
while ((buf[0] < '0' || buf[0] > '9')
&& (buf[0] < 'a' || buf[0] > 'f'))
{
- if (sr_get_debug () > 0)
- printf ("Bad register packet; fetching a new packet\n");
+ if (remote_debug)
+ printf_unfiltered ("Bad register packet; fetching a new packet\n");
getpkt (buf, 0);
}
supply_register (i, ®s[REGISTER_BYTE(i)]);
}
-/* Prepare to store registers. Since we send them all, we have to
- read out the ones we don't want to change first. */
+/* Prepare to store registers. Since we may send them all (using a
+ 'G' request), we have to read out the ones we don't want to change
+ first. */
static void
remote_prepare_to_store ()
read_register_bytes (0, (char *)NULL, REGISTER_BYTES);
}
-/* Store the remote registers from the contents of the block REGISTERS.
- FIXME, eventually just store one register if that's all that is needed. */
+/* Store register REGNO, or all registers if REGNO == -1, from the contents
+ of REGISTERS. FIXME: ignores errors. */
-/* ARGSUSED */
static void
remote_store_registers (regno)
int regno;
int i;
char *p;
+ set_thread (inferior_pid, 1);
+
+ if (regno >= 0 && stub_supports_P)
+ {
+ /* Try storing a single register. */
+ char *regp;
+
+ sprintf (buf, "P%x=", regno);
+ p = buf + strlen (buf);
+ regp = ®isters[REGISTER_BYTE (regno)];
+ for (i = 0; i < REGISTER_RAW_SIZE (regno); ++i)
+ {
+ *p++ = tohex ((regp[i] >> 4) & 0xf);
+ *p++ = tohex (regp[i] & 0xf);
+ }
+ *p = '\0';
+ remote_send (buf);
+ if (buf[0] != '\0')
+ {
+ /* The stub understands the 'P' request. We are done. */
+ return;
+ }
+
+ /* The stub does not support the 'P' request. Use 'G' instead,
+ and don't try using 'P' in the future (it will just waste our
+ time). */
+ stub_supports_P = 0;
+ }
+
buf[0] = 'G';
-
+
/* Command describes registers byte by byte,
each byte encoded as two hex characters. */
remote_send (buf);
}
-#if 0
-
-/* Use of the data cache is disabled because it loses for looking at
+/*
+ Use of the data cache *used* to be disabled because it loses for looking at
and changing hardware I/O ports and the like. Accepting `volatile'
- would perhaps be one way to fix it, but a better way which would
- win for more cases would be to use the executable file for the text
- segment, like the `icache' code below but done cleanly (in some
- target-independent place, perhaps in target_xfer_memory, perhaps
- based on assigning each target a speed or perhaps by some simpler
- mechanism). */
+ would perhaps be one way to fix it. Another idea would be to use the
+ executable file for the text segment (for all SEC_CODE sections?
+ For all SEC_READONLY sections?). This has problems if you want to
+ actually see what the memory contains (e.g. self-modifying code,
+ clobbered memory, user downloaded the wrong thing).
+
+ Because it speeds so much up, it's now enabled, if you're playing
+ with registers you turn it of (set remotecache 0)
+*/
/* Read a word from remote address ADDR and return it.
This goes through the data cache. */
remote_fetch_word (addr)
CORE_ADDR addr;
{
-#if 0
- if (icache)
- {
- extern CORE_ADDR text_start, text_end;
-
- if (addr >= text_start && addr < text_end)
- {
- int buffer;
- xfer_core_file (addr, &buffer, sizeof (int));
- return buffer;
- }
- }
-#endif
return dcache_fetch (remote_dcache, addr);
}
{
dcache_poke (remote_dcache, addr, word);
}
-#endif /* 0 */
+
\f
/* Write memory data directly to the remote machine.
This does not inform the data cache; the data cache uses this.
static int
remote_write_bytes (memaddr, myaddr, len)
CORE_ADDR memaddr;
- unsigned char *myaddr;
+ char *myaddr;
int len;
{
char buf[PBUFSIZ];
int i;
char *p;
- if (len > PBUFSIZ / 2 - 20)
- abort ();
-
- sprintf (buf, "M%x,%x:", memaddr, len);
+ /* FIXME-32x64: Need a version of print_address_numeric which puts the
+ result in a buffer like sprintf. */
+ sprintf (buf, "M%lx,%x:", (unsigned long) memaddr, len);
/* We send target system values byte by byte, in increasing byte addresses,
each byte encoded as two hex characters. */
static int
remote_read_bytes (memaddr, myaddr, len)
CORE_ADDR memaddr;
- unsigned char *myaddr;
+ char *myaddr;
int len;
{
char buf[PBUFSIZ];
if (len > PBUFSIZ / 2 - 1)
abort ();
- sprintf (buf, "m%x,%x", memaddr, len);
+ /* FIXME-32x64: Need a version of print_address_numeric which puts the
+ result in a buffer like sprintf. */
+ sprintf (buf, "m%lx,%x", (unsigned long) memaddr, len);
putpkt (buf);
getpkt (buf, 0);
int should_write;
struct target_ops *target; /* ignored */
{
- int xfersize;
- int bytes_xferred;
- int total_xferred = 0;
+ return dcache_xfer_memory (remote_dcache, memaddr, myaddr, len, should_write);
+}
+
+
+#if 0
+/* Enable after 4.12. */
- while (len > 0)
+void
+remote_search (len, data, mask, startaddr, increment, lorange, hirange
+ addr_found, data_found)
+ int len;
+ char *data;
+ char *mask;
+ CORE_ADDR startaddr;
+ int increment;
+ CORE_ADDR lorange;
+ CORE_ADDR hirange;
+ CORE_ADDR *addr_found;
+ char *data_found;
+{
+ if (increment == -4 && len == 4)
{
- if (len > MAXBUFBYTES)
- xfersize = MAXBUFBYTES;
- else
- xfersize = len;
-
- if (should_write)
- bytes_xferred = remote_write_bytes (memaddr, myaddr, xfersize);
- else
- bytes_xferred = remote_read_bytes (memaddr, myaddr, xfersize);
-
- /* If we get an error, we are done xferring. */
- if (bytes_xferred == 0)
- break;
+ long mask_long, data_long;
+ long data_found_long;
+ CORE_ADDR addr_we_found;
+ char buf[PBUFSIZ];
+ long returned_long[2];
+ char *p;
+
+ mask_long = extract_unsigned_integer (mask, len);
+ data_long = extract_unsigned_integer (data, len);
+ sprintf (buf, "t%x:%x,%x", startaddr, data_long, mask_long);
+ putpkt (buf);
+ getpkt (buf, 0);
+ if (buf[0] == '\0')
+ {
+ /* The stub doesn't support the 't' request. We might want to
+ remember this fact, but on the other hand the stub could be
+ switched on us. Maybe we should remember it only until
+ the next "target remote". */
+ generic_search (len, data, mask, startaddr, increment, lorange,
+ hirange, addr_found, data_found);
+ return;
+ }
+
+ if (buf[0] == 'E')
+ /* There is no correspondance between what the remote protocol uses
+ for errors and errno codes. We would like a cleaner way of
+ representing errors (big enough to include errno codes, bfd_error
+ codes, and others). But for now just use EIO. */
+ memory_error (EIO, startaddr);
+ p = buf;
+ addr_we_found = 0;
+ while (*p != '\0' && *p != ',')
+ addr_we_found = (addr_we_found << 4) + fromhex (*p++);
+ if (*p == '\0')
+ error ("Protocol error: short return for search");
+
+ data_found_long = 0;
+ while (*p != '\0' && *p != ',')
+ data_found_long = (data_found_long << 4) + fromhex (*p++);
+ /* Ignore anything after this comma, for future extensions. */
+
+ if (addr_we_found < lorange || addr_we_found >= hirange)
+ {
+ *addr_found = 0;
+ return;
+ }
- memaddr += bytes_xferred;
- myaddr += bytes_xferred;
- len -= bytes_xferred;
- total_xferred += bytes_xferred;
+ *addr_found = addr_we_found;
+ *data_found = store_unsigned_integer (data_we_found, len);
+ return;
}
- return total_xferred;
+ generic_search (len, data, mask, startaddr, increment, lorange,
+ hirange, addr_found, data_found);
}
-
+#endif /* 0 */
+\f
static void
remote_files_info (ignore)
struct target_ops *ignore;
/* Read a single character from the remote end, masking it down to 7 bits. */
static int
-readchar ()
+readchar (timeout)
+ int timeout;
{
int ch;
ch = SERIAL_READCHAR (remote_desc, timeout);
- if (ch < 0)
- return ch;
-
- return ch & 0x7f;
+ switch (ch)
+ {
+ case SERIAL_EOF:
+ error ("Remote connection closed");
+ case SERIAL_ERROR:
+ perror_with_name ("Remote communication error");
+ case SERIAL_TIMEOUT:
+ return ch;
+ default:
+ return ch & 0x7f;
+ }
}
/* Send the command in BUF to the remote machine,
remote_send (buf)
char *buf;
{
-
putpkt (buf);
getpkt (buf, 0);
/* Send a packet to the remote machine, with error checking.
The data of the packet is in BUF. */
-static void
+static int
putpkt (buf)
char *buf;
{
char buf2[PBUFSIZ];
int cnt = strlen (buf);
int ch;
+ int tcount = 0;
char *p;
/* Copy the packet into buffer BUF2, encapsulating it
while (1)
{
- if (sr_get_debug ())
+ int started_error_output = 0;
+
+ if (remote_debug)
{
*p = '\0';
- printf ("Sending packet: %s...", buf2); fflush(stdout);
+ printf_unfiltered ("Sending packet: %s...", buf2);
+ gdb_flush(gdb_stdout);
}
if (SERIAL_WRITE (remote_desc, buf2, p - buf2))
perror_with_name ("putpkt: write failed");
/* read until either a timeout occurs (-2) or '+' is read */
while (1)
{
- ch = readchar ();
+ ch = readchar (remote_timeout);
+
+ if (remote_debug)
+ {
+ switch (ch)
+ {
+ case '+':
+ case SERIAL_TIMEOUT:
+ case '$':
+ if (started_error_output)
+ {
+ putchar_unfiltered ('\n');
+ started_error_output = 0;
+ }
+ }
+ }
switch (ch)
{
case '+':
- if (sr_get_debug ())
- printf("Ack\n");
- return;
+ if (remote_debug)
+ printf_unfiltered("Ack\n");
+ return 1;
case SERIAL_TIMEOUT:
+ tcount ++;
+ if (tcount > 3)
+ return 0;
break; /* Retransmit buffer */
- case SERIAL_ERROR:
- perror_with_name ("putpkt: couldn't read ACK");
- case SERIAL_EOF:
- error ("putpkt: EOF while trying to read ACK");
+ case '$':
+ {
+ char junkbuf[PBUFSIZ];
+
+ /* It's probably an old response, and we're out of sync. Just
+ gobble up the packet and ignore it. */
+ getpkt (junkbuf, 0);
+ continue; /* Now, go look for + */
+ }
default:
- if (sr_get_debug ())
- printf ("%02X %c ", ch&0xFF, ch);
+ if (remote_debug)
+ {
+ if (!started_error_output)
+ {
+ started_error_output = 1;
+ printf_unfiltered ("putpkt: Junk: ");
+ }
+ putchar_unfiltered (ch & 0177);
+ }
continue;
}
break; /* Here to retransmit */
}
+#if 0
+ /* This is wrong. If doing a long backtrace, the user should be
+ able to get out next time we call QUIT, without anything as violent
+ as interrupt_query. If we want to provide a way out of here
+ without getting to the next QUIT, it should be based on hitting
+ ^C twice as in remote_wait. */
if (quit_flag)
{
quit_flag = 0;
interrupt_query ();
}
+#endif
+ }
+}
+
+/* Come here after finding the start of the frame. Collect the rest into BUF,
+ verifying the checksum, length, and handling run-length compression.
+ Returns 0 on any error, 1 on success. */
+
+static int
+read_frame (buf)
+ char *buf;
+{
+ unsigned char csum;
+ char *bp;
+ int c;
+
+ csum = 0;
+ bp = buf;
+
+ while (1)
+ {
+ c = readchar (remote_timeout);
+
+ switch (c)
+ {
+ case SERIAL_TIMEOUT:
+ if (remote_debug)
+ puts_filtered ("Timeout in mid-packet, retrying\n");
+ return 0;
+ case '$':
+ if (remote_debug)
+ puts_filtered ("Saw new packet start in middle of old one\n");
+ return 0; /* Start a new packet, count retries */
+ case '#':
+ {
+ unsigned char pktcsum;
+
+ *bp = '\000';
+
+ pktcsum = fromhex (readchar (remote_timeout)) << 4;
+ pktcsum |= fromhex (readchar (remote_timeout));
+
+ if (csum == pktcsum)
+ return 1;
+
+ if (remote_debug)
+ {
+ printf_filtered ("Bad checksum, sentsum=0x%x, csum=0x%x, buf=",
+ pktcsum, csum);
+ puts_filtered (buf);
+ puts_filtered ("\n");
+ }
+ return 0;
+ }
+ case '*': /* Run length encoding */
+ csum += c;
+ c = readchar (remote_timeout);
+ csum += c;
+ c = c - ' ' + 3; /* Compute repeat count */
+
+
+ if (c > 0 && c < 255 && bp + c - 1 < buf + PBUFSIZ - 1)
+ {
+ memset (bp, *(bp - 1), c);
+ bp += c;
+ continue;
+ }
+
+ *bp = '\0';
+ printf_filtered ("Repeat count %d too large for buffer: ", c);
+ puts_filtered (buf);
+ puts_filtered ("\n");
+ return 0;
+
+ default:
+ if (bp < buf + PBUFSIZ - 1)
+ {
+ *bp++ = c;
+ csum += c;
+ continue;
+ }
+
+ *bp = '\0';
+ puts_filtered ("Remote packet too long: ");
+ puts_filtered (buf);
+ puts_filtered ("\n");
+
+ return 0;
+ }
}
}
int forever;
{
char *bp;
- unsigned char csum;
- int c = 0;
- unsigned char c1, c2;
- int retries = 0;
-#define MAX_RETRIES 10
+ int c;
+ int tries;
+ int timeout;
+ int val;
- while (1)
+ strcpy (buf,"timeout");
+
+ if (forever)
{
- if (quit_flag)
- {
- quit_flag = 0;
- interrupt_query ();
- }
+#ifdef MAINTENANCE_CMDS
+ timeout = watchdog > 0 ? watchdog : -1;
+#else
+ timeout = -1;
+#endif
+ }
+ else
+ timeout = remote_timeout;
+
+#define MAX_TRIES 3
+
+ for (tries = 1; tries <= MAX_TRIES; tries++)
+ {
/* This can loop forever if the remote side sends us characters
continuously, but if it pauses, we'll get a zero from readchar
because of timeout. Then we'll count that as a retry. */
- c = readchar();
- if (c > 0 && c != '$')
- continue;
+ /* Note that we will only wait forever prior to the start of a packet.
+ After that, we expect characters to arrive at a brisk pace. They
+ should show up within remote_timeout intervals. */
- if (c == SERIAL_TIMEOUT)
+ do
{
- if (forever)
- continue;
- if (++retries >= MAX_RETRIES)
- if (sr_get_debug ()) puts_filtered ("Timed out.\n");
- goto out;
- }
-
- if (c == SERIAL_EOF)
- error ("Remote connection closed");
- if (c == SERIAL_ERROR)
- perror_with_name ("Remote communication error");
-
- /* Force csum to be zero here because of possible error retry. */
- csum = 0;
- bp = buf;
+ c = readchar (timeout);
- while (1)
- {
- c = readchar ();
if (c == SERIAL_TIMEOUT)
{
- if (sr_get_debug ())
- puts_filtered ("Timeout in mid-packet, retrying\n");
- goto whole; /* Start a new packet, count retries */
- }
- if (c == '$')
- {
- if (sr_get_debug ())
- puts_filtered ("Saw new packet start in middle of old one\n");
- goto whole; /* Start a new packet, count retries */
+#ifdef MAINTENANCE_CMDS
+ if (forever) /* Watchdog went off. Kill the target. */
+ {
+ target_mourn_inferior ();
+ error ("Watchdog has expired. Target detached.\n");
+ }
+#endif
+ if (remote_debug)
+ puts_filtered ("Timed out.\n");
+ goto retry;
}
- if (c == '#')
- break;
- if (bp >= buf+PBUFSIZ-1)
- {
- *bp = '\0';
- puts_filtered ("Remote packet too long: ");
- puts_filtered (buf);
- puts_filtered ("\n");
- goto whole;
- }
- *bp++ = c;
- csum += c;
}
- *bp = 0;
+ while (c != '$');
- c1 = fromhex (readchar ());
- c2 = fromhex (readchar ());
- if ((csum & 0xff) == (c1 << 4) + c2)
- break;
- printf_filtered ("Bad checksum, sentsum=0x%x, csum=0x%x, buf=",
- (c1 << 4) + c2, csum & 0xff);
- puts_filtered (buf);
- puts_filtered ("\n");
+ /* We've found the start of a packet, now collect the data. */
- /* Try the whole thing again. */
-whole:
- if (++retries < MAX_RETRIES)
- {
- SERIAL_WRITE (remote_desc, "-", 1);
- }
- else
+ val = read_frame (buf);
+
+ if (val == 1)
{
- printf ("Ignoring packet error, continuing...\n");
- break;
+ if (remote_debug)
+ fprintf_unfiltered (gdb_stderr, "Packet received: %s\n", buf);
+ SERIAL_WRITE (remote_desc, "+", 1);
+ return;
}
+
+ /* Try the whole thing again. */
+ retry:
+ SERIAL_WRITE (remote_desc, "-", 1);
}
-out:
+ /* 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);
-
- if (sr_get_debug ())
- fprintf (stderr,"Packet received: %s\n", buf);
}
\f
static void
remote_kill ()
{
- putpkt ("k");
+ /* 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 (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 ();
remote_mourn, /* to_mourn_inferior */
0, /* to_can_run */
0, /* to_notice_signals */
+ remote_thread_alive, /* to_thread_alive */
+ 0, /* to_stop */
process_stratum, /* to_stratum */
NULL, /* to_next */
1, /* to_has_all_memory */
{
add_target (&remote_ops);
}
-#endif