[PATCH 2/5] Query supported notifications by qSupported

Yao Qi
2014-01-24T09:43:20Z

V8: Treat each notification as feature.

V7: remove annex.

V6: the supported flag of each notification is saved in
'struct remote_notif_state' in GDB. In GDBserver, the supported flag
is still associated with each notification.

As we we adding more notifications, both GDB and GDBserver
has to know what notifications are supported in the other
side. This is what this patch does. When GDB connects to GDBserver,
it will happen:

--> qSupported:XXX;NotifN1+;NotifN2+;NotifN3+
(GDB supports notification N1, N2 and N3)
<-- XXX;NotifN1;NotifN2;NotifN4
(GDBsever supports notification N1, N2 and N4)

after this, GDB knows what notifications GDBserver is able to send,
and GDBservers knows what notifications GDB doesn't support.

gdb/gdbserver:

* notif.c (notif_qsupported_record): New function.
(notif_qsupported_reply): New function.
* notif.h (struct notif_server) <supported>: New field.
(notif_qsupported_reply): Declare.
(notif_qsupported_record): Declare.
* server.c (notif_stop): Update.
(handle_query): Call notif_qsupported_record and
notif_qsupported_reply.

gdb:

* remote-notif.c (remote_notif_ack): Add argument 'state'.
Callers update.
(remote_notif_parse): Likewise.
(remote_notif_find): New function.
(remote_notif_qsupported): New function.
(remote_notif_state_allocate): Initialize field 'supported'.
(remote_notif_state_xfree): Free field 'supported'.
* remote-notif.h (struct remote_notif_state) <supported>: New
field.
(remote_notif_ack, remote_notif_parse): Update declarations.
(remote_notif_qsupported): Declare.
* remote.c (PACKET_notifications): New enum.
(remote_notif_feature): New function.
(remote_protocol_features): Add new element.
(remote_query_supported): Call remote_notif_qsupported.
---
gdb/gdbserver/notif.c | 43 ++++++++++++++++++++++++++++++++++++
gdb/gdbserver/notif.h | 5 ++++
gdb/gdbserver/server.c | 15 ++++++++++++-
gdb/remote-notif.c | 56 +++++++++++++++++++++++++++++++++++++++++++++--
gdb/remote-notif.h | 12 +++++++++-
gdb/remote.c | 27 +++++++++++++++++++---
6 files changed, 149 insertions(+), 9 deletions(-)

diff --git a/gdb/gdbserver/notif.c b/gdb/gdbserver/notif.c
index 8bc66dc..3847110 100644
--- a/gdb/gdbserver/notif.c
+++ b/gdb/gdbserver/notif.c
@@ -159,6 +159,49 @@ notif_event_xfree (struct notif_event *event)
xfree (event);
}

+/* Record the notification NOTIF supported by GDB. */
+
+void
+notif_qsupported_record (char *notif)
+{
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE (notifs); i++)
+ if (strcmp (notif, notifs[i]->notif_name) == 0)
+ break;
+
+ if (i < ARRAY_SIZE (notifs))
+ notifs[i]->supported = 1;
+}
+
+/* Return a string about notifications that GDBserver supports.
+ Return NULL if no notification is supported. The caller is
+ responsible to free the returned string. Suppose GDBserver
+ supports notifications N1, N2, and N3. The returned string is
+ ";NotifN1+;NotifN2+;NotifN3+". */
+
+void
+notif_qsupported_reply (char *buf)
+{
+ size_t i;
+
+#define BUF_LEN 128
+
+ for (i = 0; i < ARRAY_SIZE (notifs); i++)
+ {
+ struct notif_server *nb = notifs[i];
+ char s[BUF_LEN];
+
+ /* Skip stop notification because it has been supported
+ unconditionally. */
+ if (nb == &notif_stop)
+ continue;
+
+ xsnprintf (s, BUF_LEN, ";Notif%s+", nb->notif_name);
+ strcat (buf, s);
+ }
+}
+
void
initialize_notif (void)
{
diff --git a/gdb/gdbserver/notif.h b/gdb/gdbserver/notif.h
index 3d233a1..671ef32 100644
--- a/gdb/gdbserver/notif.h
+++ b/gdb/gdbserver/notif.h
@@ -52,12 +52,17 @@ typedef struct notif_server

/* Write event EVENT to OWN_BUF. */
void (*write) (struct notif_event *event, char *own_buf);
+
+ /* This notification is supported by GDB or not. */
+ int supported;
} *notif_server_p;

extern struct notif_server notif_stop;

int handle_notif_ack (char *own_buf, int packet_len);
void notif_write_event (struct notif_server *notif, char *own_buf);
+void notif_qsupported_reply (char *buf);
+void notif_qsupported_record (char *notif);

