| /* Handling of inferior events for the event loop for GDB, the GNU debugger. | |
| Copyright (C) 1999, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. | |
| Written by Elena Zannoni <ezannoni@cygnus.com> of Cygnus Solutions. | |
| 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/>. */ | |
| #include "defs.h" | |
| #include "inferior.h" /* For fetch_inferior_event. */ | |
| #include "target.h" /* For enum inferior_event_type. */ | |
| #include "event-loop.h" | |
| #include "event-top.h" | |
| #include "inf-loop.h" | |
| #include "remote.h" | |
| #include "exceptions.h" | |
| #include "language.h" | |
| #include "gdbthread.h" | |
| static int fetch_inferior_event_wrapper (gdb_client_data client_data); | |
| void | |
| inferior_event_handler_wrapper (gdb_client_data client_data) | |
| { | |
| inferior_event_handler (INF_QUIT_REQ, client_data); | |
| } | |
| /* General function to handle events in the inferior. So far it just | |
| takes care of detecting errors reported by select() or poll(), | |
| otherwise it assumes that all is OK, and goes on reading data from | |
| the fd. This however may not always be what we want to do. */ | |
| void | |
| inferior_event_handler (enum inferior_event_type event_type, | |
| gdb_client_data client_data) | |
| { | |
| struct gdb_exception e; | |
| int was_sync = 0; | |
| switch (event_type) | |
| { | |
| case INF_ERROR: | |
| printf_unfiltered (_("error detected from target.\n")); | |
| pop_all_targets_above (file_stratum, 0); | |
| discard_all_intermediate_continuations (); | |
| discard_all_continuations (); | |
| async_enable_stdin (); | |
| break; | |
| case INF_REG_EVENT: | |
| /* Use catch errors for now, until the inner layers of | |
| fetch_inferior_event (i.e. readchar) can return meaningful | |
| error status. If an error occurs while getting an event from | |
| the target, just get rid of the target. */ | |
| if (!catch_errors (fetch_inferior_event_wrapper, | |
| client_data, "", RETURN_MASK_ALL)) | |
| { | |
| pop_all_targets_above (file_stratum, 0); | |
| discard_all_intermediate_continuations (); | |
| discard_all_continuations (); | |
| async_enable_stdin (); | |
| display_gdb_prompt (0); | |
| } | |
| break; | |
| case INF_EXEC_COMPLETE: | |
| if (!non_stop) | |
| { | |
| /* Unregister the inferior from the event loop. This is done | |
| so that when the inferior is not running we don't get | |
| distracted by spurious inferior output. */ | |
| if (target_has_execution) | |
| target_async (NULL, 0); | |
| } | |
| /* The call to async_enable_stdin below resets 'sync_execution'. | |
| However, if sync_execution is 1 now, we also need to show the | |
| prompt below, so save the current value. */ | |
| was_sync = sync_execution; | |
| async_enable_stdin (); | |
| /* Do all continuations associated with the whole inferior (not | |
| a particular thread). */ | |
| if (!ptid_equal (inferior_ptid, null_ptid)) | |
| do_all_inferior_continuations (); | |
| /* If we were doing a multi-step (eg: step n, next n), but it | |
| got interrupted by a breakpoint, still do the pending | |
| continuations. The continuation itself is responsible for | |
| distinguishing the cases. The continuations are allowed to | |
| touch the inferior memory, e.g. to remove breakpoints, so run | |
| them before running breakpoint commands, which may resume the | |
| target. */ | |
| if (non_stop | |
| && target_has_execution | |
| && !ptid_equal (inferior_ptid, null_ptid)) | |
| do_all_intermediate_continuations_thread (inferior_thread ()); | |
| else | |
| do_all_intermediate_continuations (); | |
| /* Always finish the previous command before running any | |
| breakpoint commands. Any stop cancels the previous command. | |
| E.g. a "finish" or "step-n" command interrupted by an | |
| unrelated breakpoint is canceled. */ | |
| if (non_stop | |
| && target_has_execution | |
| && !ptid_equal (inferior_ptid, null_ptid)) | |
| do_all_continuations_thread (inferior_thread ()); | |
| else | |
| do_all_continuations (); | |
| if (current_language != expected_language | |
| && language_mode == language_mode_auto) | |
| language_info (1); /* Print what changed. */ | |
| /* Don't propagate breakpoint commands errors. Either we're | |
| stopping or some command resumes the inferior. The user will | |
| be informed. */ | |
| TRY_CATCH (e, RETURN_MASK_ALL) | |
| { | |
| bpstat_do_actions (); | |
| } | |
| if (!was_sync | |
| && exec_done_display_p | |
| && (ptid_equal (inferior_ptid, null_ptid) | |
| || !is_running (inferior_ptid))) | |
| printf_unfiltered (_("completed.\n")); | |
| break; | |
| case INF_EXEC_CONTINUE: | |
| /* Is there anything left to do for the command issued to | |
| complete? */ | |
| if (non_stop) | |
| do_all_intermediate_continuations_thread (inferior_thread ()); | |
| else | |
| do_all_intermediate_continuations (); | |
| break; | |
| case INF_QUIT_REQ: | |
| /* FIXME: ezannoni 1999-10-04. This call should really be a | |
| target vector entry, so that it can be used for any kind of | |
| targets. */ | |
| async_remote_interrupt_twice (NULL); | |
| break; | |
| case INF_TIMER: | |
| default: | |
| printf_unfiltered (_("Event type not recognized.\n")); | |
| break; | |
| } | |
| } | |
| static int | |
| fetch_inferior_event_wrapper (gdb_client_data client_data) | |
| { | |
| fetch_inferior_event (client_data); | |
| return 1; | |
| } |