diff options
| author | wdenk <wdenk> | 2001-04-28 17:59:11 +0000 | 
|---|---|---|
| committer | wdenk <wdenk> | 2001-04-28 17:59:11 +0000 | 
| commit | 4a5b6a356a79123d3fcd780139629213afcedca8 (patch) | |
| tree | a54c1cec31c73462ba2c04fac3318a0990dd21b1 /tools/gdb/remote.c | |
| parent | b631bb9cad6b5553846f508fbfa5ba6362fb0677 (diff) | |
| download | olio-uboot-2014.01-4a5b6a356a79123d3fcd780139629213afcedca8.tar.xz olio-uboot-2014.01-4a5b6a356a79123d3fcd780139629213afcedca8.zip | |
Initial revision
Diffstat (limited to 'tools/gdb/remote.c')
| -rw-r--r-- | tools/gdb/remote.c | 928 | 
1 files changed, 928 insertions, 0 deletions
| diff --git a/tools/gdb/remote.c b/tools/gdb/remote.c new file mode 100644 index 000000000..b8b247021 --- /dev/null +++ b/tools/gdb/remote.c @@ -0,0 +1,928 @@ +/* + * 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); +} |