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]

[rfc/rfa] [3/4] SPU enhancements: gdbserver support


Hello,

this patch, implemented by Markus Deuling, extends TARGET_OBJECT_SPU
support to remote gdbserver debugging.

This is done by extended the remote protocol by two new packet types,
qXfer:spu:read and qXfer:spu:write.  In addition, the patch contains
the following changes to remote packet support:

- It adds a "length" argument to qXfer::write type packets.  This is
  to make parsing of the packet easier, and to bring it in line with
  the 'X' packet format.  (It also provides a bit of extra redundancy
  to detect transmission problems.)

- The remote_read_qxfer attempts to cache received end-of-object
  packets.  However, this is a problem for some spufs objects as
  they can start out with no content (length zero), and acquire
  actual content later on.  If remote_read_qxfer has already cache
  an end-of-object at lenght zero, future re-reads of the object
  will always return zero even if the object by now has actual
  content.  To fix this we've added a CACHEABLE flag to the
  function and use it to disable the cache for spufs objects.

Tested on spu-elf.

Eli, are the doc changes OK?

OK to apply?

Bye,
Ulrich


ChangeLog:

	* remote.c (remote_write_qxfer): New function.
	(remote_xfer_partial): Add handling for TARGET_OBJECT_SPU.
	(remote_read_qxfer): Add cacheable flag.
	(_initialize_remote): Add PACKET_qXfer_spu_read and
	PACKET_qXfer_spu_write.

doc/ChangeLog:

	* gdb.texinfo (General Query Packets): Add length to
	description of qXfer::write packet format.  Document
	qXfer:spu:read and qXfer:spu:write packets and mention
	them under qSupported.	

gdbserver/ChangeLog:

	* server.c (decode_xfer_write): New function.
	(handle_query): Add support for qXfer:spu:read/write packets.
	* spu-low.c (spu_target_ops): Add spu_proc_xfer_spu.
	* target.h (target_ops): Add qxfer_spu.


diff -urNp gdb-orig/gdb/doc/gdb.texinfo gdb-head/gdb/doc/gdb.texinfo
--- gdb-orig/gdb/doc/gdb.texinfo	2007-05-31 18:54:31.000000000 +0200
+++ gdb-head/gdb/doc/gdb.texinfo	2007-06-02 19:32:26.068097686 +0200
@@ -23590,6 +23590,16 @@ These are the currently defined stub fea
 @tab @samp{-}
 @tab Yes
 
+@item @samp{qXfer:spu:read}
+@tab No
+@tab @samp{-}
+@tab Yes
+
+@item @samp{qXfer:spu:write}
+@tab No
+@tab @samp{-}
+@tab Yes
+
 @item @samp{QPassSignals}
 @tab No
 @tab @samp{-}
@@ -23623,6 +23633,14 @@ The remote stub understands the @samp{qX
 The remote stub understands the @samp{qXfer:memory-map:read} packet
 (@pxref{qXfer memory map read}).
 
+@item qXfer:spu:read
+The remote stub understands the @samp{qXfer:spu:read} packet
+(@pxref{qXfer spu read}).
+
+@item qXfer:spu:write
+The remote stub understands the @samp{qXfer:spu:write} packet
+(@pxref{qXfer spu write}).
+
 @item QPassSignals
 The remote stub understands the @samp{QPassSignals} packet
 (@pxref{QPassSignals}).
@@ -23724,6 +23742,19 @@ auxiliary vector}.  Note @var{annex} mus
 This packet is not probed by default; the remote stub must request it,
 by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}).
 
+@item qXfer:spu:read:@var{annex}:@var{offset},@var{length}
+@anchor{qXfer spu read}
+@cindex spufs
+@cindex SPU 
+Read contents of an @code{spufs} file on the target system.  The
+annex specifies which file to read; it must be of the form 
+@var{id}/@var{name}, where @var{id} specifies an SPU context ID
+in the target process, and @var{name} identifes the @code{spufs} file
+in that context to be accessed.
+
+This packet is not probed by default; the remote stub must request it,
+by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}).
+
 @item qXfer:features:read:@var{annex}:@var{offset},@var{length}
 @anchor{qXfer target description read}
 Access the @dfn{target description}.  @xref{Target Descriptions}.  The
