/* Target-struct-independent code to start (run) and stop an inferior
process.
- Copyright (C) 1986-2017 Free Software Foundation, Inc.
+ Copyright (C) 1986-2018 Free Software Foundation, Inc.
This file is part of GDB.
#include "inf-loop.h"
#include "regcache.h"
#include "value.h"
-#include "observer.h"
+#include "observable.h"
#include "language.h"
#include "solib.h"
#include "main.h"
/* Prototypes for local functions */
-static void info_signals_command (char *, int);
-
static void sig_print_info (enum gdb_signal);
static void sig_print_header (void);
-static void resume_cleanups (void *);
-
static int follow_fork (void);
static int follow_fork_inferior (int follow_child, int detach_fork);
static void follow_inferior_reset_breakpoints (void);
-static void set_schedlock_func (char *args, int from_tty,
- struct cmd_list_element *c);
-
static int currently_stepping (struct thread_info *tp);
void nullify_last_target_wait_ptid (void);
}
static void
-set_disable_randomization (char *args, int from_tty,
+set_disable_randomization (const char *args, int from_tty,
struct cmd_list_element *c)
{
if (!target_supports_disable_randomization ())
static int non_stop_1 = 0;
static void
-set_non_stop (char *args, int from_tty,
+set_non_stop (const char *args, int from_tty,
struct cmd_list_element *c)
{
if (target_has_execution)
static int observer_mode_1 = 0;
static void
-set_observer_mode (char *args, int from_tty,
+set_observer_mode (const char *args, int from_tty,
struct cmd_list_element *c)
{
if (target_has_execution)
as appropriate when the above flag is changed. */
static void
-set_stop_on_solib_events (char *args, int from_tty, struct cmd_list_element *c)
+set_stop_on_solib_events (const char *args,
+ int from_tty, struct cmd_list_element *c)
{
update_solib_breakpoints ();
}
else
{
child_inf->aspace = new_address_space ();
- child_inf->pspace = add_program_space (child_inf->aspace);
+ child_inf->pspace = new program_space (child_inf->aspace);
child_inf->removable = 1;
set_current_program_space (child_inf->pspace);
clone_program_space (child_inf->pspace, parent_inf->pspace);
target_pid_to_str (process_ptid));
}
- target_detach (NULL, 0);
+ target_detach (parent_inf, 0);
}
/* Note that the detach above makes PARENT_INF dangling. */
else
{
child_inf->aspace = new_address_space ();
- child_inf->pspace = add_program_space (child_inf->aspace);
+ child_inf->pspace = new program_space (child_inf->aspace);
child_inf->removable = 1;
child_inf->symfile_flags = SYMFILE_NO_READ;
set_current_program_space (child_inf->pspace);
}
}
- target_detach (NULL, 0);
+ target_detach (inf->vfork_parent, 0);
/* Put it back. */
inf->pspace = pspace;
{
/* We're staying attached to the parent, so, really give the
child a new address space. */
- inf->pspace = add_program_space (maybe_new_address_space ());
+ inf->pspace = new program_space (maybe_new_address_space ());
inf->aspace = inf->pspace->aspace;
inf->removable = 1;
set_current_program_space (inf->pspace);
program space resets breakpoints). */
inf->aspace = NULL;
inf->pspace = NULL;
- pspace = add_program_space (maybe_new_address_space ());
+ pspace = new program_space (maybe_new_address_space ());
set_current_program_space (pspace);
inf->removable = 1;
inf->symfile_flags = SYMFILE_NO_READ;
struct inferior *inf = current_inferior ();
int pid = ptid_get_pid (ptid);
ptid_t process_ptid;
- char *exec_file_host;
- struct cleanup *old_chain;
/* This is an exec event that we actually wish to pay attention to.
Refresh our symbol table to the newly exec'd program, remove any
breakpoint_init_inferior (inf_execd);
- exec_file_host = exec_file_find (exec_file_target, NULL);
- old_chain = make_cleanup (xfree, exec_file_host);
+ gdb::unique_xmalloc_ptr<char> exec_file_host
+ = exec_file_find (exec_file_target, NULL);
/* If we were unable to map the executable target pathname onto a host
pathname, tell the user that. Otherwise GDB's subsequent behavior
Executable) main symbol file will only be computed by
solib_create_inferior_hook below. breakpoint_re_set would fail
to insert the breakpoints with the zero displacement. */
- try_open_exec_file (exec_file_host, inf, SYMFILE_DEFER_BP_RESET);
-
- do_cleanups (old_chain);
+ try_open_exec_file (exec_file_host.get (), inf, SYMFILE_DEFER_BP_RESET);
/* If the target can specify a description, read it. Must do this
after flipping to the new executable (because the target supplied
}
\f
-/* Resuming. */
-
-/* Things to clean up if we QUIT out of resume (). */
-static void
-resume_cleanups (void *ignore)
-{
- if (!ptid_equal (inferior_ptid, null_ptid))
- delete_single_step_breakpoints (inferior_thread ());
-
- normal_stop ();
-}
static const char schedlock_off[] = "off";
static const char schedlock_on[] = "on";
}
static void
-set_schedlock_func (char *args, int from_tty, struct cmd_list_element *c)
+set_schedlock_func (const char *args, int from_tty, struct cmd_list_element *c)
{
if (!target_can_lock_scheduler)
{
target_commit_resume ();
}
-/* Resume the inferior, but allow a QUIT. This is useful if the user
- wants to interrupt some lengthy single-stepping operation
- (for child processes, the SIGINT goes to the inferior, and so
- we get a SIGINT random_signal, but for remote debugging and perhaps
- other targets, that's not true).
+/* Resume the inferior. SIG is the signal to give the inferior
+ (GDB_SIGNAL_0 for none). Note: don't call this directly; instead
+ call 'resume', which handles exceptions. */
- SIG is the signal to give the inferior (zero for none). */
-void
-resume (enum gdb_signal sig)
+static void
+resume_1 (enum gdb_signal sig)
{
- struct cleanup *old_cleanups = make_cleanup (resume_cleanups, 0);
struct regcache *regcache = get_current_regcache ();
struct gdbarch *gdbarch = regcache->arch ();
struct thread_info *tp = inferior_thread ();
gdb_assert (!tp->stop_requested);
gdb_assert (!thread_is_in_step_over_chain (tp));
- QUIT;
-
if (tp->suspend.waitstatus_pending_p)
{
if (debug_infrun)
}
tp->suspend.stop_signal = GDB_SIGNAL_0;
- discard_cleanups (old_cleanups);
if (target_can_async_p ())
target_async (1);
resume_ptid = internal_resume_ptid (user_step);
do_target_resume (resume_ptid, 0, GDB_SIGNAL_0);
- discard_cleanups (old_cleanups);
tp->resumed = 1;
return;
}
"Got placed in step-over queue\n");
tp->control.trap_expected = 0;
- discard_cleanups (old_cleanups);
return;
}
else if (prepared < 0)
do_target_resume (resume_ptid, step, sig);
tp->resumed = 1;
- discard_cleanups (old_cleanups);
}
+
+/* Resume the inferior. SIG is the signal to give the inferior
+ (GDB_SIGNAL_0 for none). This is a wrapper around 'resume_1' that
+ rolls back state on error. */
+
+void
+resume (gdb_signal sig)
+{
+ TRY
+ {
+ resume_1 (sig);
+ }
+ CATCH (ex, RETURN_MASK_ALL)
+ {
+ /* If resuming is being aborted for any reason, delete any
+ single-step breakpoint resume_1 may have created, to avoid
+ confusing the following resumption, and to avoid leaving
+ single-step breakpoints perturbing other threads, in case
+ we're running in non-stop mode. */
+ if (inferior_ptid != null_ptid)
+ delete_single_step_breakpoints (inferior_thread ());
+ throw_exception (ex);
+ }
+ END_CATCH
+}
+
\f
/* Proceeding. */
inferior->control.stop_soon = NO_STOP_QUIETLY;
}
- observer_notify_about_to_proceed ();
+ gdb::observers::about_to_proceed.notify ();
}
/* Returns true if TP is still stopped at a breakpoint that needs
inferior. */
gdb_flush (gdb_stdout);
+ /* Since we've marked the inferior running, give it the terminal. A
+ QUIT/Ctrl-C from here on is forwarded to the target (which can
+ still detect attempts to unblock a stuck connection with repeated
+ Ctrl-C from within target_pass_ctrlc). */
+ target_terminal::inferior ();
+
/* In a multi-threaded task we may select another thread and
then continue or step.
&& !gdb_in_secondary_prompt_p (ui))
{
target_terminal::ours ();
- observer_notify_sync_execution_done ();
+ gdb::observers::sync_execution_done.notify ();
ui_register_input_event_handler (ui);
}
}
/* Support the --return-child-result option. */
return_child_result_value = ecs->ws.value.integer;
- observer_notify_exited (ecs->ws.value.integer);
+ gdb::observers::exited.notify (ecs->ws.value.integer);
}
else
{
Cannot fill $_exitsignal with the correct signal number.\n"));
}
- observer_notify_signal_exited (ecs->ws.value.sig);
+ gdb::observers::signal_exited.notify (ecs->ws.value.sig);
}
gdb_flush (gdb_stdout);
if (handle_stop_requested (ecs))
return;
- observer_notify_no_history ();
+ gdb::observers::no_history.notify ();
stop_waiting (ecs);
return;
}
{
/* The signal table tells us to print about this signal. */
target_terminal::ours_for_output ();
- observer_notify_signal_received (ecs->event_thread->suspend.stop_signal);
+ gdb::observers::signal_received.notify (ecs->event_thread->suspend.stop_signal);
target_terminal::inferior ();
}
CORE_ADDR handler;
struct breakpoint *bp;
- vsym = lookup_symbol (SYMBOL_LINKAGE_NAME (sym), b, VAR_DOMAIN, NULL);
+ vsym = lookup_symbol_search_name (SYMBOL_SEARCH_NAME (sym),
+ b, VAR_DOMAIN);
value = read_var_value (vsym.symbol, vsym.block, frame);
/* If the value was optimized out, revert to the old behavior. */
if (! value_optimized_out (value))
CFA and the HANDLER. We ignore the CFA, extract the handler, and
set a breakpoint there. */
probe = find_probe_by_pc (get_frame_pc (frame));
- if (probe.probe)
+ if (probe.prob)
{
insert_exception_resume_from_probe (ecs->event_thread, &probe, frame);
return;
static void
keep_going_pass_signal (struct execution_control_state *ecs)
{
- /* Make sure normal_stop is called if we get a QUIT handled before
- reaching resume. */
- struct cleanup *old_cleanups = make_cleanup (resume_cleanups, 0);
-
gdb_assert (ptid_equal (ecs->event_thread->ptid, inferior_ptid));
gdb_assert (!ecs->event_thread->resumed);
non-signal event (e.g., a fork); or took a signal which we
are supposed to pass through to the inferior. Simply
continue. */
- discard_cleanups (old_cleanups);
resume (ecs->event_thread->suspend.stop_signal);
}
else if (step_over_info_valid_p ())
"resume of %s deferred\n",
target_pid_to_str (tp->ptid));
}
-
- discard_cleanups (old_cleanups);
}
else
{
{
exception_print (gdb_stderr, e);
stop_waiting (ecs);
- discard_cleanups (old_cleanups);
+ clear_step_over_info ();
return;
}
END_CATCH
ecs->event_thread->control.trap_expected = (remove_bp || remove_wps);
- discard_cleanups (old_cleanups);
resume (ecs->event_thread->suspend.stop_signal);
}
update_thread_list ();
if (last.kind == TARGET_WAITKIND_STOPPED && stopped_by_random_signal)
- observer_notify_signal_received (inferior_thread ()->suspend.stop_signal);
+ gdb::observers::signal_received.notify (inferior_thread ()->suspend.stop_signal);
/* As with the notification of thread events, we want to delay
notifying the user that we've switched thread context until
/* Notify observers about the stop. This is where the interpreters
print the stop event. */
if (!ptid_equal (inferior_ptid, null_ptid))
- observer_notify_normal_stop (inferior_thread ()->control.stop_bpstat,
+ gdb::observers::normal_stop.notify (inferior_thread ()->control.stop_bpstat,
stop_print_frame);
else
- observer_notify_normal_stop (NULL, stop_print_frame);
+ gdb::observers::normal_stop.notify (NULL, stop_print_frame);
annotate_stopped ();
targets, all signals should be in the signal tables). */
static void
-info_signals_command (char *signum_exp, int from_tty)
+info_signals_command (const char *signum_exp, int from_tty)
{
enum gdb_signal oursig;
/* Other fields: */
CORE_ADDR stop_pc;
- struct regcache *registers;
+ readonly_detached_regcache *registers;
/* Format of SIGINFO_DATA or NULL if it is not present. */
struct gdbarch *siginfo_gdbarch;
inf_state->stop_pc = stop_pc;
- inf_state->registers = regcache_dup (regcache);
+ inf_state->registers = new readonly_detached_regcache (*regcache);
return inf_state;
}
(and perhaps other times). */
if (target_has_execution)
/* NB: The register write goes through to the target. */
- regcache_cpy (regcache, inf_state->registers);
+ regcache->restore (inf_state->registers);
discard_infcall_suspend_state (inf_state);
}
xfree (inf_state);
}
-struct regcache *
+readonly_detached_regcache *
get_infcall_suspend_state_regcache (struct infcall_suspend_state *inf_state)
{
return inf_state->registers;
};
static void
-set_exec_direction_func (char *args, int from_tty,
+set_exec_direction_func (const char *args, int from_tty,
struct cmd_list_element *cmd)
{
if (target_can_execute_reverse)
inferior_ptid = null_ptid;
target_last_wait_ptid = minus_one_ptid;
- observer_attach_thread_ptid_changed (infrun_thread_ptid_changed);
- observer_attach_thread_stop_requested (infrun_thread_stop_requested);
- observer_attach_thread_exit (infrun_thread_thread_exit);
- observer_attach_inferior_exit (infrun_inferior_exit);
+ gdb::observers::thread_ptid_changed.attach (infrun_thread_ptid_changed);
+ gdb::observers::thread_stop_requested.attach (infrun_thread_stop_requested);
+ gdb::observers::thread_exit.attach (infrun_thread_thread_exit);
+ gdb::observers::inferior_exit.attach (infrun_inferior_exit);
/* Explicitly create without lookup, since that tries to create a
value with a void typed value, and when we get here, gdbarch