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]

[PATCH 1/5] Add annex in a async remote notification.


In order to support "Trace:status" notification and other similar
usage (such as "Point:modified", about a tracepoint is modified), we
introduce "annex" in the async remote notification, which is helpful
to give us more details what the contents about in the async remote
notification.  The annex in each notification is optional.  In the
RSP:

  <-- %name:annex1:event
  --> vAck
  <-- annex2:event
  --> vAck
  <-- annex1:event
  --> OK

As we can see above, three events of two annexes (annex1 and annex2)
are sent.

The parsing (receiving rsp packet) and writing (sending rsp packet)
can be done on the annex level.  Each annex has its own routines to
send and parse packet, which is more OO.

Also, annex, instead of notification, is the unit of support and they
(GDB and GDBserver) can exchange their supported annexes by means of
qSupported mechanism, which is done in the next patch.

This patch adds "annex" to both GDB and GDBserver.  I find 'struct
notif_client' and 'struct notif_server' have three fields which can be
shared, so additionally, we move some shared struct to
common/common-notif.h.

The documentation patch was approved by Eli here
<http://sourceware.org/ml/gdb-patches/2013-02/msg00438.html>

gdb:

2013-04-02  Yao Qi  <yao@codesourcery.com>

	* common/common-notif.h: New.
	* Makefile.in (HFILES_NO_SRCDIR): Add "common/common-notif.h".
	* remote-notif.h: Include "common-notif.h".
	(struct notif_client) <name, ack_command, parse>: Remove.
	<base>: New.
	Caller update.
	* remote-notif.c (remote_notif_parse_1): New.
	(remote_notif_ack): Call remote_notif_parse_1.
	(remote_notif_parse): Likewise.
	(struct notif_client_annex): New.
	* remote.c (notif_client_annex_stop): New.

gdb/gdbserver:

2013-04-02  Yao Qi  <yao@codesourcery.com>

	* notif.h: Include "common-notif.h".
	(struct notif_server) <write, ack_name, notif_name>: Remove.
	<base>: New field.
	Caller update.
	(struct notif_annex_event): New.
	* notif.c (notif_write_event_1): New.
	(notif_write_event): Call notif_write_event_1 to write event.
	(notif_push): Likewise.
	* server.c (notif_annex_stop): New.
	(notif_stop): Update.

gdb/doc:

2013-04-02  Yao Qi  <yao@codesourcery.com>

	* gdb.texinfo (Notification Packets): Document 'annex'.
---
 gdb/Makefile.in           |    2 +-
 gdb/common/common-notif.h |   77 +++++++++++++++++++++++++++++++++++++++++++++
 gdb/doc/gdb.texinfo       |   12 +++++--
 gdb/gdbserver/notif.c     |   41 ++++++++++++++++++++----
 gdb/gdbserver/notif.h     |   20 ++++++-----
 gdb/gdbserver/server.c    |    7 +++-
 gdb/remote-notif.c        |   59 +++++++++++++++++++++++++++++-----
 gdb/remote-notif.h        |   13 +------
 gdb/remote.c              |   15 +++++---
 9 files changed, 199 insertions(+), 47 deletions(-)
 create mode 100644 gdb/common/common-notif.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 9bab01c..fa4c302 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -838,7 +838,7 @@ common/common-utils.h common/xml-utils.h common/buffer.h common/ptid.h \
 common/format.h common/host-defs.h utils.h common/queue.h \
 common/linux-osdata.h gdb-dlfcn.h auto-load.h probe.h stap-probe.h \
 gdb_bfd.h sparc-ravenscar-thread.h ppc-ravenscar-thread.h common/linux-btrace.h \
-ctf.h
+ctf.h common/common-notif.h
 
 # Header files that already have srcdir in them, or which are in objdir.
 
