xref: /dragonfly/contrib/gdb-7/gdb/remote-notif.c (revision ef5ccd6c)
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   &notif_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, &notif_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