123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 |
- /* Remote notification in GDB protocol
- Copyright (C) 1988-2022 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/>. */
- /* Remote async notification is sent from remote target over RSP.
- Each type of notification is represented by an object of
- 'struct notif', which has a field 'pending_reply'. It is not
- NULL when GDB receives a notification from GDBserver, but hasn't
- acknowledge yet. Before GDB acknowledges the notification,
- GDBserver shouldn't send notification again (see the header comments
- in gdbserver/notif.c).
- Notifications are processed in an almost-unified approach for both
- all-stop mode and non-stop mode, except the timing to process them.
- In non-stop mode, notifications are processed in
- remote_async_get_pending_events_handler, while in all-stop mode,
- they are processed in remote_resume. */
- #include "defs.h"
- #include "remote.h"
- #include "remote-notif.h"
- #include "observable.h"
- #include "gdbsupport/event-loop.h"
- #include "target.h"
- #include "inferior.h"
- #include "infrun.h"
- #include "gdbcmd.h"
- #include "async-event.h"
- bool notif_debug = false;
- /* Supported clients of notifications. */
- static struct notif_client *notifs[] =
- {
- ¬if_client_stop,
- };
- gdb_static_assert (ARRAY_SIZE (notifs) == REMOTE_NOTIF_LAST);
- /* Parse the BUF for the expected notification NC, and send packet to
- acknowledge. */
- void
- remote_notif_ack (remote_target *remote,
- struct notif_client *nc, const char *buf)
- {
- notif_event_up event = nc->alloc_event ();
- if (notif_debug)
- gdb_printf (gdb_stdlog, "notif: ack '%s'\n",
- nc->ack_command);
- nc->parse (remote, nc, buf, event.get ());
- nc->ack (remote, nc, buf, event.release ());
- }
- /* Parse the BUF for the expected notification NC. */
- struct notif_event *
- remote_notif_parse (remote_target *remote,
- struct notif_client *nc, const char *buf)
- {
- notif_event_up event = nc->alloc_event ();
- if (notif_debug)
- gdb_printf (gdb_stdlog, "notif: parse '%s'\n", nc->name);
- nc->parse (remote, nc, buf, event.get ());
- return event.release ();
- }
- /* Process notifications in STATE's notification queue one by one.
- EXCEPT is not expected in the queue. */
- void
- remote_notif_process (struct remote_notif_state *state,
- struct notif_client *except)
- {
- while (!state->notif_queue.empty ())
- {
- struct notif_client *nc = state->notif_queue.front ();
- state->notif_queue.pop_front ();
- gdb_assert (nc != except);
- if (nc->can_get_pending_events (state->remote, nc))
- remote_notif_get_pending_events (state->remote, nc);
- }
- }
- static void
- remote_async_get_pending_events_handler (gdb_client_data data)
- {
- remote_notif_state *notif_state = (remote_notif_state *) data;
- clear_async_event_handler (notif_state->get_pending_events_token);
- gdb_assert (remote_target_is_non_stop_p (notif_state->remote));
- remote_notif_process (notif_state, NULL);
- }
- /* Remote notification handler. Parse BUF, queue notification and
- update STATE. */
- void
- handle_notification (struct remote_notif_state *state, const char *buf)
- {
- struct notif_client *nc;
- size_t i;
- for (i = 0; i < ARRAY_SIZE (notifs); i++)
- {
- const char *name = notifs[i]->name;
- if (startswith (buf, name)
- && buf[strlen (name)] == ':')
- break;
- }
- /* We ignore notifications we don't recognize, for compatibility
- with newer stubs. */
- if (i == ARRAY_SIZE (notifs))
- return;
- nc = notifs[i];
- if (state->pending_event[nc->id] != NULL)
- {
- /* We've already parsed the in-flight reply, but the stub for some
- reason thought we didn't, possibly due to timeout on its side.
- Just ignore it. */
- if (notif_debug)
- gdb_printf (gdb_stdlog,
- "notif: ignoring resent notification\n");
- }
- else
- {
- struct notif_event *event
- = remote_notif_parse (state->remote, nc, buf + strlen (nc->name) + 1);
- /* Be careful to only set it after parsing, since an error
- may be thrown then. */
- state->pending_event[nc->id] = event;
- /* Notify the event loop there's a stop reply to acknowledge
- and that there may be more events to fetch. */
- state->notif_queue.push_back (nc);
- if (target_is_non_stop_p ())
- {
- /* In non-stop, We mark REMOTE_ASYNC_GET_PENDING_EVENTS_TOKEN
- in order to go on what we were doing and postpone
- querying notification events to some point safe to do so.
- See details in the function comment of
- remote.c:remote_notif_get_pending_events.
- In all-stop, GDB may be blocked to wait for the reply, we
- shouldn't return to event loop until the expected reply
- arrives. For example:
- 1.1) --> vCont;c
- GDB expects getting stop reply 'T05 thread:2'.
- 1.2) <-- %Notif
- <GDB marks the REMOTE_ASYNC_GET_PENDING_EVENTS_TOKEN>
- After step #1.2, we return to the event loop, which
- notices there is a new event on the
- REMOTE_ASYNC_GET_PENDING_EVENTS_TOKEN and calls the
- handler, which will send 'vNotif' packet.
- 1.3) --> vNotif
- It is not safe to start a new sequence, because target
- is still running and GDB is expecting the stop reply
- from stub.
- To solve this, whenever we parse a notification
- successfully, we don't mark the
- REMOTE_ASYNC_GET_PENDING_EVENTS_TOKEN and let GDB blocked
- there as before to get the sequence done.
- 2.1) --> vCont;c
- GDB expects getting stop reply 'T05 thread:2'
- 2.2) <-- %Notif
- <Don't mark the REMOTE_ASYNC_GET_PENDING_EVENTS_TOKEN>
- 2.3) <-- T05 thread:2
- These pending notifications can be processed later. */
- mark_async_event_handler (state->get_pending_events_token);
- }
- if (notif_debug)
- gdb_printf (gdb_stdlog,
- "notif: Notification '%s' captured\n",
- nc->name);
- }
- }
- /* Return an allocated remote_notif_state. */
- struct remote_notif_state *
- remote_notif_state_allocate (remote_target *remote)
- {
- struct remote_notif_state *notif_state = new struct remote_notif_state;
- notif_state->remote = remote;
- /* Register async_event_handler for notification. */
- notif_state->get_pending_events_token
- = create_async_event_handler (remote_async_get_pending_events_handler,
- notif_state, "remote-notif");
- return notif_state;
- }
- /* Free STATE and its fields. */
- remote_notif_state::~remote_notif_state ()
- {
- int i;
- /* Unregister async_event_handler for notification. */
- if (get_pending_events_token != NULL)
- delete_async_event_handler (&get_pending_events_token);
- for (i = 0; i < REMOTE_NOTIF_LAST; i++)
- delete pending_event[i];
- }
- void _initialize_notif ();
- void
- _initialize_notif ()
- {
- add_setshow_boolean_cmd ("notification", no_class, ¬if_debug,
- _("\
- Set debugging of async remote notification."), _("\
- Show debugging of async remote notification."), _("\
- When non-zero, debugging output about async remote notifications"
- " is enabled."),
- NULL,
- NULL,
- &setdebuglist, &showdebuglist);
- }
|