@@ -23774,18 +23805,29 @@ An empty reply indicates the @var{object
 the stub, or that the object does not support reading.
 @end table
 
-@item qXfer:@var{object}:write:@var{annex}:@var{offset}:@var{data}@dots{}
+@item qXfer:@var{object}:write:@var{annex}:@var{offset},@var{length}:@var{data}@dots{}
 @cindex write data into object, remote request
-Write uninterpreted bytes into the target's special data area
-identified by the keyword @var{object}, starting at @var{offset} bytes
-into the data.  @samp{@var{data}@dots{}} is the binary-encoded data
-(@pxref{Binary Data}) to be written.  The content and encoding of @var{annex}
-is specific to the object; it can supply additional details about what data
-to access.
-
-No requests of this form are presently in use.  This specification
-serves as a placeholder to document the common format that new
-specific request specifications ought to use.
+Write @var{length} bytes of uninterpreted data into the target's
+special data area identified by the keyword @var{object}, starting
+at @var{offset} bytes into the data.  @samp{@var{data}@dots{}} is
+the binary-encoded data (@pxref{Binary Data}) to be written.  The
+content and encoding of @var{annex} is specific to the object; it can
+supply additional details about what data to access.
+
+@table @samp
+@item qXfer:@var{spu}:write:@var{annex}:@var{offset},@var{length}:@var{data}@dots{}
+@anchor{qXfer spu write}
+@cindex spufs
+@cindex SPU
+Write @var{length} bytes of @var{data} to an @code{spufs} file on 
+the target system.  The annex specifies which file to write; it must 
+be of the form @var{id}/@var{name}, where @var{id} specifies an SPU context ID
+in the target process, and @var{name} identifes the @code{spufs} file
+in that context to be accessed.
+
+This packet is not probed by default; the remote stub must request it,
+by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}).
+@end table
 
 Reply:
 @table @samp
diff -urNp gdb-orig/gdb/gdbserver/server.c gdb-head/gdb/gdbserver/server.c
--- gdb-orig/gdb/gdbserver/server.c	2007-05-16 17:25:22.000000000 +0200
+++ gdb-head/gdb/gdbserver/server.c	2007-06-02 19:32:10.732047243 +0200
@@ -141,13 +141,32 @@ decode_xfer_read (char *buf, char **anne
     return -1;
   *buf++ = 0;
 
-  /* After the read/write marker and annex, qXfer looks like a
+  /* After the read marker and annex, qXfer looks like a
      traditional 'm' packet.  */
   decode_m_packet (buf, ofs, len);
 
   return 0;
 }
 
+/* Decode a qXfer write request.  Return 0 if everything looks OK,
+   or -1 otherwise.  */
+static int
+decode_xfer_write (char *buf, int packet_len, char **annex, CORE_ADDR *ofs, 
+                   unsigned int *len, unsigned char *data)
+{
+  /* Extract and NUL-terminate the annex.  */
+  *annex = buf;
+  while (*buf && *buf != ':')
+    buf++;
+  if (*buf == '\0')
+    return -1;
+  *buf++ = 0;
+
+  /* After the write marker and annex, qXfer looks like
+     a traditional 'X' packet.  */
+  return decode_X_packet (buf, packet_len - strlen (*annex) - 1, ofs, len, data);
+}
+
 /* Write the response to a successful qXfer read.  Returns the
    length of the (binary) data stored in BUF, corresponding
    to as much of DATA/LEN as we could fit.  IS_MORE controls
@@ -255,7 +274,7 @@ monitor_show_help (void)
 
 /* Handle all of the extended 'q' packets.  */
 void