void notif_push (struct notif_server *np, struct notif_event *event);
void notif_event_enque (struct notif_server *notif,
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 88354be..0d8f545 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -185,7 +185,7 @@ vstop_notif_reply (struct notif_event *event, char *own_buf)

struct notif_server notif_stop =
{
- "vStopped", "Stop", NULL, vstop_notif_reply,
+ "vStopped", "Stop", NULL, vstop_notif_reply, 1,
};

static int
@@ -1832,6 +1832,17 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
/* GDB supports relocate instruction requests. */
gdb_supports_qRelocInsn = 1;
}
+ else if (strncmp (p, "Notif", 5) == 0)
+ {
+ char *notif_name = xstrdup (&p[5]);
+
+ /* Remove '+' at the end. */
+ notif_name[strlen(notif_name) - 1] = 0;
+ /* Record what notifications GDB supports. */
+ notif_qsupported_record (notif_name);
+
+ xfree (notif_name);
+ }
else
target_process_qsupported (p);

@@ -1921,6 +1932,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
strcat (own_buf, ";qXfer:btrace:read+");
}

+ notif_qsupported_reply (own_buf);
+
return;
}

diff --git a/gdb/remote-notif.c b/gdb/remote-notif.c
index d3e1b26..ee2c2c4 100644
--- a/gdb/remote-notif.c
+++ b/gdb/remote-notif.c
@@ -59,7 +59,8 @@ static void do_notif_event_xfree (void *arg);
acknowledge. */

void
-remote_notif_ack (struct notif_client *nc, char *buf)
+remote_notif_ack (struct notif_client *nc,
+ struct remote_notif_state *state, char *buf)
{
struct notif_event *event = nc->alloc_event ();
struct cleanup *old_chain
@@ -78,7 +79,8 @@ remote_notif_ack (struct notif_client *nc, char *buf)
/* Parse the BUF for the expected notification NC. */

struct notif_event *
-remote_notif_parse (struct notif_client *nc, char *buf)
+remote_notif_parse (struct notif_client *nc,
+ struct remote_notif_state *state, char *buf)
{
struct notif_event *event = nc->alloc_event ();
struct cleanup *old_chain
@@ -121,6 +123,20 @@ remote_async_get_pending_events_handler (gdb_client_data data)
remote_notif_process (data, NULL);
}

+/* Find notification by NAME. Return NULL if not found. */
+
+struct notif_client *
+remote_notif_find (const char *name)
+{
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE (notifs); i++)
+ if (strcmp (name, notifs[i]->name) == 0)
+ return notifs[i];
+
+ return NULL;
+}
+
/* Remote notification handler. Parse BUF, queue notification and
update STATE. */

@@ -158,7 +174,7 @@ handle_notification (struct remote_notif_state *state, char *buf)
else
{
struct notif_event *event
- = remote_notif_parse (nc, buf + strlen (nc->name) + 1);
+ = remote_notif_parse (nc, state, buf + strlen (nc->name) + 1);

/* Be careful to only set it after parsing, since an error
may be thrown then. */
@@ -234,6 +250,36 @@ do_notif_event_xfree (void *arg)
notif_event_xfree (arg);
}

+/* Return a string about notifications that GDB supports. The caller
+ is responsible to free the returned string. Suppose GDB supports
+ notifications N1, N2, and N3. The returned string is
+ ";NotifN1+;NotifN2+;NotifN3+". */
+
+char *
+remote_notif_qsupported (char *q)
+{
+ int i;
+ char * p = q;
+#define BUF_LEN 128
+ char buf[BUF_LEN];
+
+ memcpy (buf, "Notif", 5);
+ for (i = 0; i < ARRAY_SIZE (notifs); i++)
+ {
+ struct notif_client *nb = notifs[i];
+
+ /* Skip stop notification because it has been supported
+ unconditionally. */
+ if (nb == &notif_client_stop)
+ continue;
+
+ strcpy (&buf[5], nb->name);
+ p = reconcat (p, p, ";", buf, "+", (char *) NULL);
+ }
+
+ return p;
+}
+
/* Return an allocated remote_notif_state. */

struct remote_notif_state *
@@ -249,6 +295,8 @@ remote_notif_state_allocate (void)
= create_async_event_handler (remote_async_get_pending_events_handler,
notif_state);

+ notif_state->supported = xcalloc (ARRAY_SIZE (notifs), sizeof (int));
+
return notif_state;
}

@@ -268,6 +316,8 @@ remote_notif_state_xfree (struct remote_notif_state *state)
for (i = 0; i < REMOTE_NOTIF_LAST; i++)
notif_event_xfree (state->pending_event[i]);

+ xfree (state->supported);
+
xfree (state);
}

