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