diff --git a/gdb/common/common-notif.h b/gdb/common/common-notif.h
new file mode 100644
index 0000000..5e7e9fa
--- /dev/null
+++ b/gdb/common/common-notif.h
@@ -0,0 +1,77 @@
+/* Shared structs of asynchronous remote notification.
+
+   Copyright (C) 2013 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 3 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, see <http://www.gnu.org/licenses/>.  */
+
+struct notif_event;
+#ifndef GDBSERVER
+struct notif_client;
+#endif
+
+/* An annex of a notification.  A notification may or may not have
+   annexes.  */
+
+struct notif_annex
+{
+  /* Name of this annex.  If it is NULL, the notification doesn't have
+     annex, and the field PARSE and SUPPORTED is about the
+     notification this annex belongs to.  For example, notification
+     event "N1:event" doesn't have an annex in the packet, but the
+     notification object still has one instance of 'notif_annex', and
+     its field <name> is NULL.  The field <supported> is about the
+     notification.  */
+  const char *name;
+
+#ifdef GDBSERVER
+  /* Write event EVENT to OWN_BUF.  */
+  void (*write) (struct notif_event *event, char *own_buf);
+#else
+  /* Parse BUF to get the expected event and update EVENT.  This
+     function may throw exception if contents in BUF is not the
+     expected event.  */
+  void (*parse) (struct notif_client *self, char *buf,
+		 struct notif_event *event);
+#endif
+};
+
+/* Iterate over annexes in *NOTIF by increasing INDEX from zero.  */
+
+#define NOTIF_ITER_ANNEX(NOTIF, INDEX)	\
+  for (INDEX = 0; (NOTIF)->annexes[INDEX].name != NULL; INDEX++)
+
+/* Notification *NOTIF has annex or not.  */
+
+#define NOTIF_HAS_ANNEX(NOTIF) ((NOTIF)->annexes[0].name != NULL)
+
+
+/* "Base class" of a notification.  It can be extended in both GDB
+   and GDBserver to represent a type of notification.  */
+
+struct notif_base
+{
+  /* The notification packet, for example, '%Stop'.  Note that '%' is
+     not in 'notif_name'.  */
+  const char *notif_name;
+  /* The name of ack packet, for example, 'vStopped'.  */
+  const char *ack_name;
+
+  /* Annexes the notification has.  The notification may or not have
+     annexes.  Macro 'NOTIF_HAS_ANNEX' is to check notification has
+     annexes, and macro 'NOTIF_ITER_ANNEX' is to iterate over annexes
+     of the notification.  */
+  struct notif_annex *annexes;
+};
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 3b63d01..6cbb8b5 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -38871,13 +38871,15 @@ transmit notifications without fear of confusing older clients.  There
 are no notifications defined for @value{GDBN} to send at the moment, but we
 assume that most older stubs would ignore them, as well.)
 
-Each notification is comprised of three parts:
+Each notification is comprised of four parts:
 @table @samp
-@item @var{name}:@var{event}
+@item @var{name}[:@var{annex}]:@var{event}
 The notification packet is sent by the side that initiates the
 exchange (currently, only the stub does that), with @var{event}
 carrying the specific information about the notification.
-@var{name} is the name of the notification.
+@var{name} is the name of the notification.  The @var{annex} is
+specific to @var{name}; it can supply additional details about
+@var{event}.
 @item @var{ack}
 The acknowledge sent by the other side, usually @value{GDBN}, to
 acknowledge the exchange and request the event.
@@ -38940,15 +38942,17 @@ following example:
 @end smallexample
 
 The following notifications are defined:
-@multitable @columnfractions 0.12 0.12 0.38 0.38
+@multitable @columnfractions 0.10 0.10 0.10 0.35 0.35
 
 @item Notification
 @tab Ack
+@tab Annex
 @tab Event
 @tab Description
 
 @item Stop
 @tab vStopped
+@tab
 @tab @var{reply}.  The @var{reply} has the form of a stop reply, as
 described in @ref{Stop Reply Packets}.  Refer to @ref{Remote Non-Stop},
 for information on how these notifications are acknowledged by 
diff --git a/gdb/gdbserver/notif.c b/gdb/gdbserver/notif.c
index e27746e..9300697 100644
--- a/gdb/gdbserver/notif.c
+++ b/gdb/gdbserver/notif.c
@@ -54,6 +54,30 @@ static struct notif_server *notifs[] =
   &notif_stop,
 };
 
