|  | /* | 
|  | * taken from gdb/remote.c | 
|  | * | 
|  | * I am only interested in the write to memory stuff - everything else | 
|  | * has been ripped out | 
|  | * | 
|  | * all the copyright notices etc have been left in | 
|  | */ | 
|  |  | 
|  | /* enough so that it will compile */ | 
|  | #include <stdio.h> | 
|  | #include <stdlib.h> | 
|  | #include <string.h> | 
|  | #include <errno.h> | 
|  |  | 
|  | /*nicked from gcc..*/ | 
|  |  | 
|  | #ifndef alloca | 
|  | #ifdef __GNUC__ | 
|  | #define alloca __builtin_alloca | 
|  | #else /* not GNU C.  */ | 
|  | #if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) | 
|  | #include <alloca.h> | 
|  | #else /* not sparc */ | 
|  | #if defined (MSDOS) && !defined (__TURBOC__) | 
|  | #include <malloc.h> | 
|  | #else /* not MSDOS, or __TURBOC__ */ | 
|  | #if defined(_AIX) | 
|  | #include <malloc.h> | 
|  | #pragma alloca | 
|  | #else /* not MSDOS, __TURBOC__, or _AIX */ | 
|  | #ifdef __hpux | 
|  | #endif /* __hpux */ | 
|  | #endif /* not _AIX */ | 
|  | #endif /* not MSDOS, or __TURBOC__ */ | 
|  | #endif /* not sparc.  */ | 
|  | #endif /* not GNU C.  */ | 
|  | #ifdef __cplusplus | 
|  | extern "C" { | 
|  | #endif | 
|  | void* alloca(size_t); | 
|  | #ifdef __cplusplus | 
|  | } | 
|  | #endif | 
|  | #endif /* alloca not defined.  */ | 
|  |  | 
|  |  | 
|  | #include "serial.h" | 
|  | #include "error.h" | 
|  | #include "remote.h" | 
|  | #define REGISTER_BYTES 0 | 
|  | #define fprintf_unfiltered fprintf | 
|  | #define fprintf_filtered fprintf | 
|  | #define fputs_unfiltered fputs | 
|  | #define fputs_filtered fputs | 
|  | #define fputc_unfiltered fputc | 
|  | #define fputc_filtered fputc | 
|  | #define printf_unfiltered printf | 
|  | #define printf_filtered printf | 
|  | #define puts_unfiltered puts | 
|  | #define puts_filtered puts | 
|  | #define putchar_unfiltered putchar | 
|  | #define putchar_filtered putchar | 
|  | #define fputstr_unfiltered(a,b,c) fputs((a), (c)) | 
|  | #define gdb_stdlog stderr | 
|  | #define SERIAL_READCHAR(fd,timo)	serialreadchar((fd), (timo)) | 
|  | #define SERIAL_WRITE(fd, addr, len)	serialwrite((fd), (addr), (len)) | 
|  | #define error Error | 
|  | #define perror_with_name Perror | 
|  | #define gdb_flush fflush | 
|  | #define max(a,b) (((a)>(b))?(a):(b)) | 
|  | #define min(a,b) (((a)<(b))?(a):(b)) | 
|  | #define target_mourn_inferior() {} | 
|  | #define ULONGEST unsigned long | 
|  | #define CORE_ADDR unsigned long | 
|  |  | 
|  | static int putpkt (char *); | 
|  | static int putpkt_binary(char *, int); | 
|  | static void getpkt (char *, int); | 
|  |  | 
|  | static int remote_debug = 0, remote_register_buf_size = 0, watchdog = 0; | 
|  |  | 
|  | int remote_desc = -1, remote_timeout = 10; | 
|  |  | 
|  | static void | 
|  | fputstrn_unfiltered(char *s, int n, int x, FILE *fp) | 
|  | { | 
|  | while (n-- > 0) | 
|  | fputc(*s++, fp); | 
|  | } | 
|  |  | 
|  | void | 
|  | remote_reset(void) | 
|  | { | 
|  | SERIAL_WRITE(remote_desc, "+", 1); | 
|  | } | 
|  |  | 
|  | void | 
|  | remote_continue(void) | 
|  | { | 
|  | putpkt("c"); | 
|  | } | 
|  |  | 
|  | /* Remote target communications for serial-line targets in custom GDB protocol | 
|  | Copyright 1988, 91, 92, 93, 94, 95, 96, 97, 98, 1999 | 
|  | Free Software Foundation, Inc. | 
|  |  | 
|  | This file is part of GDB. | 
|  |  | 
|  | This program is free software; you can redistribute it and/or modify | 
|  | it under the terms of the GNU General Public License as published by | 
|  | the Free Software Foundation; either version 2 of the License, or | 
|  | (at your option) any later version. | 
|  |  | 
|  | This program is distributed in the hope that it will be useful, | 
|  | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | GNU General Public License for more details. | 
|  |  | 
|  | You should have received a copy of the GNU General Public License | 
|  | along with this program; if not, write to the Free Software | 
|  | Foundation, Inc., 59 Temple Place - Suite 330, | 
|  | Boston, MA 02111-1307, USA.  */ | 
|  | /* *INDENT-OFF* */ | 
|  | /* Remote communication protocol. | 
|  |  | 
|  | A debug packet whose contents are <data> | 
|  | is encapsulated for transmission in the form: | 
|  |  | 
|  | $ <data> # CSUM1 CSUM2 | 
|  |  | 
|  | <data> must be ASCII alphanumeric and cannot include characters | 
|  | '$' 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. | 
|  | the hex digits 0-9,a-f are used. | 
|  |  | 
|  | Receiver responds with: | 
|  |  | 
|  | +	- if CSUM is correct and ready for next packet | 
|  | -	- if CSUM is incorrect | 
|  |  | 
|  | <data> is as follows: | 
|  | 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. | 
|  | Registers are in the internal order | 
|  | for GDB, and the bytes in a register | 
|  | are in the same order the machine uses. | 
|  | or ENN		for an error. | 
|  |  | 
|  | write regs	GXX..XX		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 | 
|  | if able to read only part of the data. | 
|  | or ENN		NN is errno | 
|  |  | 
|  | write mem	MAA..AA,LLLL:XX..XX | 
|  | AA..AA is address, | 
|  | LLLL is number of bytes, | 
|  | XX..XX is data | 
|  | reply		OK		for success | 
|  | ENN		for an error (this includes the case | 
|  | where only part of the data was | 
|  | written). | 
|  |  | 
|  | write mem       XAA..AA,LLLL:XX..XX | 
|  | (binary)                       AA..AA is address, | 
|  | LLLL is number of bytes, | 
|  | XX..XX is binary data | 
|  | reply           OK              for success | 
|  | ENN             for an error | 
|  |  | 
|  | continue	cAA..AA		AA..AA is address to resume | 
|  | If AA..AA is omitted, | 
|  | resume at same address. | 
|  |  | 
|  | step		sAA..AA		AA..AA is address to resume | 
|  | If AA..AA is omitted, | 
|  | resume at same address. | 
|  |  | 
|  | continue with	Csig;AA..AA	Continue with signal sig (hex signal | 
|  | signal				number).  If ;AA..AA is omitted, | 
|  | resume at same address. | 
|  |  | 
|  | step with	Ssig;AA..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 | 
|  | signal number. | 
|  |  | 
|  | detach          D               Reply OK. | 
|  |  | 
|  | There is no immediate reply to step or cont. | 
|  | The reply comes when the machine stops. | 
|  | It is		SAA		AA is the signal number. | 
|  |  | 
|  | or...		TAAn...:r...;n...:r...;n...:r...; | 
|  | AA = signal number | 
|  | 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...		XAA		The process terminated with signal | 
|  | AA. | 
|  | or (obsolete)	NAA;tttttttt;dddddddd;bbbbbbbb | 
|  | AA = signal number | 
|  | tttttttt = address of symbol "_start" | 
|  | dddddddd = base of data section | 
|  | bbbbbbbb = base of bss  section. | 
|  | Note: only used by Cisco Systems | 
|  | targets.  The difference between this | 
|  | reply and the "qOffsets" query is that | 
|  | the 'N' packet may arrive spontaneously | 
|  | whereas the 'qOffsets' is a query | 
|  | initiated by the host debugger. | 
|  | or...           OXX..XX	XX..XX  is hex encoding of ASCII data. This | 
|  | can happen at any time while the | 
|  | program is running and the debugger | 
|  | should continue to wait for | 
|  | 'W', 'T', etc. | 
|  |  | 
|  | thread alive	TXX		Find out if the thread XX is alive. | 
|  | reply		OK		thread is still alive | 
|  | ENN		thread is dead | 
|  |  | 
|  | remote restart	RXX		Restart the remote server | 
|  |  | 
|  | extended ops	!		Use the extended remote protocol. | 
|  | Sticky -- only needs to be set once. | 
|  |  | 
|  | kill request	k | 
|  |  | 
|  | toggle debug	d		toggle debug flag (see 386 & 68k stubs) | 
|  | reset		r		reset -- see sparc stub. | 
|  | reserved	<other>		On other requests, the stub should | 
|  | ignore the request and send an empty | 
|  | response ($#<checksum>).  This way | 
|  | 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".  */ | 
|  | /* *INDENT-ON* */ | 
|  |  | 
|  | /* This variable (available to the user via "set remotebinarydownload") | 
|  | dictates whether downloads are sent in binary (via the 'X' packet). | 
|  | We assume that the stub can, and attempt to do it. This will be cleared if | 
|  | the stub does not understand it. This switch is still needed, though | 
|  | in cases when the packet is supported in the stub, but the connection | 
|  | does not allow it (i.e., 7-bit serial connection only). */ | 
|  | static int remote_binary_download = 1; | 
|  |  | 
|  | /* Have we already checked whether binary downloads work? */ | 
|  | static int remote_binary_checked; | 
|  |  | 
|  | /* 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(N) (((N)-32)/2) | 
|  |  | 
|  | /* 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).  */ | 
|  | /* Round up PBUFSIZ to hold all the registers, at least.  */ | 
|  | #define	PBUFSIZ ((REGISTER_BYTES > MAXBUFBYTES (400)) \ | 
|  | ? (REGISTER_BYTES * 2 + 32) \ | 
|  | : 400) | 
|  |  | 
|  |  | 
|  | /* This variable sets the number of bytes to be written to the target | 
|  | in a single packet.  Normally PBUFSIZ is satisfactory, but some | 
|  | targets need smaller values (perhaps because the receiving end | 
|  | is slow).  */ | 
|  |  | 
|  | static int remote_write_size = 0x7fffffff; | 
|  |  | 
|  | /* This variable sets the number of bits in an address that are to be | 
|  | sent in a memory ("M" or "m") packet.  Normally, after stripping | 
|  | leading zeros, the entire address would be sent. This variable | 
|  | restricts the address to REMOTE_ADDRESS_SIZE bits.  HISTORY: The | 
|  | initial implementation of remote.c restricted the address sent in | 
|  | memory packets to ``host::sizeof long'' bytes - (typically 32 | 
|  | bits).  Consequently, for 64 bit targets, the upper 32 bits of an | 
|  | address was never sent.  Since fixing this bug may cause a break in | 
|  | some remote targets this variable is principly provided to | 
|  | facilitate backward compatibility. */ | 
|  |  | 
|  | static int remote_address_size; | 
|  |  | 
|  | /* Convert hex digit A to a number.  */ | 
|  |  | 
|  | static int | 
|  | fromhex (int a) | 
|  | { | 
|  | if (a >= '0' && a <= '9') | 
|  | return a - '0'; | 
|  | else if (a >= 'a' && a <= 'f') | 
|  | return a - 'a' + 10; | 
|  | else if (a >= 'A' && a <= 'F') | 
|  | return a - 'A' + 10; | 
|  | else { | 
|  | error ("Reply contains invalid hex digit %d", a); | 
|  | return -1; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Convert number NIB to a hex digit.  */ | 
|  |  | 
|  | static int | 
|  | tohex (int nib) | 
|  | { | 
|  | if (nib < 10) | 
|  | return '0' + nib; | 
|  | else | 
|  | return 'a' + nib - 10; | 
|  | } | 
|  |  | 
|  | /* Return the number of hex digits in num.  */ | 
|  |  | 
|  | static int | 
|  | hexnumlen (ULONGEST num) | 
|  | { | 
|  | int i; | 
|  |  | 
|  | for (i = 0; num != 0; i++) | 
|  | num >>= 4; | 
|  |  | 
|  | return max (i, 1); | 
|  | } | 
|  |  | 
|  | /* Set BUF to the hex digits representing NUM.  */ | 
|  |  | 
|  | static int | 
|  | hexnumstr (char *buf, ULONGEST num) | 
|  | { | 
|  | int i; | 
|  | int len = hexnumlen (num); | 
|  |  | 
|  | buf[len] = '\0'; | 
|  |  | 
|  | for (i = len - 1; i >= 0; i--) | 
|  | { | 
|  | buf[i] = "0123456789abcdef"[(num & 0xf)]; | 
|  | num >>= 4; | 
|  | } | 
|  |  | 
|  | return len; | 
|  | } | 
|  |  | 
|  | /* Mask all but the least significant REMOTE_ADDRESS_SIZE bits. */ | 
|  |  | 
|  | static CORE_ADDR | 
|  | remote_address_masked (CORE_ADDR addr) | 
|  | { | 
|  | if (remote_address_size > 0 | 
|  | && remote_address_size < (sizeof (ULONGEST) * 8)) | 
|  | { | 
|  | /* Only create a mask when that mask can safely be constructed | 
|  | in a ULONGEST variable. */ | 
|  | ULONGEST mask = 1; | 
|  | mask = (mask << remote_address_size) - 1; | 
|  | addr &= mask; | 
|  | } | 
|  | return addr; | 
|  | } | 
|  |  | 
|  | /* Determine whether the remote target supports binary downloading. | 
|  | This is accomplished by sending a no-op memory write of zero length | 
|  | to the target at the specified address. It does not suffice to send | 
|  | the whole packet, since many stubs strip the eighth bit and subsequently | 
|  | compute a wrong checksum, which causes real havoc with remote_write_bytes. | 
|  |  | 
|  | NOTE: This can still lose if the serial line is not eight-bit clean. In | 
|  | cases like this, the user should clear "remotebinarydownload". */ | 
|  | static void | 
|  | check_binary_download (CORE_ADDR addr) | 
|  | { | 
|  | if (remote_binary_download && !remote_binary_checked) | 
|  | { | 
|  | char *buf = alloca (PBUFSIZ); | 
|  | char *p; | 
|  | remote_binary_checked = 1; | 
|  |  | 
|  | p = buf; | 
|  | *p++ = 'X'; | 
|  | p += hexnumstr (p, (ULONGEST) addr); | 
|  | *p++ = ','; | 
|  | p += hexnumstr (p, (ULONGEST) 0); | 
|  | *p++ = ':'; | 
|  | *p = '\0'; | 
|  |  | 
|  | putpkt_binary (buf, (int) (p - buf)); | 
|  | getpkt (buf, 0); | 
|  |  | 
|  | if (buf[0] == '\0') | 
|  | remote_binary_download = 0; | 
|  | } | 
|  |  | 
|  | if (remote_debug) | 
|  | { | 
|  | if (remote_binary_download) | 
|  | fprintf_unfiltered (gdb_stdlog, | 
|  | "binary downloading suppported by target\n"); | 
|  | else | 
|  | fprintf_unfiltered (gdb_stdlog, | 
|  | "binary downloading NOT suppported by target\n"); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Write memory data directly to the remote machine. | 
|  | This does not inform the data cache; the data cache uses this. | 
|  | MEMADDR is the address in the remote memory space. | 
|  | MYADDR is the address of the buffer in our space. | 
|  | LEN is the number of bytes. | 
|  |  | 
|  | Returns number of bytes transferred, or 0 for error.  */ | 
|  |  | 
|  | int | 
|  | remote_write_bytes (memaddr, myaddr, len) | 
|  | CORE_ADDR memaddr; | 
|  | char *myaddr; | 
|  | 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); | 
|  | } |