This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[commit] Implement X packet for gdbserver


I've been meaning to do this for ages.  I had two other reasons
recently to implement the underlying support for binary packets
in gdbserver (file transfer and qXfer), and once I'd done that
it wasn't much work at all to add 'X'.  Tested on x86_64-pc-linux-gnu
and committed.

-- 
Daniel Jacobowitz
CodeSourcery

2006-06-22  Daniel Jacobowitz  <dan@codesourcery.com>

	* remote-utils.c (remote_escape_output, remote_unescape_input): New.
	(putpkt_binary): Renamed from putpkt and adjusted for binary
	data.
	(putpkt): New wrapper for putpkt_binary.
	(readchar): Don't mask off the high bit.
	(decode_X_packet): New function.
	* server.c (main): Call putpkt_binary if a handler sets the packet
	length.  Save the length of the incoming packet.  Handle 'X'.
	* server.h (gdb_byte, remote_escape_output, decode_X_packet): New.

Index: src/gdb/gdbserver/remote-utils.c
===================================================================
--- src.orig/gdb/gdbserver/remote-utils.c	2006-06-22 10:08:27.000000000 -0400
+++ src/gdb/gdbserver/remote-utils.c	2006-06-22 10:23:12.000000000 -0400
@@ -276,17 +276,98 @@ hexify (char *hex, const char *bin, int 
   return i;
 }
 
+/* Convert BUFFER, binary data at least LEN bytes long, into escaped
+   binary data in OUT_BUF.  Set *OUT_LEN to the length of the data
+   encoded in OUT_BUF, and return the number of bytes in OUT_BUF
+   (which may be more than *OUT_LEN due to escape characters).  The
+   total number of bytes in the output buffer will be at most
+   OUT_MAXLEN.  */
+
+int
+remote_escape_output (const gdb_byte *buffer, int len,
+		      gdb_byte *out_buf, int *out_len,
+		      int out_maxlen)
+{
+  int input_index, output_index;
+
+  output_index = 0;
+  for (input_index = 0; input_index < len; input_index++)
+    {
+      gdb_byte b = buffer[input_index];
+
+      if (b == '$' || b == '#' || b == '}' || b == '*')
+	{
+	  /* These must be escaped.  */
+	  if (output_index + 2 > out_maxlen)
+	    break;
+	  out_buf[output_index++] = '}';
+	  out_buf[output_index++] = b ^ 0x20;
+	}
+      else
+	{
+	  if (output_index + 1 > out_maxlen)
+	    break;
+	  out_buf[output_index++] = b;
+	}
+    }
+
+  *out_len = input_index;
+  return output_index;
+}
+
+/* Convert BUFFER, escaped data LEN bytes long, into binary data
+   in OUT_BUF.  Return the number of bytes written to OUT_BUF.
+   Raise an error if the total number of bytes exceeds OUT_MAXLEN.
+
+   This function reverses remote_escape_output.  It allows more
+   escaped characters than that function does, in particular because
+   '*' must be escaped to avoid the run-length encoding processing
+   in reading packets.  */
+
+static int
+remote_unescape_input (const gdb_byte *buffer, int len,
+		       gdb_byte *out_buf, int out_maxlen)
+{
+  int input_index, output_index;
+  int escaped;
+
+  output_index = 0;
+  escaped = 0;
+  for (input_index = 0; input_index < len; input_index++)
+    {
+      gdb_byte b = buffer[input_index];
+
+      if (output_index + 1 > out_maxlen)
+	error ("Received too much data from the target.");
+
+      if (escaped)
+	{
+	  out_buf[output_index++] = b ^ 0x20;
+	  escaped = 0;
+	}
+      else if (b == '}')
+	escaped = 1;
+      else
+	out_buf[output_index++] = b;
+    }
+
+  if (escaped)
+    error ("Unmatched escape character in target response.");
+
+  return output_index;
+}
+
 /* Send a packet to the remote machine, with error checking.
-   The data of the packet is in BUF.  Returns >= 0 on success, -1 otherwise. */
+   The data of the packet is in BUF, and the length of the
+   packet is in CNT.  Returns >= 0 on success, -1 otherwise.  */
 
 int
-putpkt (char *buf)
+putpkt_binary (char *buf, int cnt)
 {
   int i;
   unsigned char csum = 0;
   char *buf2;
   char buf3[1];
-  int cnt = strlen (buf);
   char *p;
 
   buf2 = malloc (PBUFSIZ);
@@ -353,6 +434,17 @@ putpkt (char *buf)
   return 1;			/* Success! */
 }
 