+/* Helper function to write EVENT of NOTIF to buffer OWN_BUF.  */
+
+static void
+notif_write_event_1 (struct notif_base *notif,
+		     struct notif_event *event,
+		     char *own_buf)
+{
+  int annex_index = 0;
+
+  /* If the NOTIF has annexes, extract the annex index from the
+     EVENT and append annex name to OWN_BUF; otherwise, NOTIF
+     doesn't have annex and use slot 0 of annexes for the
+     notification itself.  */
+  if (NOTIF_HAS_ANNEX (notif))
+    {
+      annex_index
+	= ((struct notif_annex_event *) event)->annex_index;
+      sprintf (own_buf, "%s:", notif->annexes[annex_index].name);
+      own_buf += strlen (notif->annexes[annex_index].name) + 1;
+    }
+
+  notif->annexes[annex_index].write (event, own_buf);
+}
+
 /* Write another event or an OK, if there are no more left, to
    OWN_BUF.  */
 
@@ -65,7 +89,8 @@ notif_write_event (struct notif_server *notif, char *own_buf)
       struct notif_event *event
 	= QUEUE_peek (notif_event_p, notif->queue);
 
-      notif->write (event, own_buf);
+      notif_write_event_1 ((struct notif_base *) notif, event,
+			   own_buf);
     }
   else
     write_ok (own_buf);
@@ -84,8 +109,9 @@ handle_notif_ack (char *own_buf, int packet_len)
   for (i = 0; i < ARRAY_SIZE (notifs); i++)
     {
       np = notifs[i];
-      if (strncmp (own_buf, np->ack_name, strlen (np->ack_name)) == 0
-	  && packet_len == strlen (np->ack_name))
+      if (0 == strncmp (own_buf, np->base.ack_name,
+			strlen (np->base.ack_name))
+	  && packet_len == strlen (np->base.ack_name))
 	break;
     }
 
@@ -100,7 +126,7 @@ handle_notif_ack (char *own_buf, int packet_len)
 	= QUEUE_deque (notif_event_p, np->queue);
 
       if (remote_debug)
-	fprintf (stderr, "%s: acking %d\n", np->ack_name,
+	fprintf (stderr, "%s: acking %d\n", np->base.ack_name,
 		 QUEUE_length (notif_event_p, np->queue));
 
       xfree (head);
@@ -120,7 +146,8 @@ notif_event_enque (struct notif_server *notif,
   QUEUE_enque (notif_event_p, notif->queue, event);
 
   if (remote_debug)
-    fprintf (stderr, "pending events: %s %d\n", notif->notif_name,
+    fprintf (stderr, "pending events: %s %d\n",
+	     notif->base.notif_name,
 	     QUEUE_length (notif_event_p, notif->queue));
 
 }
@@ -142,10 +169,10 @@ notif_push (struct notif_server *np, struct notif_event *new_event)
       char buf[PBUFSIZ];
       char *p = buf;
 
-      xsnprintf (p, PBUFSIZ, "%s:", np->notif_name);
+      xsnprintf (p, PBUFSIZ, "%s:", np->base.notif_name);
       p += strlen (p);
 
-      np->write (new_event, p);
+      notif_write_event_1 ((struct notif_base *) np, new_event, p);
       putpkt_notif (buf);
     }
 }
diff --git a/gdb/gdbserver/notif.h b/gdb/gdbserver/notif.h
index 608b763..9bdb299 100644
--- a/gdb/gdbserver/notif.h
+++ b/gdb/gdbserver/notif.h
@@ -20,6 +20,7 @@
 #include "server.h"
 #include "target.h"
 #include "queue.h"