-handle_query (char *own_buf, int *new_packet_len_p)
+handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
 {
   static struct inferior_list_entry *thread_ptr;
 
@@ -314,6 +333,69 @@ handle_query (char *own_buf, int *new_pa
       return;
     }
 
+  if (the_target->qxfer_spu != NULL
+      && strncmp ("qXfer:spu:read:", own_buf, 15) == 0)
+    {
+      char *annex;
+      int n;
+      unsigned int len;
+      CORE_ADDR ofs;
+      unsigned char *spu_buf;
+
+      strcpy (own_buf, "E00");
+      if (decode_xfer_read (own_buf + 15, &annex, &ofs, &len) < 0)
+	  return;
+      if (len > PBUFSIZ - 2)
+	len = PBUFSIZ - 2;
+      spu_buf = malloc (len + 1);
+      if (!spu_buf)
+        return;
+
+      n = (*the_target->qxfer_spu) (annex, spu_buf, NULL, ofs, len + 1);
+      if (n < 0) 
+	write_enn (own_buf);
+      else if (n > len)
+	*new_packet_len_p = write_qxfer_response
+			      (own_buf, spu_buf, len, 1);
+      else 
+	*new_packet_len_p = write_qxfer_response
+			      (own_buf, spu_buf, n, 0);
+
+      free (spu_buf);
+      return;
+    }
+
+  if (the_target->qxfer_spu != NULL
+      && strncmp ("qXfer:spu:write:", own_buf, 16) == 0)
+    {
+      char *annex;
+      int n;
+      unsigned int len;
+      CORE_ADDR ofs;
+      unsigned char *spu_buf;
+
+      strcpy (own_buf, "E00");
+      spu_buf = malloc (packet_len - 15);
+      if (!spu_buf)
+        return;
+      if (decode_xfer_write (own_buf + 16, packet_len - 16, &annex,
+                             &ofs, &len, spu_buf) < 0)
+	{
+	  free (spu_buf);
+	  return;
+	}
+
+      n = (*the_target->qxfer_spu) 
+	(annex, NULL, (unsigned const char *)spu_buf, ofs, len);
+      if (n < 0)
+	write_enn (own_buf);
+      else
+	sprintf (own_buf, "%x", n);
+
+      free (spu_buf);
+      return;
+    }
+
   if (the_target->read_auxv != NULL
       && strncmp ("qXfer:auxv:read:", own_buf, 16) == 0)
     {
@@ -403,6 +485,9 @@ handle_query (char *own_buf, int *new_pa
 
       if (the_target->read_auxv != NULL)
 	strcat (own_buf, ";qXfer:auxv:read+");
+     
+      if (the_target->qxfer_spu != NULL)
+	strcat (own_buf, ";qXfer:spu:read+;qXfer:spu:write+");
 
       if (get_features_xml ("target.xml") != NULL)
 	strcat (own_buf, ";qXfer:features:read+");
@@ -809,7 +894,7 @@ main (int argc, char *argv[])
 	  switch (ch)
 	    {
 	    case 'q':
-	      handle_query (own_buf, &new_packet_len);
+	      handle_query (own_buf, packet_len, &new_packet_len);
 	      break;
 	    case 'Q':
 	      handle_general_set (own_buf);
diff -urNp gdb-orig/gdb/gdbserver/spu-low.c gdb-head/gdb/gdbserver/spu-low.c
--- gdb-orig/gdb/gdbserver/spu-low.c	2007-06-01 22:31:04.000000000 +0200
+++ gdb-head/gdb/gdbserver/spu-low.c	2007-06-02 19:32:10.738046378 +0200
@@ -574,7 +574,6 @@ spu_arch_string (void)
   return "spu";
 }
 
-
 static struct target_ops spu_target_ops = {
   spu_create_inferior,
   spu_attach,
@@ -598,6 +597,7 @@ static struct target_ops spu_target_ops 
   NULL,
   NULL,
   spu_arch_string,
+  spu_proc_xfer_spu,
 };
 
 void
diff -urNp gdb-orig/gdb/gdbserver/target.h gdb-head/gdb/gdbserver/target.h
--- gdb-orig/gdb/gdbserver/target.h	2007-05-10 23:34:34.000000000 +0200
+++ gdb-head/gdb/gdbserver/target.h	2007-06-02 19:32:10.751044505 +0200
@@ -185,6 +185,10 @@ struct target_ops
   /* Return a string identifying the current architecture, or NULL if
      this operation is not supported.  */
   const char *(*arch_string) (void);
+
+   /* Read/Write from/to spufs using qXfer packets.  */
+  int (*qxfer_spu) (const char *annex, unsigned char *readbuf,
+		    unsigned const char *writebuf, CORE_ADDR offset, int len);
 };
 
 extern struct target_ops *the_target;
diff -urNp gdb-orig/gdb/remote.c gdb-head/gdb/remote.c
--- gdb-orig/gdb/remote.c	2007-06-01 18:51:01.000000000 +0200
+++ gdb-head/gdb/remote.c	2007-06-02 19:32:10.810036003 +0200
@@ -907,6 +907,8 @@ enum {
   PACKET_qXfer_auxv,
   PACKET_qXfer_features,
   PACKET_qXfer_memory_map,
+  PACKET_qXfer_spu_read,
+  PACKET_qXfer_spu_write,
   PACKET_qGetTLSAddr,
   PACKET_qSupported,
   PACKET_QPassSignals,
@@ -5517,18 +5519,59 @@ the loaded file\n"));
     printf_filtered (_("No loaded section named '%s'.\n"), args);
 }
 
+/* Write LEN bytes from WRITEBUF into OBJECT_NAME/ANNEX at OFFSET
+   into remote target.  The number of bytes written to the remote
+   target is returned, or -1 for error.  */
+
+static LONGEST
+remote_write_qxfer (struct target_ops *ops, const char *object_name,
+                    const char *annex, const gdb_byte *writebuf, 
+                    ULONGEST offset, LONGEST len, 
+                    struct packet_config *packet)
+{
+  int i, buf_len;
+  ULONGEST n;
+  gdb_byte *wbuf;
+  struct remote_state *rs = get_remote_state ();
+  int max_size = get_memory_write_packet_size (); 
+
+  if (packet->support == PACKET_DISABLE)
+    return -1;
+
+  /* Insert header.  */
+  i = snprintf (rs->buf, max_size, 
+		"qXfer:%s:write:%s:%s,%s:",
+		object_name, annex ? annex : "",
+		phex_nz (offset, sizeof offset),
+		phex_nz (len, sizeof len));
+  max_size -= (i + 1);
+
+  /* Escape as much data as fits into rs->buf.  */
+  buf_len = remote_escape_output 
+    (writebuf, len, (rs->buf + i), &max_size, max_size);
+
+  if (putpkt_binary (rs->buf, i + buf_len) < 0
+      || getpkt_sane (&rs->buf, &rs->buf_size, 0) < 0
+      || packet_ok (rs->buf, packet) != PACKET_OK)
+    return -1;
+
+  unpack_varlen_hex (rs->buf, &n);
+  return n;
+}
+
 /* Read OBJECT_NAME/ANNEX from the remote target using a qXfer packet.
    Data at OFFSET, of up to LEN bytes, is read into READBUF; the
    number of bytes read is returned, or 0 for EOF, or -1 for error.
    The number of bytes read may be less than LEN without indicating an
    EOF.  PACKET is checked and updated to indicate whether the remote
-   target supports this object.  */
+   target supports this object.  If CACHEABLE is set then the packet
+   is cached.  */
 
 static LONGEST
 remote_read_qxfer (struct target_ops *ops, const char *object_name,
 		   const char *annex,
 		   gdb_byte *readbuf, ULONGEST offset, LONGEST len,
-		   struct packet_config *packet)
+		   struct packet_config *packet, int cacheable)
 {
   static char *finished_object;
   static char *finished_annex;
@@ -5591,7 +5634,8 @@ remote_read_qxfer (struct target_ops *op
   /* 'l' is an EOF marker, possibly including a final block of data,
      or possibly empty.  Record it to bypass the next read, if one is
      issued.  */
-  if (rs->buf[0] == 'l')
+  if (rs->buf[0] == 'l'
+      && cacheable)
     {
       finished_object = xstrdup (object_name);
       finished_annex = xstrdup (annex ? annex : "");
@@ -5630,6 +5674,19 @@ remote_xfer_partial (struct target_ops *
 	return -1;
     }
 
+  /* Handle SPU memory using qxfer packets. */
+  if (object == TARGET_OBJECT_SPU)
+    {
+      if (readbuf)
+	return remote_read_qxfer (ops, "spu", annex, readbuf, offset, len,
+				  &remote_protocol_packets
+				    [PACKET_qXfer_spu_read], 0);
+      else
+	return remote_write_qxfer (ops, "spu", annex, writebuf, offset, len,
+				   &remote_protocol_packets
+				     [PACKET_qXfer_spu_write]);
+    }
+
   /* Only handle flash writes.  */
   if (writebuf != NULL)
     {
@@ -5663,22 +5720,21 @@ remote_xfer_partial (struct target_ops *
     case TARGET_OBJECT_AUXV:
       gdb_assert (annex == NULL);
       return remote_read_qxfer (ops, "auxv", annex, readbuf, offset, len,
-				&remote_protocol_packets[PACKET_qXfer_auxv]);
+				&remote_protocol_packets[PACKET_qXfer_auxv], 1);
 
     case TARGET_OBJECT_AVAILABLE_FEATURES:
       return remote_read_qxfer
 	(ops, "features", annex, readbuf, offset, len,
-	 &remote_protocol_packets[PACKET_qXfer_features]);
+	 &remote_protocol_packets[PACKET_qXfer_features], 1);
 
     case TARGET_OBJECT_MEMORY_MAP:
       gdb_assert (annex == NULL);
       return remote_read_qxfer (ops, "memory-map", annex, readbuf, offset, len,
-				&remote_protocol_packets[PACKET_qXfer_memory_map]);
+				&remote_protocol_packets[PACKET_qXfer_memory_map], 1);
 
     default:
       return -1;
     }
-
   /* Note: a zero OFFSET and LEN can be used to query the minimum
      buffer size.  */
   if (offset == 0 && len == 0)
@@ -6540,6 +6596,12 @@ Show the maximum size of the address (in
   add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_memory_map],
 			 "qXfer:memory-map:read", "memory-map", 0);
 
+  add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_spu_read],
+                         "qXfer:spu:read", "read-spu-object", 0);
+
+  add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_spu_write],
+                         "qXfer:spu:write", "write-spu-object", 0);
+
   add_packet_config_cmd (&remote_protocol_packets[PACKET_qGetTLSAddr],
 			 "qGetTLSAddr", "get-thread-local-storage-address",
 			 0);
-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com


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