| /* | 
 |  * 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); | 
 | } |