+#include "common-notif.h"
 
 /* Structure holding information related to a single event.  We
    keep a queue of these to push to GDB.  It can be extended if
@@ -31,25 +32,26 @@ typedef struct notif_event
 
 DECLARE_QUEUE_P (notif_event_p);
 
+/* An event of a notification which has an annex.  */
+
+struct notif_annex_event
+{
+  struct notif_event base;
+  /* The index of the annex in field 'annexes' in 'notif_server'.  */
+  int annex_index;
+};
+
 /* A type notification to GDB.  An object of 'struct notif_server'
    represents a type of notification.  */
 
 typedef struct notif_server
 {
-  /* The name of ack packet, for example, 'vStopped'.  */
-  const char *ack_name;
-
-  /* The notification packet, for example, '%Stop'.  Note that '%' is
-     not in 'notif_name'.  */
-  const char *notif_name;
+  struct notif_base base;
 
   /* A queue of events to GDB.  A new notif_event can be enque'ed
      into QUEUE at any appropriate time, and the notif_reply is
      deque'ed only when the ack from GDB arrives.  */
   QUEUE (notif_event_p) *queue;
-
-  /* Write event EVENT to OWN_BUF.  */
-  void (*write) (struct notif_event *event, char *own_buf);
 } *notif_server_p;
 
 extern struct notif_server notif_stop;
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 6bb36d8..8c00b7c 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -184,9 +184,14 @@ vstop_notif_reply (struct notif_event *event, char *own_buf)
   prepare_resume_reply (own_buf, vstop->ptid, &vstop->status);
 }
 
+static struct notif_annex notif_annex_stop[] =
+{
+  { NULL, vstop_notif_reply, },
+};
+
 struct notif_server notif_stop =
 {
-  "vStopped", "Stop", NULL, vstop_notif_reply,
+  { "Stop", "vStopped", notif_annex_stop, }, NULL,
 };
 
 static int
diff --git a/gdb/remote-notif.c b/gdb/remote-notif.c
index c4bfd8d..335572b 100644
--- a/gdb/remote-notif.c
+++ b/gdb/remote-notif.c
@@ -53,6 +53,46 @@ static struct notif_client *notifs[] =
 
 static void do_notif_event_xfree (void *arg);
 
+/* Iterate over annexes in NC to match annex in BUF.   */
+
+static void
+remote_notif_parse_1 (struct notif_client *nc,
+		      struct notif_event *event, char *buf)
+{
+  const struct notif_annex *m = NULL;
+  const struct notif_base *base = (struct notif_base *) nc;
+
+  if (NOTIF_HAS_ANNEX (base))
+    {
+      int i;
+
+      NOTIF_ITER_ANNEX (base, i)
+	{
+	  m = &base->annexes[i];
+
+	  if (strncmp (m->name, buf, strlen (base->notif_name)) == 0
+	      /* The annex is separated by ':' for the rest of
+		 contents in BUF.  */
+	      && buf[strlen (m->name)] == ':')
+	    {
+	      /* Pass BUF without annex and ':'.  */
+	      m->parse (nc, buf + strlen (m->name) + 1, event);
+	      break;
+	    }
+	  m = NULL;
+	}
+    }
+  else
+    {
+      m = &base->annexes[0];
+      m->parse (nc, buf, event);
+    }
+
+  if (m == NULL)
+    error (_("Can't parse '%s' for notif '%s'"), buf,
+	   base->notif_name);
+}
+
 /* Parse the BUF for the expected notification NC, and send packet to
    acknowledge.  */
 
@@ -65,9 +105,9 @@ remote_notif_ack (struct notif_client *nc, char *buf)
 
   if (notif_debug)
     fprintf_unfiltered (gdb_stdlog, "notif: ack '%s'\n",
-			nc->ack_command);
+			nc->base.ack_name);
 
-  nc->parse (nc, buf, event);
+  remote_notif_parse_1 (nc, event, buf);
   nc->ack (nc, buf, event);
 
   discard_cleanups (old_chain);
@@ -83,9 +123,10 @@ remote_notif_parse (struct notif_client *nc, char *buf)
     = make_cleanup (do_notif_event_xfree, event);
 
   if (notif_debug)
-    fprintf_unfiltered (gdb_stdlog, "notif: parse '%s'\n", nc->name);
+    fprintf_unfiltered (gdb_stdlog, "notif: parse '%s'\n",
+			nc->base.notif_name);
 
-  nc->parse (nc, buf, event);
+  remote_notif_parse_1 (nc, event, buf);
 
   discard_cleanups (old_chain);
   return event;
