1*ef5ccd6cSJohn Marino /* Remote notification in GDB protocol
2*ef5ccd6cSJohn Marino
3*ef5ccd6cSJohn Marino Copyright (C) 1988-2013 Free Software Foundation, Inc.
4*ef5ccd6cSJohn Marino
5*ef5ccd6cSJohn Marino This file is part of GDB.
6*ef5ccd6cSJohn Marino
7*ef5ccd6cSJohn Marino This program is free software; you can redistribute it and/or modify
8*ef5ccd6cSJohn Marino it under the terms of the GNU General Public License as published by
9*ef5ccd6cSJohn Marino the Free Software Foundation; either version 3 of the License, or
10*ef5ccd6cSJohn Marino (at your option) any later version.
11*ef5ccd6cSJohn Marino
12*ef5ccd6cSJohn Marino This program is distributed in the hope that it will be useful,
13*ef5ccd6cSJohn Marino but WITHOUT ANY WARRANTY; without even the implied warranty of
14*ef5ccd6cSJohn Marino MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15*ef5ccd6cSJohn Marino GNU General Public License for more details.
16*ef5ccd6cSJohn Marino
17*ef5ccd6cSJohn Marino You should have received a copy of the GNU General Public License
18*ef5ccd6cSJohn Marino along with this program. If not, see <http://www.gnu.org/licenses/>. */
19*ef5ccd6cSJohn Marino
20*ef5ccd6cSJohn Marino /* Remote async notification is sent from remote target over RSP.
21*ef5ccd6cSJohn Marino Each type of notification is represented by an object of
22*ef5ccd6cSJohn Marino 'struct notif', which has a field 'pending_reply'. It is not
23*ef5ccd6cSJohn Marino NULL when GDB receives a notification from GDBserver, but hasn't
24*ef5ccd6cSJohn Marino acknowledge yet. Before GDB acknowledges the notification,
25*ef5ccd6cSJohn Marino GDBserver shouldn't send notification again (see the header comments
26*ef5ccd6cSJohn Marino in gdbserver/notif.c).
27*ef5ccd6cSJohn Marino
28*ef5ccd6cSJohn Marino Notifications are processed in an almost-unified approach for both
29*ef5ccd6cSJohn Marino all-stop mode and non-stop mode, except the timing to process them.
30*ef5ccd6cSJohn Marino In non-stop mode, notifications are processed in
31*ef5ccd6cSJohn Marino remote_async_get_pending_events_handler, while in all-stop mode,
32*ef5ccd6cSJohn Marino they are processed in remote_resume. */
33*ef5ccd6cSJohn Marino
34*ef5ccd6cSJohn Marino #include "defs.h"
35*ef5ccd6cSJohn Marino #include "remote.h"
36*ef5ccd6cSJohn Marino #include "remote-notif.h"
37*ef5ccd6cSJohn Marino #include "observer.h"
38*ef5ccd6cSJohn Marino #include "event-loop.h"
39*ef5ccd6cSJohn Marino #include "target.h"
40*ef5ccd6cSJohn Marino #include "inferior.h"
41*ef5ccd6cSJohn Marino #include "gdbcmd.h"
42*ef5ccd6cSJohn Marino
43*ef5ccd6cSJohn Marino #include <string.h>
44*ef5ccd6cSJohn Marino
45*ef5ccd6cSJohn Marino int notif_debug = 0;
46*ef5ccd6cSJohn Marino
47*ef5ccd6cSJohn Marino /* Supported clients of notifications. */
48*ef5ccd6cSJohn Marino
49*ef5ccd6cSJohn Marino static struct notif_client *notifs[] =
50*ef5ccd6cSJohn Marino {
51*ef5ccd6cSJohn Marino ¬if_client_stop,
52*ef5ccd6cSJohn Marino };
53*ef5ccd6cSJohn Marino
54*ef5ccd6cSJohn Marino static void do_notif_event_xfree (void *arg);
55*ef5ccd6cSJohn Marino
56*ef5ccd6cSJohn Marino /* Parse the BUF for the expected notification NC, and send packet to
57*ef5ccd6cSJohn Marino acknowledge. */
58*ef5ccd6cSJohn Marino
59*ef5ccd6cSJohn Marino void
remote_notif_ack(struct notif_client * nc,char * buf)60*ef5ccd6cSJohn Marino remote_notif_ack (struct notif_client *nc, char *buf)
61*ef5ccd6cSJohn Marino {
62*ef5ccd6cSJohn Marino struct notif_event *event = nc->alloc_event ();
63*ef5ccd6cSJohn Marino struct cleanup *old_chain
64*ef5ccd6cSJohn Marino = make_cleanup (do_notif_event_xfree, event);
65*ef5ccd6cSJohn Marino
66*ef5ccd6cSJohn Marino if (notif_debug)
67*ef5ccd6cSJohn Marino fprintf_unfiltered (gdb_stdlog, "notif: ack '%s'\n",
68*ef5ccd6cSJohn Marino nc->ack_command);
69*ef5ccd6cSJohn Marino
70*ef5ccd6cSJohn Marino nc->parse (nc, buf, event);
71*ef5ccd6cSJohn Marino nc->ack (nc, buf, event);
72*ef5ccd6cSJohn Marino
73*ef5ccd6cSJohn Marino discard_cleanups (old_chain);
74*ef5ccd6cSJohn Marino }
75*ef5ccd6cSJohn Marino
76*ef5ccd6cSJohn Marino /* Parse the BUF for the expected notification NC. */
77*ef5ccd6cSJohn Marino
78*ef5ccd6cSJohn Marino struct notif_event *
remote_notif_parse(struct notif_client * nc,char * buf)79*ef5ccd6cSJohn Marino remote_notif_parse (struct notif_client *nc, char *buf)
80*ef5ccd6cSJohn Marino {
81*ef5ccd6cSJohn Marino struct notif_event *event = nc->alloc_event ();
82*ef5ccd6cSJohn Marino struct cleanup *old_chain
83*ef5ccd6cSJohn Marino = make_cleanup (do_notif_event_xfree, event);
84*ef5ccd6cSJohn Marino
85*ef5ccd6cSJohn Marino if (notif_debug)
86*ef5ccd6cSJohn Marino fprintf_unfiltered (gdb_stdlog, "notif: parse '%s'\n", nc->name);
87*ef5ccd6cSJohn Marino
88*ef5ccd6cSJohn Marino nc->parse (nc, buf, event);
89*ef5ccd6cSJohn Marino
90*ef5ccd6cSJohn Marino discard_cleanups (old_chain);
91*ef5ccd6cSJohn Marino return event;
92*ef5ccd6cSJohn Marino }
93*ef5ccd6cSJohn Marino
94*ef5ccd6cSJohn Marino DECLARE_QUEUE_P (notif_client_p);
95*ef5ccd6cSJohn Marino DEFINE_QUEUE_P (notif_client_p);
96*ef5ccd6cSJohn Marino
QUEUE(notif_client_p)97*ef5ccd6cSJohn Marino static QUEUE(notif_client_p) *notif_queue;
98*ef5ccd6cSJohn Marino
99*ef5ccd6cSJohn Marino /* Process notifications one by one. EXCEPT is not expected in
100*ef5ccd6cSJohn Marino the queue. */
101*ef5ccd6cSJohn Marino
102*ef5ccd6cSJohn Marino void
103*ef5ccd6cSJohn Marino remote_notif_process (struct notif_client *except)
104*ef5ccd6cSJohn Marino {
105*ef5ccd6cSJohn Marino while (!QUEUE_is_empty (notif_client_p, notif_queue))
106*ef5ccd6cSJohn Marino {
107*ef5ccd6cSJohn Marino struct notif_client *nc = QUEUE_deque (notif_client_p,
108*ef5ccd6cSJohn Marino notif_queue);
109*ef5ccd6cSJohn Marino
110*ef5ccd6cSJohn Marino gdb_assert (nc != except);
111*ef5ccd6cSJohn Marino
112*ef5ccd6cSJohn Marino if (nc->can_get_pending_events (nc))
113*ef5ccd6cSJohn Marino remote_notif_get_pending_events (nc);
114*ef5ccd6cSJohn Marino }
115*ef5ccd6cSJohn Marino }
116*ef5ccd6cSJohn Marino
117*ef5ccd6cSJohn Marino static void
remote_async_get_pending_events_handler(gdb_client_data data)118*ef5ccd6cSJohn Marino remote_async_get_pending_events_handler (gdb_client_data data)
119*ef5ccd6cSJohn Marino {
120*ef5ccd6cSJohn Marino gdb_assert (non_stop);
121*ef5ccd6cSJohn Marino remote_notif_process (NULL);
122*ef5ccd6cSJohn Marino }
123*ef5ccd6cSJohn Marino
124*ef5ccd6cSJohn Marino /* Asynchronous signal handle registered as event loop source for when
125*ef5ccd6cSJohn Marino the remote sent us a notification. The registered callback
126*ef5ccd6cSJohn Marino will do a ACK sequence to pull the rest of the events out of
127*ef5ccd6cSJohn Marino the remote side into our event queue. */
128*ef5ccd6cSJohn Marino
129*ef5ccd6cSJohn Marino static struct async_event_handler *remote_async_get_pending_events_token;
130*ef5ccd6cSJohn Marino
131*ef5ccd6cSJohn Marino /* Register async_event_handler for notification. */
132*ef5ccd6cSJohn Marino
133*ef5ccd6cSJohn Marino void
remote_notif_register_async_event_handler(void)134*ef5ccd6cSJohn Marino remote_notif_register_async_event_handler (void)
135*ef5ccd6cSJohn Marino {
136*ef5ccd6cSJohn Marino remote_async_get_pending_events_token
137*ef5ccd6cSJohn Marino = create_async_event_handler (remote_async_get_pending_events_handler,
138*ef5ccd6cSJohn Marino NULL);
139*ef5ccd6cSJohn Marino }
140*ef5ccd6cSJohn Marino
141*ef5ccd6cSJohn Marino /* Unregister async_event_handler for notification. */
142*ef5ccd6cSJohn Marino
143*ef5ccd6cSJohn Marino void
remote_notif_unregister_async_event_handler(void)144*ef5ccd6cSJohn Marino remote_notif_unregister_async_event_handler (void)
145*ef5ccd6cSJohn Marino {
146*ef5ccd6cSJohn Marino if (remote_async_get_pending_events_token)
147*ef5ccd6cSJohn Marino delete_async_event_handler (&remote_async_get_pending_events_token);
148*ef5ccd6cSJohn Marino }
149*ef5ccd6cSJohn Marino
150*ef5ccd6cSJohn Marino /* Remote notification handler. */
151*ef5ccd6cSJohn Marino
152*ef5ccd6cSJohn Marino void
handle_notification(char * buf)153*ef5ccd6cSJohn Marino handle_notification (char *buf)
154*ef5ccd6cSJohn Marino {
155*ef5ccd6cSJohn Marino struct notif_client *nc = NULL;
156*ef5ccd6cSJohn Marino int i;
157*ef5ccd6cSJohn Marino
158*ef5ccd6cSJohn Marino for (i = 0; i < ARRAY_SIZE (notifs); i++)
159*ef5ccd6cSJohn Marino {
160*ef5ccd6cSJohn Marino nc = notifs[i];
161*ef5ccd6cSJohn Marino if (strncmp (buf, nc->name, strlen (nc->name)) == 0
162*ef5ccd6cSJohn Marino && buf[strlen (nc->name)] == ':')
163*ef5ccd6cSJohn Marino break;
164*ef5ccd6cSJohn Marino }
165*ef5ccd6cSJohn Marino
166*ef5ccd6cSJohn Marino /* We ignore notifications we don't recognize, for compatibility
167*ef5ccd6cSJohn Marino with newer stubs. */
168*ef5ccd6cSJohn Marino if (nc == NULL)
169*ef5ccd6cSJohn Marino return;
170*ef5ccd6cSJohn Marino
171*ef5ccd6cSJohn Marino if (nc->pending_event)
172*ef5ccd6cSJohn Marino {
173*ef5ccd6cSJohn Marino /* We've already parsed the in-flight reply, but the stub for some
174*ef5ccd6cSJohn Marino reason thought we didn't, possibly due to timeout on its side.
175*ef5ccd6cSJohn Marino Just ignore it. */
176*ef5ccd6cSJohn Marino if (notif_debug)
177*ef5ccd6cSJohn Marino fprintf_unfiltered (gdb_stdlog,
178*ef5ccd6cSJohn Marino "notif: ignoring resent notification\n");
179*ef5ccd6cSJohn Marino }
180*ef5ccd6cSJohn Marino else
181*ef5ccd6cSJohn Marino {
182*ef5ccd6cSJohn Marino struct notif_event *event
183*ef5ccd6cSJohn Marino = remote_notif_parse (nc, buf + strlen (nc->name) + 1);
184*ef5ccd6cSJohn Marino
185*ef5ccd6cSJohn Marino /* Be careful to only set it after parsing, since an error
186*ef5ccd6cSJohn Marino may be thrown then. */
187*ef5ccd6cSJohn Marino nc->pending_event = event;
188*ef5ccd6cSJohn Marino
189*ef5ccd6cSJohn Marino /* Notify the event loop there's a stop reply to acknowledge
190*ef5ccd6cSJohn Marino and that there may be more events to fetch. */
191*ef5ccd6cSJohn Marino QUEUE_enque (notif_client_p, notif_queue, nc);
192*ef5ccd6cSJohn Marino if (non_stop)
193*ef5ccd6cSJohn Marino {
194*ef5ccd6cSJohn Marino /* In non-stop, We mark REMOTE_ASYNC_GET_PENDING_EVENTS_TOKEN
195*ef5ccd6cSJohn Marino in order to go on what we were doing and postpone
196*ef5ccd6cSJohn Marino querying notification events to some point safe to do so.
197*ef5ccd6cSJohn Marino See details in the function comment of
198*ef5ccd6cSJohn Marino remote.c:remote_notif_get_pending_events.
199*ef5ccd6cSJohn Marino
200*ef5ccd6cSJohn Marino In all-stop, GDB may be blocked to wait for the reply, we
201*ef5ccd6cSJohn Marino shouldn't return to event loop until the expected reply
202*ef5ccd6cSJohn Marino arrives. For example:
203*ef5ccd6cSJohn Marino
204*ef5ccd6cSJohn Marino 1.1) --> vCont;c
205*ef5ccd6cSJohn Marino GDB expects getting stop reply 'T05 thread:2'.
206*ef5ccd6cSJohn Marino 1.2) <-- %Notif
207*ef5ccd6cSJohn Marino <GDB marks the REMOTE_ASYNC_GET_PENDING_EVENTS_TOKEN>
208*ef5ccd6cSJohn Marino
209*ef5ccd6cSJohn Marino After step #1.2, we return to the event loop, which
210*ef5ccd6cSJohn Marino notices there is a new event on the
211*ef5ccd6cSJohn Marino REMOTE_ASYNC_GET_PENDING_EVENTS_TOKEN and calls the
212*ef5ccd6cSJohn Marino handler, which will send 'vNotif' packet.
213*ef5ccd6cSJohn Marino 1.3) --> vNotif
214*ef5ccd6cSJohn Marino It is not safe to start a new sequence, because target
215*ef5ccd6cSJohn Marino is still running and GDB is expecting the stop reply
216*ef5ccd6cSJohn Marino from stub.
217*ef5ccd6cSJohn Marino
218*ef5ccd6cSJohn Marino To solve this, whenever we parse a notification
219*ef5ccd6cSJohn Marino successfully, we don't mark the
220*ef5ccd6cSJohn Marino REMOTE_ASYNC_GET_PENDING_EVENTS_TOKEN and let GDB blocked
221*ef5ccd6cSJohn Marino there as before to get the sequence done.
222*ef5ccd6cSJohn Marino
223*ef5ccd6cSJohn Marino 2.1) --> vCont;c
224*ef5ccd6cSJohn Marino GDB expects getting stop reply 'T05 thread:2'
225*ef5ccd6cSJohn Marino 2.2) <-- %Notif
226*ef5ccd6cSJohn Marino <Don't mark the REMOTE_ASYNC_GET_PENDING_EVENTS_TOKEN>
227*ef5ccd6cSJohn Marino 2.3) <-- T05 thread:2
228*ef5ccd6cSJohn Marino
229*ef5ccd6cSJohn Marino These pending notifications can be processed later. */
230*ef5ccd6cSJohn Marino mark_async_event_handler (remote_async_get_pending_events_token);
231*ef5ccd6cSJohn Marino }
232*ef5ccd6cSJohn Marino
233*ef5ccd6cSJohn Marino if (notif_debug)
234*ef5ccd6cSJohn Marino fprintf_unfiltered (gdb_stdlog,
235*ef5ccd6cSJohn Marino "notif: Notification '%s' captured\n",
236*ef5ccd6cSJohn Marino nc->name);
237*ef5ccd6cSJohn Marino }
238*ef5ccd6cSJohn Marino }
239*ef5ccd6cSJohn Marino
240*ef5ccd6cSJohn Marino /* Cleanup wrapper. */
241*ef5ccd6cSJohn Marino
242*ef5ccd6cSJohn Marino static void
do_notif_event_xfree(void * arg)243*ef5ccd6cSJohn Marino do_notif_event_xfree (void *arg)
244*ef5ccd6cSJohn Marino {
245*ef5ccd6cSJohn Marino struct notif_event *event = arg;
246*ef5ccd6cSJohn Marino
247*ef5ccd6cSJohn Marino if (event && event->dtr)
248*ef5ccd6cSJohn Marino event->dtr (event);
249*ef5ccd6cSJohn Marino
250*ef5ccd6cSJohn Marino xfree (event);
251*ef5ccd6cSJohn Marino }
252*ef5ccd6cSJohn Marino
253*ef5ccd6cSJohn Marino static void
notif_xfree(struct notif_client * notif)254*ef5ccd6cSJohn Marino notif_xfree (struct notif_client *notif)
255*ef5ccd6cSJohn Marino {
256*ef5ccd6cSJohn Marino if (notif->pending_event != NULL
257*ef5ccd6cSJohn Marino && notif->pending_event->dtr != NULL)
258*ef5ccd6cSJohn Marino notif->pending_event->dtr (notif->pending_event);
259*ef5ccd6cSJohn Marino
260*ef5ccd6cSJohn Marino xfree (notif->pending_event);
261*ef5ccd6cSJohn Marino xfree (notif);
262*ef5ccd6cSJohn Marino }
263*ef5ccd6cSJohn Marino
264*ef5ccd6cSJohn Marino /* -Wmissing-prototypes */
265*ef5ccd6cSJohn Marino extern initialize_file_ftype _initialize_notif;
266*ef5ccd6cSJohn Marino
267*ef5ccd6cSJohn Marino void
_initialize_notif(void)268*ef5ccd6cSJohn Marino _initialize_notif (void)
269*ef5ccd6cSJohn Marino {
270*ef5ccd6cSJohn Marino notif_queue = QUEUE_alloc (notif_client_p, notif_xfree);
271*ef5ccd6cSJohn Marino
272*ef5ccd6cSJohn Marino add_setshow_boolean_cmd ("notification", no_class, ¬if_debug,
273*ef5ccd6cSJohn Marino _("\
274*ef5ccd6cSJohn Marino Set debugging of async remote notification."), _("\
275*ef5ccd6cSJohn Marino Show debugging of async remote notification."), _("\
276*ef5ccd6cSJohn Marino When non-zero, debugging output about async remote notifications"
277*ef5ccd6cSJohn Marino " is enabled."),
278*ef5ccd6cSJohn Marino NULL,
279*ef5ccd6cSJohn Marino NULL,
280*ef5ccd6cSJohn Marino &setdebuglist, &showdebuglist);
281*ef5ccd6cSJohn Marino }
282