+/* Send a packet to the remote machine, with error checking.  The data
+   of the packet is in BUF, and the packet should be a NUL-terminated
+   string.  Returns >= 0 on success, -1 otherwise.  */
+
+int
+putpkt (char *buf)
+{
+  return putpkt_binary (buf, strlen (buf));
+}
+
+
 /* Come here when we get an input interrupt from the remote side.  This
    interrupt should only be active while we are waiting for the child to do
    something.  About the only thing that should come through is a ^C, which
@@ -439,12 +531,12 @@ disable_async_io (void)
 static int
 readchar (void)
 {
-  static char buf[BUFSIZ];
+  static unsigned char buf[BUFSIZ];
   static int bufcnt = 0;
-  static char *bufp;
+  static unsigned char *bufp;
 
   if (bufcnt-- > 0)
-    return *bufp++ & 0x7f;
+    return *bufp++;
 
   bufcnt = read (remote_desc, buf, sizeof (buf));
 
@@ -755,6 +847,33 @@ decode_M_packet (char *from, CORE_ADDR *
   convert_ascii_to_int (&from[i++], to, *len_ptr);
 }
 
+int
+decode_X_packet (char *from, int packet_len, CORE_ADDR *mem_addr_ptr,
+		 unsigned int *len_ptr, unsigned char *to)
+{
+  int i = 0;
+  char ch;
+  *mem_addr_ptr = *len_ptr = 0;
+
+  while ((ch = from[i++]) != ',')
+    {
+      *mem_addr_ptr = *mem_addr_ptr << 4;
+      *mem_addr_ptr |= fromhex (ch) & 0x0f;
+    }
+
+  while ((ch = from[i++]) != ':')
+    {
+      *len_ptr = *len_ptr << 4;
+      *len_ptr |= fromhex (ch) & 0x0f;
+    }
+
+  if (remote_unescape_input ((const gdb_byte *) &from[i], packet_len - i,
+			     to, *len_ptr) != *len_ptr)
+    return -1;
+
+  return 0;
+}
+
 /* Ask GDB for the address of NAME, and return it in ADDRP if found.
    Returns 1 if the symbol is found, 0 if it is not, -1 on error.  */
 
Index: src/gdb/gdbserver/server.c
===================================================================
--- src.orig/gdb/gdbserver/server.c	2006-06-22 10:08:27.000000000 -0400
+++ src/gdb/gdbserver/server.c	2006-06-22 10:15:41.000000000 -0400
@@ -440,9 +440,16 @@ main (int argc, char *argv[])
 
     restart:
       setjmp (toplevel);
-      while (getpkt (own_buf) > 0)
+      while (1)
 	{
 	  unsigned char sig;
+	  int packet_len;
+	  int new_packet_len = -1;
+
+	  packet_len = getpkt (own_buf);
+	  if (packet_len <= 0)
+	    break;
+
 	  i = 0;
 	  ch = own_buf[i++];
 	  switch (ch)
@@ -547,6 +554,14 @@ main (int argc, char *argv[])
 	      else
 		write_enn (own_buf);
 	      break;
+	    case 'X':
+	      if (decode_X_packet (&own_buf[1], packet_len - 1,
+				   &mem_addr, &len, mem_buf) < 0
+		  || write_inferior_memory (mem_addr, mem_buf, len) != 0)
+		write_enn (own_buf);
+	      else
+		write_ok (own_buf);
+	      break;
 	    case 'C':
 	      convert_ascii_to_int (own_buf + 1, &sig, 1);
 	      if (target_signal_to_host_p (sig))
@@ -714,7 +729,10 @@ main (int argc, char *argv[])
 	      break;
 	    }
 
-	  putpkt (own_buf);
+	  if (new_packet_len != -1)
+	    putpkt_binary (own_buf, new_packet_len);
+	  else
+	    putpkt (own_buf);
 
 	  if (status == 'W')
 	    fprintf (stderr,
Index: src/gdb/gdbserver/server.h
===================================================================
--- src.orig/gdb/gdbserver/server.h	2006-06-22 10:08:27.000000000 -0400
+++ src/gdb/gdbserver/server.h	2006-06-22 10:22:47.000000000 -0400
@@ -57,6 +57,9 @@ extern char *strerror (int);	/* X3.159-1
 #endif
 #endif
 
+/* A type used for binary buffers.  */
+typedef unsigned char gdb_byte;
+
 /* FIXME: This should probably be autoconf'd for.  It's an integer type at
    least the size of a (void *).  */
 typedef long long CORE_ADDR;
@@ -133,6 +136,7 @@ extern jmp_buf toplevel;
 extern int all_symbols_looked_up;
 
 int putpkt (char *buf);
+int putpkt_binary (char *buf, int len);
 int getpkt (char *buf);
 void remote_open (char *name);
 void remote_close (void);
@@ -152,9 +156,14 @@ void decode_m_packet (char *from, CORE_A
 		      unsigned int *len_ptr);
 void decode_M_packet (char *from, CORE_ADDR * mem_addr_ptr,
 		      unsigned int *len_ptr, unsigned char *to);
+int decode_X_packet (char *from, int packet_len, CORE_ADDR * mem_addr_ptr,
+		     unsigned int *len_ptr, unsigned char *to);
 
 int unhexify (char *bin, const char *hex, int count);
 int hexify (char *hex, const char *bin, int count);
+int remote_escape_output (const gdb_byte *buffer, int len,
+			  gdb_byte *out_buf, int *out_len,
+			  int out_maxlen);
 
 int look_up_one_symbol (const char *name, CORE_ADDR *addrp);
 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]