@@ -158,8 +199,9 @@ handle_notification (char *buf)
   for (i = 0; i < ARRAY_SIZE (notifs); i++)
     {
       nc = notifs[i];
-      if (strncmp (buf, nc->name, strlen (nc->name)) == 0
-	  && buf[strlen (nc->name)] == ':')
+      if (0 == strncmp (buf, nc->base.notif_name,
+			strlen (nc->base.notif_name))
+	  && buf[strlen (nc->base.notif_name)] == ':')
 	break;
       nc = NULL;
     }
@@ -181,7 +223,8 @@ handle_notification (char *buf)
   else
     {
       struct notif_event *event
-	= remote_notif_parse (nc, buf + strlen (nc->name) + 1);
+	= remote_notif_parse (nc,
+			      buf + strlen (nc->base.notif_name) + 1);
 
       /* Be careful to only set it after parsing, since an error
 	 may be thrown then.  */
@@ -234,7 +277,7 @@ handle_notification (char *buf)
       if (notif_debug)
 	fprintf_unfiltered (gdb_stdlog,
 			    "notif: Notification '%s' captured\n",
-			    nc->name);
+			    nc->base.notif_name);
     }
 }
 
diff --git a/gdb/remote-notif.h b/gdb/remote-notif.h
index da4fdea..fd38ea4 100644
--- a/gdb/remote-notif.h
+++ b/gdb/remote-notif.h
@@ -21,6 +21,7 @@
 #define REMOTE_NOTIF_H
 
 #include "queue.h"
+#include "common-notif.h"
 
 /* An event of a type of async remote notification.  */
 
@@ -35,17 +36,7 @@ struct notif_event
 
 typedef struct notif_client
 {
-  /* The name of notification packet.  */
-  const char *name;
-
-  /* The packet to acknowledge a previous reply.  */
-  const char *ack_command;
-
-  /* Parse BUF to get the expected event and update EVENT.  This
-     function may throw exception if contents in BUF is not the
-     expected event.  */
-  void (*parse) (struct notif_client *self, char *buf,
-		 struct notif_event *event);
+  struct notif_base base;
 
   /* Send field <ack_command> to remote, and do some checking.  If
      something wrong, throw an exception.  */
diff --git a/gdb/remote.c b/gdb/remote.c
index b8a7a1a..e435354 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -5226,7 +5226,7 @@ remote_notif_stop_ack (struct notif_client *self, char *buf,
   struct stop_reply *stop_reply = (struct stop_reply *) event;
 
   /* acknowledge */
-  putpkt ((char *) self->ack_command);
+  putpkt ((char *) self->base.ack_name);
 
   if (stop_reply->ws.kind == TARGET_WAITKIND_IGNORE)
       /* We got an unknown stop reply.  */
@@ -5266,13 +5266,16 @@ remote_notif_stop_alloc_reply (void)
   return r;
 }
 
+static struct notif_annex notif_client_annex_stop[] =
+{
+  { NULL, remote_notif_stop_parse, },
+};
+
 /* A client of notification Stop.  */
 
 struct notif_client notif_client_stop =
 {
-  "Stop",
-  "vStopped",
-  remote_notif_stop_parse,
+  { "Stop", "vStopped", notif_client_annex_stop, },
   remote_notif_stop_ack,
   remote_notif_stop_can_get_pending_events,
   remote_notif_stop_alloc_reply,
@@ -5699,7 +5702,7 @@ remote_notif_get_pending_events (struct notif_client *nc)
       if (notif_debug)
 	fprintf_unfiltered (gdb_stdlog,
 			    "notif: process: '%s' ack pending event\n",
-			    nc->name);
+			    nc->base.notif_name);
 
       /* acknowledge */
       nc->ack (nc, rs->buf, nc->pending_event);
@@ -5719,7 +5722,7 @@ remote_notif_get_pending_events (struct notif_client *nc)
       if (notif_debug)
 	fprintf_unfiltered (gdb_stdlog,
 			    "notif: process: '%s' no pending reply\n",
-			    nc->name);
+			    nc->base.notif_name);
     }
 }
 
-- 
1.7.7.6


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