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
+ console output Otext Send text to stdout. Only comes from
+ remote target.
Responses can be run-length encoded to save space. A '*' means that
- the next two characters are hex digits giving a repeat count which
+ the next character is an ASCII encoding giving a repeat count which
stands for that many repititions of the character preceding the '*'.
- Note that this means that responses cannot contain '*'. Example:
- "0*03" means the same as "0000". */
+ 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 "dcache.h"
-#if !defined(DONT_USE_REMOTE)
#ifdef USG
#include <sys/types.h>
#endif
remote_send PARAMS ((char *buf));
static int
-readchar PARAMS ((void));
+readchar PARAMS ((int timeout));
static int remote_wait PARAMS ((int pid, struct target_waitstatus *status));
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;
+static int remote_timeout = 2;
#if 0
int icache;
static void
get_offsets ()
{
- unsigned char buf [PBUFSIZ];
+ unsigned char buf[PBUFSIZ];
int nvals;
CORE_ADDR text_addr, data_addr, bss_addr;
struct section_offsets *offs;
putpkt ("qOffsets");
- getpkt (buf, 1);
+ 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);
stub to another, we can (if the target is closed and reopened) cope. */
stub_supports_P = 1;
+ /* 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). */
return a - 'a' + 10;
else
error ("Reply contains invalid hex digit");
- return -1;
}
/* Convert number NIB to a hex digit. */
if (siggnal)
{
- char *name;
target_terminal_ours_for_output ();
printf_filtered
("Can't send signals to a remote system. %s not sent.\n",
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];
+ 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];
- /* 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
- */
+ /* 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 */
+ p = &buf[3]; /* after Txx */
- while (*p)
- {
- unsigned char *p1;
+ while (*p)
+ {
+ unsigned char *p1;
- regno = strtol (p, &p1, 16); /* Read the register number */
+ 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);
+ if (p1 == p)
+ warning ("Remote sent badly formed register number: %s\nPacket: '%s'\n",
+ p1, buf);
- p = p1;
+ p = p1;
- if (*p++ != ':')
- warning ("Malformed packet (missing colon): %s\nPacket: '%s'\n",
- p, buf);
+ if (*p++ != ':')
+ warning ("Malformed packet (missing colon): %s\nPacket: '%s'\n",
+ p, buf);
- if (regno >= NUM_REGS)
- warning ("Remote sent bad register number %d: %s\nPacket: '%s'\n",
- regno, p, buf);
+ if (regno >= NUM_REGS)
+ warning ("Remote sent bad register number %d: %s\nPacket: '%s'\n",
+ regno, p, buf);
- 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;
- }
+ 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;
+ }
- if (*p++ != ';')
- warning ("Remote register badly formatted: %s", buf);
+ if (*p++ != ';')
+ warning ("Remote register badly formatted: %s", buf);
- supply_register (regno, regs);
- }
- break;
- }
- else if (buf[0] == 'W')
- {
- /* The remote process exited. */
- status->kind = TARGET_WAITKIND_EXITED;
- status->value.integer = (fromhex (buf[1]) << 4) + fromhex (buf[2]);
- return 0;
+ supply_register (regno, regs);
+ }
+ }
+ /* 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])));
+
+ return inferior_pid;
+ case 'W': /* Target exited */
+ {
+ /* The remote process exited. */
+ status->kind = TARGET_WAITKIND_EXITED;
+ status->value.integer = (fromhex (buf[1]) << 4) + fromhex (buf[2]);
+ return inferior_pid;
+ }
+ case 'O': /* Console output */
+ fputs_filtered (buf + 1, gdb_stdout);
+ continue;
+ default:
+ warning ("Invalid remote reply: %s", buf);
+ continue;
}
- else if (buf[0] == 'S')
- break;
- else
- warning ("Invalid remote reply: %s", buf);
}
-
- status->kind = TARGET_WAITKIND_STOPPED;
- status->value.sig = (enum target_signal)
- (((fromhex (buf[1])) << 4) + (fromhex (buf[2])));
-
- return 0;
+ return inferior_pid;
}
/* Number of bytes of registers this stub implements. */
int i;
char *p;
- /* FIXME-32x64: Need a version of print_address_numeric which doesn't
- set use_local (and also puts the result in a buffer like sprintf). */
+ /* 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,
if (len > PBUFSIZ / 2 - 1)
abort ();
- /* FIXME-32x64: Need a version of print_address_numeric which doesn't
- set use_local (and also puts the result in a buffer like sprintf). */
+ /* 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);
/* 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,
/* read until either a timeout occurs (-2) or '+' is read */
while (1)
{
- ch = readchar ();
+ ch = readchar (remote_timeout);
if (remote_debug)
{
{
case '+':
case SERIAL_TIMEOUT:
- case SERIAL_ERROR:
- case SERIAL_EOF:
case '$':
if (started_error_output)
{
return;
case SERIAL_TIMEOUT:
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 '$':
{
unsigned char junkbuf[PBUFSIZ];
}
}
+/* 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;
+
+ 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 (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;
+ }
+ }
+}
+
/* Read a packet from the remote machine, with error checking,
and store it in BUF. BUF is expected to be of size PBUFSIZ.
If FOREVER, wait forever rather than timing out; this is used
while the target is executing user code. */
static void
-getpkt (retbuf, forever)
- char *retbuf;
+getpkt (buf, forever)
+ char *buf;
int forever;
{
char *bp;
- unsigned char csum;
- int c = 0;
- unsigned char c1, c2;
- int retries = 0;
- char buf[PBUFSIZ];
+ int c;
+ int tries;
+ int timeout;
+ int val;
-#define MAX_RETRIES 10
+ if (forever)
+ timeout = -1;
+ else
+ timeout = remote_timeout;
- while (1)
- {
-#if 0
- /* This is wrong. If doing a long backtrace, the user should be
- able to get out time next 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
+#define MAX_TRIES 10
+ 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 (remote_debug)
- puts_filtered ("Timed out.\n");
- goto whole;
- }
-
- if (c == SERIAL_EOF)
- error ("Remote connection closed");
- if (c == SERIAL_ERROR)
- perror_with_name ("Remote communication error");
+ c = readchar (timeout);
- /* Force csum to be zero here because of possible error retry. */
- csum = 0;
- bp = buf;
-
- while (1)
- {
- c = readchar ();
if (c == SERIAL_TIMEOUT)
{
if (remote_debug)
- puts_filtered ("Timeout in mid-packet, retrying\n");
- goto whole; /* Start a new packet, count retries */
- }
- if (c == '$')
- {
- if (remote_debug)
- puts_filtered ("Saw new packet start in middle of old one\n");
- goto whole; /* Start a new packet, count retries */
+ 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_unfiltered ("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);
}
- /* Deal with run-length encoding. */
- {
- char *src = buf;
- char *dest = retbuf;
- int i;
- int repeat;
- do {
- if (*src == '*')
- {
- if (src[1] == '\0' || src[2] == '\0')
- {
- if (remote_debug)
- puts_filtered ("Packet too short, retrying\n");
- goto whole;
- }
- repeat = (fromhex (src[1]) << 4) + fromhex (src[2]);
- for (i = 0; i < repeat; ++i)
- {
- *dest++ = src[-1];
- }
- src += 2;
- }
- else
- {
- *dest++ = *src;
- }
- } while (*src++ != '\0');
- }
+ /* 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 (remote_debug)
- fprintf_unfiltered (gdb_stderr,"Packet received: %s\n", buf);
}
\f
static void
NULL, /* sections_end */
OPS_MAGIC /* to_magic */
};
-#endif /* Use remote. */
void
_initialize_remote ()
{
-#if !defined(DONT_USE_REMOTE)
add_target (&remote_ops);
-#endif
}