diff --git a/gdb/remote-notif.h b/gdb/remote-notif.h
index 0124ce0..6fd58bf 100644
--- a/gdb/remote-notif.h
+++ b/gdb/remote-notif.h
@@ -96,10 +96,17 @@ struct remote_notif_state
remote.c:remote_notif_pending_replies). */

struct notif_event *pending_event[REMOTE_NOTIF_LAST];
+
+ /* Each element indicates the notification is supported by the
+ remote stub or not. The index is the field 'id' in
+ 'struct notif_client'. */
+ int *supported;
};

-void remote_notif_ack (struct notif_client *nc, char *buf);
+void remote_notif_ack (struct notif_client *nc,
+ struct remote_notif_state *state, char *buf);
struct notif_event *remote_notif_parse (struct notif_client *nc,
+ struct remote_notif_state *state,
char *buf);

void notif_event_xfree (struct notif_event *event);
@@ -111,6 +118,9 @@ void remote_notif_process (struct remote_notif_state *state,
struct notif_client *except);
struct remote_notif_state *remote_notif_state_allocate (void);
void remote_notif_state_xfree (struct remote_notif_state *state);
+struct notif_client *remote_notif_find (const char *name);
+
+char *remote_notif_qsupported (char *buf);

extern struct notif_client notif_client_stop;

diff --git a/gdb/remote.c b/gdb/remote.c
index 7110e0a..098ad8f 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -3631,7 +3631,7 @@ remote_start_remote (int from_tty, struct target_ops *target, int extended_p)
/* remote_notif_get_pending_replies acks this one, and gets
the rest out. */
rs->notif_state->pending_event[notif_client_stop.id]
- = remote_notif_parse (notif, rs->buf);
+ = remote_notif_parse (notif, rs->notif_state, rs->buf);
remote_notif_get_pending_events (notif);

/* Make sure that threads that were stopped remain
@@ -4051,6 +4051,20 @@ remote_augmented_libraries_svr4_read_feature
rs->augmented_libraries_svr4_read = (support == PACKET_ENABLE);
}

+/* Function to call when the remote notification, as a feature, is
+ supported. */
+
+static void
+remote_notif_feature (const struct protocol_feature *feature,
+ enum packet_support support, const char *value)
+{
+ struct remote_state *rs = get_remote_state ();
+ struct notif_client *nc = remote_notif_find (&feature->name[5]);
+
+ if (nc != NULL)
+ rs->notif_state->supported[nc->id] = (support == PACKET_ENABLE);
+}
+
static const struct protocol_feature remote_protocol_features[] = {
{ "PacketSize", PACKET_DISABLE, remote_packet_size, -1 },
{ "qXfer:auxv:read", PACKET_DISABLE, remote_supported_packet,
@@ -4125,7 +4139,8 @@ static const struct protocol_feature remote_protocol_features[] = {
{ "Qbtrace:off", PACKET_DISABLE, remote_supported_packet, PACKET_Qbtrace_off },
{ "Qbtrace:bts", PACKET_DISABLE, remote_supported_packet, PACKET_Qbtrace_bts },
{ "qXfer:btrace:read", PACKET_DISABLE, remote_supported_packet,
- PACKET_qXfer_btrace }
+ PACKET_qXfer_btrace },
+ { "NotifTrace", PACKET_DISABLE, remote_notif_feature, -1 },
};

static char *remote_support_xml;
@@ -4199,6 +4214,8 @@ remote_query_supported (void)

q = remote_query_supported_append (q, "qRelocInsn+");

+ q = remote_notif_qsupported (q);
+
q = reconcat (q, "qSupported:", q, (char *) NULL);
putpkt (q);

@@ -4654,7 +4671,8 @@ extended_remote_attach_1 (struct target_ops *target, char *args, int from_tty)
if (target_can_async_p ())
{
struct notif_event *reply
- = remote_notif_parse (&notif_client_stop, wait_status);
+ = remote_notif_parse (&notif_client_stop, rs->notif_state,
+ wait_status);

push_stop_reply ((struct stop_reply *) reply);

@@ -5916,7 +5934,7 @@ remote_notif_get_pending_events (struct notif_client *nc)
if (strcmp (rs->buf, "OK") == 0)
break;
else
- remote_notif_ack (nc, rs->buf);
+ remote_notif_ack (nc, rs->notif_state, rs->buf);
}
}
else
@@ -6120,6 +6138,7 @@ remote_wait_as (ptid_t ptid, struct target_waitstatus *status, int options)
{
struct stop_reply *stop_reply
= (struct stop_reply *) remote_notif_parse (&notif_client_stop,
+ rs->notif_state,
rs->buf);

event_ptid = process_stop_reply (stop_reply, status);
--
1.7.7.6