916 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			916 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C
		
	
	
	
// SPDX-License-Identifier: GPL-2.0+
 | 
						|
/*
 | 
						|
 * 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.
 | 
						|
 */
 | 
						|
/* *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);
 | 
						|
}
 |