📄 remote.c
字号:
int len;
{
unsigned char *buf = alloca (PBUFSIZ);
int max_buf_size; /* Max size of packet output buffer */
int origlen;
extern int verbose;
/* Verify that the target can support a binary download */
check_binary_download (memaddr);
/* Chop the transfer down if necessary */
max_buf_size = min (remote_write_size, PBUFSIZ);
if (remote_register_buf_size != 0)
max_buf_size = min (max_buf_size, remote_register_buf_size);
/* Subtract header overhead from max payload size - $M<memaddr>,<len>:#nn */
max_buf_size -= 2 + hexnumlen (memaddr + len - 1) + 1 + hexnumlen (len) + 4;
origlen = len;
while (len > 0)
{
unsigned char *p, *plen;
int todo;
int i;
/* construct "M"<memaddr>","<len>":" */
/* sprintf (buf, "M%lx,%x:", (unsigned long) memaddr, todo); */
memaddr = remote_address_masked (memaddr);
p = buf;
if (remote_binary_download)
{
*p++ = 'X';
todo = min (len, max_buf_size);
}
else
{
*p++ = 'M';
todo = min (len, max_buf_size / 2); /* num bytes that will fit */
}
p += hexnumstr ((char *)p, (ULONGEST) memaddr);
*p++ = ',';
plen = p; /* remember where len field goes */
p += hexnumstr ((char *)p, (ULONGEST) todo);
*p++ = ':';
*p = '\0';
/* We send target system values byte by byte, in increasing byte
addresses, each byte encoded as two hex characters (or one
binary character). */
if (remote_binary_download)
{
int escaped = 0;
for (i = 0;
(i < todo) && (i + escaped) < (max_buf_size - 2);
i++)
{
switch (myaddr[i] & 0xff)
{
case '$':
case '#':
case 0x7d:
/* These must be escaped */
escaped++;
*p++ = 0x7d;
*p++ = (myaddr[i] & 0xff) ^ 0x20;
break;
default:
*p++ = myaddr[i] & 0xff;
break;
}
}
if (i < todo)
{
/* Escape chars have filled up the buffer prematurely,
and we have actually sent fewer bytes than planned.
Fix-up the length field of the packet. */
/* FIXME: will fail if new len is a shorter string than
old len. */
plen += hexnumstr ((char *)plen, (ULONGEST) i);
*plen++ = ':';
}
}
else
{
for (i = 0; i < todo; i++)
{
*p++ = tohex ((myaddr[i] >> 4) & 0xf);
*p++ = tohex (myaddr[i] & 0xf);
}
*p = '\0';
}
putpkt_binary ((char *)buf, (int) (p - buf));
getpkt ((char *)buf, 0);
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 return EIO. */
errno = EIO;
return 0;
}
/* Increment by i, not by todo, in case escape chars
caused us to send fewer bytes than we'd planned. */
myaddr += i;
memaddr += i;
len -= i;
if (verbose)
putc('.', stderr);
}
return origlen;
}
/* Stuff for dealing with the packets which are part of this protocol.
See comment at top of file for details. */
/* Read a single character from the remote end, masking it down to 7 bits. */
static int
readchar (int timeout)
{
int ch;
ch = SERIAL_READCHAR (remote_desc, timeout);
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;
}
}
static int
putpkt (buf)
char *buf;
{
return putpkt_binary (buf, strlen (buf));
}
/* Send a packet to the remote machine, with error checking. The data
of the packet is in BUF. The string in BUF can be at most PBUFSIZ - 5
to account for the $, # and checksum, and for a possible /0 if we are
debugging (remote_debug) and want to print the sent packet as a string */
static int
putpkt_binary (buf, cnt)
char *buf;
int cnt;
{
int i;
unsigned char csum = 0;
char *buf2 = alloca (PBUFSIZ);
char *junkbuf = alloca (PBUFSIZ);
int ch;
int tcount = 0;
char *p;
/* Copy the packet into buffer BUF2, encapsulating it
and giving it a checksum. */
if (cnt > BUFSIZ - 5) /* Prosanity check */
abort ();
p = buf2;
*p++ = '$';
for (i = 0; i < cnt; i++)
{
csum += buf[i];
*p++ = buf[i];
}
*p++ = '#';
*p++ = tohex ((csum >> 4) & 0xf);
*p++ = tohex (csum & 0xf);
/* Send it over and over until we get a positive ack. */
while (1)
{
int started_error_output = 0;
if (remote_debug)
{
*p = '\0';
fprintf_unfiltered (gdb_stdlog, "Sending packet: ");
fputstrn_unfiltered (buf2, p - buf2, 0, gdb_stdlog);
fprintf_unfiltered (gdb_stdlog, "...");
gdb_flush (gdb_stdlog);
}
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 (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 (remote_debug)
fprintf_unfiltered (gdb_stdlog, "Ack\n");
return 1;
case SERIAL_TIMEOUT:
tcount++;
if (tcount > 3)
return 0;
break; /* Retransmit buffer */
case '$':
{
/* 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 (remote_debug)
{
if (!started_error_output)
{
started_error_output = 1;
fprintf_unfiltered (gdb_stdlog, "putpkt: Junk: ");
}
fputc_unfiltered (ch & 0177, gdb_stdlog);
}
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 (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)
fputs_filtered ("Timeout in mid-packet, retrying\n", gdb_stdlog);
return 0;
case '$':
if (remote_debug)
fputs_filtered ("Saw new packet start in middle of old one\n",
gdb_stdlog);
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)
{
fprintf_filtered (gdb_stdlog,
"Bad checksum, sentsum=0x%x, csum=0x%x, buf=",
pktcsum, csum);
fputs_filtered (buf, gdb_stdlog);
fputs_filtered ("\n", gdb_stdlog);
}
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;
}
}
}
/* 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 (buf, forever)
char *buf;
int forever;
{
int c;
int tries;
int timeout;
int val;
strcpy (buf, "timeout");
if (forever)
{
timeout = watchdog > 0 ? watchdog : -1;
}
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. */
/* 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. */
do
{
c = readchar (timeout);
if (c == SERIAL_TIMEOUT)
{
if (forever) /* Watchdog went off. Kill the target. */
{
target_mourn_inferior ();
error ("Watchdog has expired. Target detached.\n");
}
if (remote_debug)
fputs_filtered ("Timed out.\n", gdb_stdlog);
goto retry;
}
}
while (c != '$');
/* We've found the start of a packet, now collect the data. */
val = read_frame (buf);
if (val == 1)
{
if (remote_debug)
{
fprintf_unfiltered (gdb_stdlog, "Packet received: ");
fputstr_unfiltered (buf, 0, gdb_stdlog);
fprintf_unfiltered (gdb_stdlog, "\n");
}
SERIAL_WRITE (remote_desc, "+", 1);
return;
}
/* Try the whole thing again. */
retry:
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);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -