/* Target-struct-independent code to start (run) and stop an inferior
process.
- Copyright (C) 1986-2016 Free Software Foundation, Inc.
+ Copyright (C) 1986-2019 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"
#include "event-loop.h"
#include "thread-fsm.h"
#include "common/enum-flags.h"
+#include "progspace-and-thread.h"
+#include "common/gdb_optional.h"
+#include "arch-utils.h"
/* Prototypes for local functions */
-static void signals_info (char *, int);
-
-static void handle_command (char *, int);
-
static void sig_print_info (enum gdb_signal);
static void sig_print_header (void);
-static void resume_cleanups (void *);
-
-static int hook_stop_stub (void *);
-
-static int restore_selected_frame (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 _initialize_infrun (void);
-
void nullify_last_target_wait_ptid (void);
static void insert_hp_step_resume_breakpoint_at_frame (struct frame_info *);
static int maybe_software_singlestep (struct gdbarch *gdbarch, CORE_ADDR pc);
+static void resume (gdb_signal sig);
+
/* Asynchronous signal handler registered as event loop source for
when we have pending events ready to be passed to the core. */
static struct async_event_handler *infrun_async_inferior_event_token;
}
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 ();
}
static ptid_t target_last_wait_ptid;
static struct target_waitstatus target_last_waitstatus;
-static void context_switch (ptid_t ptid);
-
void init_thread_stepping_state (struct thread_info *tss);
static const char follow_fork_mode_child[] = "child";
if (has_vforked)
{
/* Keep breakpoints list in sync. */
- remove_breakpoints_pid (ptid_get_pid (inferior_ptid));
+ remove_breakpoints_inf (current_inferior ());
}
- if (info_verbose || debug_infrun)
+ if (print_inferior_events)
{
/* Ensure that we have a process ptid. */
- ptid_t process_ptid = pid_to_ptid (ptid_get_pid (child_ptid));
+ ptid_t process_ptid = ptid_t (child_ptid.pid ());
- target_terminal_ours_for_output ();
+ target_terminal::ours_for_output ();
fprintf_filtered (gdb_stdlog,
- _("Detaching after %s from child %s.\n"),
+ _("[Detaching after %s from child %s]\n"),
has_vforked ? "vfork" : "fork",
target_pid_to_str (process_ptid));
}
else
{
struct inferior *parent_inf, *child_inf;
- struct cleanup *old_chain;
/* Add process to GDB's tables. */
- child_inf = add_inferior (ptid_get_pid (child_ptid));
+ child_inf = add_inferior (child_ptid.pid ());
parent_inf = current_inferior ();
child_inf->attach_flag = parent_inf->attach_flag;
child_inf->gdbarch = parent_inf->gdbarch;
copy_inferior_target_desc_info (child_inf, parent_inf);
- old_chain = save_inferior_ptid ();
- save_current_program_space ();
+ scoped_restore_current_pspace_and_thread restore_pspace_thread;
inferior_ptid = child_ptid;
- add_thread (inferior_ptid);
+ add_thread_silent (inferior_ptid);
+ set_current_inferior (child_inf);
child_inf->symfile_flags = SYMFILE_NO_READ;
/* If this is a vfork child, then the address-space is
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);
required. */
solib_create_inferior_hook (0);
}
-
- do_cleanups (old_chain);
}
if (has_vforked)
struct inferior *parent_inf, *child_inf;
struct program_space *parent_pspace;
- if (info_verbose || debug_infrun)
+ if (print_inferior_events)
{
- target_terminal_ours_for_output ();
+ std::string parent_pid = target_pid_to_str (parent_ptid);
+ std::string child_pid = target_pid_to_str (child_ptid);
+
+ target_terminal::ours_for_output ();
fprintf_filtered (gdb_stdlog,
- _("Attaching after %s %s to child %s.\n"),
- target_pid_to_str (parent_ptid),
+ _("[Attaching after %s %s to child %s]\n"),
+ parent_pid.c_str (),
has_vforked ? "vfork" : "fork",
- target_pid_to_str (child_ptid));
+ child_pid.c_str ());
}
/* Add the new inferior first, so that the target_detach below
doesn't unpush the target. */
- child_inf = add_inferior (ptid_get_pid (child_ptid));
+ child_inf = add_inferior (child_ptid.pid ());
parent_inf = current_inferior ();
child_inf->attach_flag = parent_inf->attach_flag;
}
else if (detach_fork)
{
- if (info_verbose || debug_infrun)
+ if (print_inferior_events)
{
/* Ensure that we have a process ptid. */
- ptid_t process_ptid = pid_to_ptid (ptid_get_pid (child_ptid));
+ ptid_t process_ptid = ptid_t (parent_ptid.pid ());
- target_terminal_ours_for_output ();
+ target_terminal::ours_for_output ();
fprintf_filtered (gdb_stdlog,
- _("Detaching after fork from "
- "child %s.\n"),
+ _("[Detaching after fork from "
+ "parent %s]\n"),
target_pid_to_str (process_ptid));
}
- target_detach (NULL, 0);
+ target_detach (parent_inf, 0);
}
/* Note that the detach above makes PARENT_INF dangling. */
informing the solib layer about this new process. */
inferior_ptid = child_ptid;
- add_thread (inferior_ptid);
+ add_thread_silent (inferior_ptid);
+ set_current_inferior (child_inf);
/* If this is a vfork child, then the address-space is shared
with the parent. If we detached from the parent, then we can
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);
/* Check if we switched over from WAIT_PTID, since the event was
reported. */
- if (!ptid_equal (wait_ptid, minus_one_ptid)
- && !ptid_equal (inferior_ptid, wait_ptid))
+ if (wait_ptid != minus_one_ptid
+ && inferior_ptid != wait_ptid)
{
/* We did. Switch back to WAIT_PTID thread, to tell the
target to follow it (in either direction). We'll
afterwards refuse to resume, and inform the user what
happened. */
- switch_to_thread (wait_ptid);
+ thread_info *wait_thread
+ = find_thread_ptid (wait_ptid);
+ switch_to_thread (wait_thread);
should_resume = 0;
}
}
/* If we followed the child, switch to it... */
if (follow_child)
{
- switch_to_thread (child);
+ thread_info *child_thr = find_thread_ptid (child);
+ switch_to_thread (child_thr);
/* ... and preserve the stepping state, in case the
user was stepping over the fork call. */
/* Reset breakpoints in the child as appropriate. */
follow_inferior_reset_breakpoints ();
}
- else
- switch_to_thread (parent);
}
}
break;
{
int pid = * (int *) arg;
- if (ptid_get_pid (thread->ptid) == pid
- && is_running (thread->ptid)
- && !is_executing (thread->ptid)
+ if (thread->ptid.pid () == pid
+ && thread->state == THREAD_RUNNING
+ && !thread->executing
&& !thread->stop_requested
&& thread->suspend.stop_signal == GDB_SIGNAL_0)
{
"infrun: resuming vfork parent thread %s\n",
target_pid_to_str (thread->ptid));
- switch_to_thread (thread->ptid);
+ switch_to_thread (thread);
clear_proceed_status (0);
proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT);
}
return 0;
}
+/* Save/restore inferior_ptid, current program space and current
+ inferior. Only use this if the current context points at an exited
+ inferior (and therefore there's no current thread to save). */
+class scoped_restore_exited_inferior
+{
+public:
+ scoped_restore_exited_inferior ()
+ : m_saved_ptid (&inferior_ptid)
+ {}
+
+private:
+ scoped_restore_tmpl<ptid_t> m_saved_ptid;
+ scoped_restore_current_program_space m_pspace;
+ scoped_restore_current_inferior m_inferior;
+};
+
/* Called whenever we notice an exec or exit event, to handle
detaching or resuming a vfork parent. */
if (inf->vfork_parent->pending_detach)
{
struct thread_info *tp;
- struct cleanup *old_chain;
struct program_space *pspace;
struct address_space *aspace;
inf->vfork_parent->pending_detach = 0;
+ gdb::optional<scoped_restore_exited_inferior>
+ maybe_restore_inferior;
+ gdb::optional<scoped_restore_current_pspace_and_thread>
+ maybe_restore_thread;
+
+ /* If we're handling a child exit, then inferior_ptid points
+ at the inferior's pid, not to a thread. */
if (!exec)
- {
- /* If we're handling a child exit, then inferior_ptid
- points at the inferior's pid, not to a thread. */
- old_chain = save_inferior_ptid ();
- save_current_program_space ();
- save_current_inferior ();
- }
+ maybe_restore_inferior.emplace ();
else
- old_chain = save_current_space_and_thread ();
+ maybe_restore_thread.emplace ();
/* We're letting loose of the parent. */
- tp = any_live_thread_of_process (inf->vfork_parent->pid);
- switch_to_thread (tp->ptid);
+ tp = any_live_thread_of_inferior (inf->vfork_parent);
+ switch_to_thread (tp);
/* We're about to detach from the parent, which implicitly
removes breakpoints from its address space. There's a
inf->aspace = NULL;
inf->pspace = NULL;
- if (debug_infrun || info_verbose)
+ if (print_inferior_events)
{
- target_terminal_ours_for_output ();
+ const char *pidstr
+ = target_pid_to_str (ptid_t (inf->vfork_parent->pid));
+
+ target_terminal::ours_for_output ();
if (exec)
{
fprintf_filtered (gdb_stdlog,
- _("Detaching vfork parent process "
- "%d after child exec.\n"),
- inf->vfork_parent->pid);
+ _("[Detaching vfork parent %s "
+ "after child exec]\n"), pidstr);
}
else
{
fprintf_filtered (gdb_stdlog,
- _("Detaching vfork parent process "
- "%d after child exit.\n"),
- inf->vfork_parent->pid);
+ _("[Detaching vfork parent %s "
+ "after child exit]\n"), pidstr);
}
}
- target_detach (NULL, 0);
+ target_detach (inf->vfork_parent, 0);
/* Put it back. */
inf->pspace = pspace;
inf->aspace = aspace;
-
- do_cleanups (old_chain);
}
else if (exec)
{
/* 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);
}
else
{
- struct cleanup *old_chain;
struct program_space *pspace;
/* If this is a vfork child exiting, then the pspace and
go ahead and create a new one for this exiting
inferior. */
- /* Switch to null_ptid, so that clone_program_space doesn't want
- to read the selected frame of a dead process. */
- old_chain = save_inferior_ptid ();
- inferior_ptid = null_ptid;
+ /* Switch to null_ptid while running clone_program_space, so
+ that clone_program_space doesn't want to read the
+ selected frame of a dead process. */
+ scoped_restore restore_ptid
+ = make_scoped_restore (&inferior_ptid, null_ptid);
/* This inferior is dead, so avoid giving the breakpoints
module the option to write through to it (cloning a
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;
inf->pspace = pspace;
inf->aspace = pspace->aspace;
- /* Put back inferior_ptid. We'll continue mourning this
- inferior. */
- do_cleanups (old_chain);
-
resume_parent = inf->vfork_parent->pid;
/* Break the bonds. */
inf->vfork_parent->vfork_child = NULL;
{
/* If the user wanted the parent to be running, let it go
free now. */
- struct cleanup *old_chain = make_cleanup_restore_current_thread ();
+ scoped_restore_current_thread restore_thread;
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog,
resume_parent);
iterate_over_threads (proceed_after_vfork_done, &resume_parent);
-
- do_cleanups (old_chain);
}
}
}
fprintf_filtered (file, _("Follow exec mode is \"%s\".\n"), value);
}
-/* EXECD_PATHNAME is assumed to be non-NULL. */
+/* EXEC_FILE_TARGET is assumed to be non-NULL. */
static void
-follow_exec (ptid_t ptid, char *execd_pathname)
+follow_exec (ptid_t ptid, char *exec_file_target)
{
- struct thread_info *th, *tmp;
struct inferior *inf = current_inferior ();
- int pid = ptid_get_pid (ptid);
+ int pid = ptid.pid ();
ptid_t process_ptid;
/* This is an exec event that we actually wish to pay attention to.
them. Deleting them now rather than at the next user-visible
stop provides a nicer sequence of events for user and MI
notifications. */
- ALL_THREADS_SAFE (th, tmp)
- if (ptid_get_pid (th->ptid) == pid && !ptid_equal (th->ptid, ptid))
- delete_thread (th->ptid);
+ for (thread_info *th : all_threads_safe ())
+ if (th->ptid.pid () == pid && th->ptid != ptid)
+ delete_thread (th);
/* We also need to clear any left over stale state for the
leader/event thread. E.g., if there was any step-resume
breakpoint or similar, it's gone now. We cannot truly
step-to-next statement through an exec(). */
- th = inferior_thread ();
+ thread_info *th = inferior_thread ();
th->control.step_resume_breakpoint = NULL;
th->control.exception_resume_breakpoint = NULL;
th->control.single_step_breakpoints = NULL;
update_breakpoints_after_exec ();
/* What is this a.out's name? */
- process_ptid = pid_to_ptid (pid);
+ process_ptid = ptid_t (pid);
printf_unfiltered (_("%s is executing new program: %s\n"),
target_pid_to_str (process_ptid),
- execd_pathname);
+ exec_file_target);
/* We've followed the inferior through an exec. Therefore, the
inferior has essentially been killed & reborn. */
breakpoint_init_inferior (inf_execd);
- if (*gdb_sysroot != '\0')
- {
- char *name = exec_file_find (execd_pathname, NULL);
+ gdb::unique_xmalloc_ptr<char> exec_file_host
+ = exec_file_find (exec_file_target, NULL);
- execd_pathname = (char *) alloca (strlen (name) + 1);
- strcpy (execd_pathname, name);
- xfree (name);
- }
+ /* If we were unable to map the executable target pathname onto a host
+ pathname, tell the user that. Otherwise GDB's subsequent behavior
+ is confusing. Maybe it would even be better to stop at this point
+ so that the user can specify a file manually before continuing. */
+ if (exec_file_host == NULL)
+ warning (_("Could not load symbols for executable %s.\n"
+ "Do you need \"set sysroot\"?"),
+ exec_file_target);
/* Reset the shared library package. This ensures that we get a
shlib event when the child reaches "_start", at which point the
/* The user wants to keep the old inferior and program spaces
around. Create a new fresh one, and switch to it. */
- /* Do exit processing for the original inferior before adding
- the new inferior so we don't have two active inferiors with
- the same ptid, which can confuse find_inferior_ptid. */
- exit_inferior_num_silent (current_inferior ()->num);
-
+ /* Do exit processing for the original inferior before setting the new
+ inferior's pid. Having two inferiors with the same pid would confuse
+ find_inferior_p(t)id. Transfer the terminal state and info from the
+ old to the new inferior. */
inf = add_inferior_with_spaces ();
+ swap_terminal_info (inf, current_inferior ());
+ exit_inferior_silent (current_inferior ());
+
inf->pid = pid;
- target_follow_exec (inf, execd_pathname);
+ target_follow_exec (inf, exec_file_target);
set_current_inferior (inf);
set_current_program_space (inf->pspace);
gdb_assert (current_program_space == inf->pspace);
- /* That a.out is now the one to use. */
- exec_file_attach (execd_pathname, 0);
-
- /* SYMFILE_DEFER_BP_RESET is used as the proper displacement for PIE
- (Position Independent Executable) main symbol file will get applied by
- solib_create_inferior_hook below. breakpoint_re_set would fail to insert
- the breakpoints with the zero displacement. */
-
- symbol_file_add (execd_pathname,
- (inf->symfile_flags
- | SYMFILE_MAINLINE | SYMFILE_DEFER_BP_RESET),
- NULL, 0);
-
- if ((inf->symfile_flags & SYMFILE_NO_READ) == 0)
- set_initial_language ();
+ /* Attempt to open the exec file. SYMFILE_DEFER_BP_RESET is used
+ because the proper displacement for a PIE (Position Independent
+ 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.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
and address of the instruction the breakpoint is set at. We'll
skip inserting all breakpoints here. Valid iff ASPACE is
non-NULL. */
- struct address_space *aspace;
+ const address_space *aspace;
CORE_ADDR address;
/* The instruction being stepped over triggers a nonsteppable
static struct step_over_info step_over_info;
/* Record the address of the breakpoint/instruction we're currently
- stepping over. */
+ stepping over.
+ N.B. We record the aspace and address now, instead of say just the thread,
+ because when we need the info later the thread may be running. */
static void
-set_step_over_info (struct address_space *aspace, CORE_ADDR address,
+set_step_over_info (const address_space *aspace, CORE_ADDR address,
int nonsteppable_watchpoint_p,
int thread)
{
same effect the instruction would have had if we had executed it
at its original address. We use this in step n3.
- - gdbarch_displaced_step_free_closure provides cleanup.
-
The gdbarch_displaced_step_copy_insn and
gdbarch_displaced_step_fixup functions must be written so that
copying an instruction with gdbarch_displaced_step_copy_insn,
displaced step operation on it. See displaced_step_prepare and
displaced_step_fixup for details. */
-/* Per-inferior displaced stepping state. */
-struct displaced_step_inferior_state
-{
- /* Pointer to next in linked list. */
- struct displaced_step_inferior_state *next;
-
- /* The process this displaced step state refers to. */
- int pid;
-
- /* True if preparing a displaced step ever failed. If so, we won't
- try displaced stepping for this inferior again. */
- int failed_before;
-
- /* If this is not null_ptid, this is the thread carrying out a
- displaced single-step in process PID. This thread's state will
- require fixing up once it has completed its step. */
- ptid_t step_ptid;
-
- /* The architecture the thread had when we stepped it. */
- struct gdbarch *step_gdbarch;
+/* Default destructor for displaced_step_closure. */
- /* The closure provided gdbarch_displaced_step_copy_insn, to be used
- for post-step cleanup. */
- struct displaced_step_closure *step_closure;
-
- /* The address of the original instruction, and the copy we
- made. */
- CORE_ADDR step_original, step_copy;
-
- /* Saved contents of copy area. */
- gdb_byte *step_saved_copy;
-};
-
-/* The list of states of processes involved in displaced stepping
- presently. */
-static struct displaced_step_inferior_state *displaced_step_inferior_states;
+displaced_step_closure::~displaced_step_closure () = default;
/* Get the displaced stepping state of process PID. */
-static struct displaced_step_inferior_state *
-get_displaced_stepping_state (int pid)
+static displaced_step_inferior_state *
+get_displaced_stepping_state (inferior *inf)
{
- struct displaced_step_inferior_state *state;
-
- for (state = displaced_step_inferior_states;
- state != NULL;
- state = state->next)
- if (state->pid == pid)
- return state;
-
- return NULL;
+ return &inf->displaced_step_state;
}
/* Returns true if any inferior has a thread doing a displaced
step. */
-static int
-displaced_step_in_progress_any_inferior (void)
+static bool
+displaced_step_in_progress_any_inferior ()
{
- struct displaced_step_inferior_state *state;
-
- for (state = displaced_step_inferior_states;
- state != NULL;
- state = state->next)
- if (!ptid_equal (state->step_ptid, null_ptid))
- return 1;
+ for (inferior *i : all_inferiors ())
+ {
+ if (i->displaced_step_state.step_thread != nullptr)
+ return true;
+ }
- return 0;
+ return false;
}
/* Return true if thread represented by PTID is doing a displaced
step. */
static int
-displaced_step_in_progress_thread (ptid_t ptid)
+displaced_step_in_progress_thread (thread_info *thread)
{
- struct displaced_step_inferior_state *displaced;
-
- gdb_assert (!ptid_equal (ptid, null_ptid));
+ gdb_assert (thread != NULL);
- displaced = get_displaced_stepping_state (ptid_get_pid (ptid));
-
- return (displaced != NULL && ptid_equal (displaced->step_ptid, ptid));
+ return get_displaced_stepping_state (thread->inf)->step_thread == thread;
}
/* Return true if process PID has a thread doing a displaced step. */
static int
-displaced_step_in_progress (int pid)
+displaced_step_in_progress (inferior *inf)
{
- struct displaced_step_inferior_state *displaced;
-
- displaced = get_displaced_stepping_state (pid);
- if (displaced != NULL && !ptid_equal (displaced->step_ptid, null_ptid))
- return 1;
-
- return 0;
-}
-
-/* Add a new displaced stepping state for process PID to the displaced
- stepping state list, or return a pointer to an already existing
- entry, if it already exists. Never returns NULL. */
-
-static struct displaced_step_inferior_state *
-add_displaced_stepping_state (int pid)
-{
- struct displaced_step_inferior_state *state;
-
- for (state = displaced_step_inferior_states;
- state != NULL;
- state = state->next)
- if (state->pid == pid)
- return state;
-
- state = XCNEW (struct displaced_step_inferior_state);
- state->pid = pid;
- state->next = displaced_step_inferior_states;
- displaced_step_inferior_states = state;
-
- return state;
+ return get_displaced_stepping_state (inf)->step_thread != nullptr;
}
/* If inferior is in displaced stepping, and ADDR equals to starting address
struct displaced_step_closure*
get_displaced_step_closure_by_addr (CORE_ADDR addr)
{
- struct displaced_step_inferior_state *displaced
- = get_displaced_stepping_state (ptid_get_pid (inferior_ptid));
+ displaced_step_inferior_state *displaced
+ = get_displaced_stepping_state (current_inferior ());
/* If checking the mode of displaced instruction in copy area. */
- if (displaced && !ptid_equal (displaced->step_ptid, null_ptid)
- && (displaced->step_copy == addr))
+ if (displaced->step_thread != nullptr
+ && displaced->step_copy == addr)
return displaced->step_closure;
return NULL;
}
-/* Remove the displaced stepping state of process PID. */
-
-static void
-remove_displaced_stepping_state (int pid)
-{
- struct displaced_step_inferior_state *it, **prev_next_p;
-
- gdb_assert (pid != 0);
-
- it = displaced_step_inferior_states;
- prev_next_p = &displaced_step_inferior_states;
- while (it)
- {
- if (it->pid == pid)
- {
- *prev_next_p = it->next;
- xfree (it);
- return;
- }
-
- prev_next_p = &it->next;
- it = *prev_next_p;
- }
-}
-
static void
infrun_inferior_exit (struct inferior *inf)
{
- remove_displaced_stepping_state (inf->pid);
+ inf->displaced_step_state.reset ();
}
/* If ON, and the architecture supports it, GDB will use displaced
static int
use_displaced_stepping (struct thread_info *tp)
{
- struct regcache *regcache = get_thread_regcache (tp->ptid);
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
- struct displaced_step_inferior_state *displaced_state;
-
- displaced_state = get_displaced_stepping_state (ptid_get_pid (tp->ptid));
+ struct regcache *regcache = get_thread_regcache (tp);
+ struct gdbarch *gdbarch = regcache->arch ();
+ displaced_step_inferior_state *displaced_state
+ = get_displaced_stepping_state (tp->inf);
return (((can_use_displaced_stepping == AUTO_BOOLEAN_AUTO
&& target_is_non_stop_p ())
|| can_use_displaced_stepping == AUTO_BOOLEAN_TRUE)
&& gdbarch_displaced_step_copy_insn_p (gdbarch)
&& find_record_target () == NULL
- && (displaced_state == NULL
- || !displaced_state->failed_before));
+ && !displaced_state->failed_before);
}
/* Clean out any stray displaced stepping state. */
displaced_step_clear (struct displaced_step_inferior_state *displaced)
{
/* Indicate that there is no cleanup pending. */
- displaced->step_ptid = null_ptid;
+ displaced->step_thread = nullptr;
- if (displaced->step_closure)
- {
- gdbarch_displaced_step_free_closure (displaced->step_gdbarch,
- displaced->step_closure);
- displaced->step_closure = NULL;
- }
+ delete displaced->step_closure;
+ displaced->step_closure = NULL;
}
static void
if this instruction can't be displaced stepped. */
static int
-displaced_step_prepare_throw (ptid_t ptid)
+displaced_step_prepare_throw (thread_info *tp)
{
- struct cleanup *old_cleanups, *ignore_cleanups;
- struct thread_info *tp = find_thread_ptid (ptid);
- struct regcache *regcache = get_thread_regcache (ptid);
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
- struct address_space *aspace = get_regcache_aspace (regcache);
+ regcache *regcache = get_thread_regcache (tp);
+ struct gdbarch *gdbarch = regcache->arch ();
+ const address_space *aspace = regcache->aspace ();
CORE_ADDR original, copy;
ULONGEST len;
struct displaced_step_closure *closure;
- struct displaced_step_inferior_state *displaced;
int status;
/* We should never reach this function if the architecture does not
/* We have to displaced step one thread at a time, as we only have
access to a single scratch space per inferior. */
- displaced = add_displaced_stepping_state (ptid_get_pid (ptid));
+ displaced_step_inferior_state *displaced
+ = get_displaced_stepping_state (tp->inf);
- if (!ptid_equal (displaced->step_ptid, null_ptid))
+ if (displaced->step_thread != nullptr)
{
/* Already waiting for a displaced step to finish. Defer this
request and place in queue. */
if (debug_displaced)
fprintf_unfiltered (gdb_stdlog,
"displaced: deferring step of %s\n",
- target_pid_to_str (ptid));
+ target_pid_to_str (tp->ptid));
thread_step_over_chain_enqueue (tp);
return 0;
if (debug_displaced)
fprintf_unfiltered (gdb_stdlog,
"displaced: stepping %s now\n",
- target_pid_to_str (ptid));
+ target_pid_to_str (tp->ptid));
}
displaced_step_clear (displaced);
- old_cleanups = save_inferior_ptid ();
- inferior_ptid = ptid;
+ scoped_restore_current_thread restore_thread;
+
+ switch_to_thread (tp);
original = regcache_read_pc (regcache);
"Stepping over breakpoint in-line instead.\n");
}
- do_cleanups (old_cleanups);
return -1;
}
/* Save the original contents of the copy area. */
- displaced->step_saved_copy = (gdb_byte *) xmalloc (len);
- ignore_cleanups = make_cleanup (free_current_contents,
- &displaced->step_saved_copy);
- status = target_read_memory (copy, displaced->step_saved_copy, len);
+ displaced->step_saved_copy.resize (len);
+ status = target_read_memory (copy, displaced->step_saved_copy.data (), len);
if (status != 0)
throw_error (MEMORY_ERROR,
_("Error accessing memory address %s (%s) for "
fprintf_unfiltered (gdb_stdlog, "displaced: saved %s: ",
paddress (gdbarch, copy));
displaced_step_dump_bytes (gdb_stdlog,
- displaced->step_saved_copy,
+ displaced->step_saved_copy.data (),
len);
};
/* The architecture doesn't know how or want to displaced step
this instruction or instruction sequence. Fallback to
stepping over the breakpoint in-line. */
- do_cleanups (old_cleanups);
return -1;
}
/* Save the information we need to fix things up if the step
succeeds. */
- displaced->step_ptid = ptid;
+ displaced->step_thread = tp;
displaced->step_gdbarch = gdbarch;
displaced->step_closure = closure;
displaced->step_original = original;
displaced->step_copy = copy;
- make_cleanup (displaced_step_clear_cleanup, displaced);
+ cleanup *ignore_cleanups
+ = make_cleanup (displaced_step_clear_cleanup, displaced);
/* Resume execution at the copy. */
regcache_write_pc (regcache, copy);
discard_cleanups (ignore_cleanups);
- do_cleanups (old_cleanups);
-
if (debug_displaced)
fprintf_unfiltered (gdb_stdlog, "displaced: displaced pc to %s\n",
paddress (gdbarch, copy));
attempts at displaced stepping if we get a memory error. */
static int
-displaced_step_prepare (ptid_t ptid)
+displaced_step_prepare (thread_info *thread)
{
int prepared = -1;
TRY
{
- prepared = displaced_step_prepare_throw (ptid);
+ prepared = displaced_step_prepare_throw (thread);
}
CATCH (ex, RETURN_MASK_ERROR)
{
/* Disable further displaced stepping attempts. */
displaced_state
- = get_displaced_stepping_state (ptid_get_pid (ptid));
+ = get_displaced_stepping_state (thread->inf);
displaced_state->failed_before = 1;
}
END_CATCH
write_memory_ptid (ptid_t ptid, CORE_ADDR memaddr,
const gdb_byte *myaddr, int len)
{
- struct cleanup *ptid_cleanup = save_inferior_ptid ();
+ scoped_restore save_inferior_ptid = make_scoped_restore (&inferior_ptid);
inferior_ptid = ptid;
write_memory (memaddr, myaddr, len);
- do_cleanups (ptid_cleanup);
}
/* Restore the contents of the copy area for thread PTID. */
ULONGEST len = gdbarch_max_insn_length (displaced->step_gdbarch);
write_memory_ptid (ptid, displaced->step_copy,
- displaced->step_saved_copy, len);
+ displaced->step_saved_copy.data (), len);
if (debug_displaced)
fprintf_unfiltered (gdb_stdlog, "displaced: restored %s %s\n",
target_pid_to_str (ptid),
-1. If the thread wasn't displaced stepping, return 0. */
static int
-displaced_step_fixup (ptid_t event_ptid, enum gdb_signal signal)
+displaced_step_fixup (thread_info *event_thread, enum gdb_signal signal)
{
struct cleanup *old_cleanups;
struct displaced_step_inferior_state *displaced
- = get_displaced_stepping_state (ptid_get_pid (event_ptid));
+ = get_displaced_stepping_state (event_thread->inf);
int ret;
- /* Was any thread of this process doing a displaced step? */
- if (displaced == NULL)
- return 0;
-
- /* Was this event for the pid we displaced? */
- if (ptid_equal (displaced->step_ptid, null_ptid)
- || ! ptid_equal (displaced->step_ptid, event_ptid))
+ /* Was this event for the thread we displaced? */
+ if (displaced->step_thread != event_thread)
return 0;
old_cleanups = make_cleanup (displaced_step_clear_cleanup, displaced);
- displaced_step_restore (displaced, displaced->step_ptid);
+ displaced_step_restore (displaced, displaced->step_thread->ptid);
/* Fixup may need to read memory/registers. Switch to the thread
that we're fixing up. Also, target_stopped_by_watchpoint checks
the current thread. */
- switch_to_thread (event_ptid);
+ switch_to_thread (event_thread);
/* Did the instruction complete successfully? */
if (signal == GDB_SIGNAL_TRAP
displaced->step_closure,
displaced->step_original,
displaced->step_copy,
- get_thread_regcache (displaced->step_ptid));
+ get_thread_regcache (displaced->step_thread));
ret = 1;
}
else
{
/* Since the instruction didn't complete, all we can do is
relocate the PC. */
- struct regcache *regcache = get_thread_regcache (event_ptid);
+ struct regcache *regcache = get_thread_regcache (event_thread);
CORE_ADDR pc = regcache_read_pc (regcache);
pc = displaced->step_original + (pc - displaced->step_copy);
do_cleanups (old_cleanups);
- displaced->step_ptid = null_ptid;
+ displaced->step_thread = nullptr;
return ret;
}
step_over_what step_what;
int must_be_in_line;
+ gdb_assert (!tp->stop_requested);
+
next = thread_step_over_chain_next (tp);
/* If this inferior already has a displaced step in process,
don't start a new one. */
- if (displaced_step_in_progress (ptid_get_pid (tp->ptid)))
+ if (displaced_step_in_progress (tp->inf))
continue;
step_what = thread_still_needs_step_over (tp);
if (!target_is_non_stop_p () && !step_what)
continue;
- switch_to_thread (tp->ptid);
+ switch_to_thread (tp);
reset_ecs (ecs, tp);
keep_going_pass_signal (ecs);
static void
infrun_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid)
{
- struct displaced_step_inferior_state *displaced;
-
- if (ptid_equal (inferior_ptid, old_ptid))
+ if (inferior_ptid == old_ptid)
inferior_ptid = new_ptid;
-
- for (displaced = displaced_step_inferior_states;
- displaced;
- displaced = displaced->next)
- {
- if (ptid_equal (displaced->step_ptid, old_ptid))
- displaced->step_ptid = new_ptid;
- }
}
\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)
{
int hw_step = 1;
if (execution_direction == EXEC_FORWARD
- && gdbarch_software_single_step_p (gdbarch)
- && gdbarch_software_single_step (gdbarch, get_current_frame ()))
- {
- hw_step = 0;
- }
+ && gdbarch_software_single_step_p (gdbarch))
+ hw_step = !insert_single_step_breakpoints (gdbarch);
+
return hw_step;
}
{
/* Resume all threads of the current process (and none of other
processes). */
- resume_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
+ resume_ptid = ptid_t (inferior_ptid.pid ());
}
else
{
{
struct thread_info *tp = inferior_thread ();
+ gdb_assert (!tp->stop_requested);
+
/* Install inferior's terminal modes. */
- target_terminal_inferior ();
+ target_terminal::inferior ();
/* Avoid confusing the next resume, if the next stop/resume
happens to apply to another thread. */
return to the scratch pad area, which would no longer be
valid. */
if (step_over_info_valid_p ()
- || displaced_step_in_progress (ptid_get_pid (tp->ptid)))
+ || displaced_step_in_progress (tp->inf))
target_pass_signals (0, NULL);
else
target_pass_signals ((int) GDB_SIGNAL_LAST, signal_pass);
target_resume (resume_ptid, step, sig);
+
+ 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 = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = regcache->arch ();
struct thread_info *tp = inferior_thread ();
CORE_ADDR pc = regcache_read_pc (regcache);
- struct address_space *aspace = get_regcache_aspace (regcache);
+ const address_space *aspace = regcache->aspace ();
ptid_t resume_ptid;
/* This represents the user's step vs continue request. When
deciding whether "set scheduler-locking step" applies, it's the
single-step). */
int step;
+ gdb_assert (!tp->stop_requested);
gdb_assert (!thread_is_in_step_over_chain (tp));
- QUIT;
-
if (tp->suspend.waitstatus_pending_p)
{
if (debug_infrun)
{
- char *statstr;
+ std::string statstr
+ = target_waitstatus_to_string (&tp->suspend.waitstatus);
- statstr = target_waitstatus_to_string (&tp->suspend.waitstatus);
fprintf_unfiltered (gdb_stdlog,
- "infrun: resume: thread %s has pending wait status %s "
- "(currently_stepping=%d).\n",
- target_pid_to_str (tp->ptid), statstr,
+ "infrun: resume: thread %s has pending wait "
+ "status %s (currently_stepping=%d).\n",
+ target_pid_to_str (tp->ptid), statstr.c_str (),
currently_stepping (tp));
- xfree (statstr);
}
tp->resumed = 1;
}
tp->suspend.stop_signal = GDB_SIGNAL_0;
- discard_cleanups (old_cleanups);
if (target_can_async_p ())
- target_async (1);
+ {
+ target_async (1);
+ /* Tell the event loop we have an event to process. */
+ mark_async_event_handler (infrun_async_inferior_event_token);
+ }
return;
}
resume_ptid = internal_resume_ptid (user_step);
do_target_resume (resume_ptid, 0, GDB_SIGNAL_0);
- discard_cleanups (old_cleanups);
tp->resumed = 1;
return;
}
&& sig == GDB_SIGNAL_0
&& !current_inferior ()->waiting_for_vfork_done)
{
- int prepared = displaced_step_prepare (inferior_ptid);
+ int prepared = displaced_step_prepare (tp);
if (prepared == 0)
{
"Got placed in step-over queue\n");
tp->control.trap_expected = 0;
- discard_cleanups (old_cleanups);
return;
}
else if (prepared < 0)
if (target_is_non_stop_p ())
stop_all_threads ();
- set_step_over_info (get_regcache_aspace (regcache),
+ set_step_over_info (regcache->aspace (),
regcache_read_pc (regcache), 0, tp->global_num);
step = maybe_software_singlestep (gdbarch, pc);
/* Update pc to reflect the new address from which we will
execute instructions due to displaced stepping. */
- pc = regcache_read_pc (get_thread_regcache (inferior_ptid));
+ pc = regcache_read_pc (get_thread_regcache (tp));
- displaced = get_displaced_stepping_state (ptid_get_pid (inferior_ptid));
+ displaced = get_displaced_stepping_state (tp->inf);
step = gdbarch_displaced_step_hw_singlestep (gdbarch,
displaced->step_closure);
}
&& use_displaced_stepping (tp)
&& !step_over_info_valid_p ())
{
- struct regcache *resume_regcache = get_thread_regcache (tp->ptid);
- struct gdbarch *resume_gdbarch = get_regcache_arch (resume_regcache);
+ struct regcache *resume_regcache = get_thread_regcache (tp);
+ struct gdbarch *resume_gdbarch = resume_regcache->arch ();
CORE_ADDR actual_pc = regcache_read_pc (resume_regcache);
gdb_byte buf[4];
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. */
+
+static 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. */
}
else if (debug_infrun)
{
- char *statstr;
+ std::string statstr
+ = target_waitstatus_to_string (&tp->suspend.waitstatus);
- statstr = target_waitstatus_to_string (&tp->suspend.waitstatus);
fprintf_unfiltered (gdb_stdlog,
"infrun: clear_proceed_status_thread: thread %s "
"has pending wait status %s "
"(currently_stepping=%d).\n",
- target_pid_to_str (tp->ptid), statstr,
+ target_pid_to_str (tp->ptid), statstr.c_str (),
currently_stepping (tp));
- xfree (statstr);
}
}
execution_direction))
target_record_stop_replaying ();
- if (!non_stop)
+ if (!non_stop && inferior_ptid != null_ptid)
{
- struct thread_info *tp;
- ptid_t resume_ptid;
-
- resume_ptid = user_visible_resume_ptid (step);
+ ptid_t resume_ptid = user_visible_resume_ptid (step);
/* In all-stop mode, delete the per-thread status of all threads
we're about to resume, implicitly and explicitly. */
- ALL_NON_EXITED_THREADS (tp)
- {
- if (!ptid_match (tp->ptid, resume_ptid))
- continue;
- clear_proceed_status_thread (tp);
- }
+ for (thread_info *tp : all_non_exited_threads (resume_ptid))
+ clear_proceed_status_thread (tp);
}
- if (!ptid_equal (inferior_ptid, null_ptid))
+ if (inferior_ptid != null_ptid)
{
struct inferior *inferior;
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
{
if (tp->stepping_over_breakpoint)
{
- struct regcache *regcache = get_thread_regcache (tp->ptid);
+ struct regcache *regcache = get_thread_regcache (tp);
- if (breakpoint_here_p (get_regcache_aspace (regcache),
+ if (breakpoint_here_p (regcache->aspace (),
regcache_read_pc (regcache))
== ordinary_breakpoint_here)
return 1;
/* Basic routine for continuing the program in various fashions.
ADDR is the address to resume at, or -1 for resume where stopped.
- SIGGNAL is the signal to give it, or 0 for none,
- or -1 for act according to how it stopped.
- STEP is nonzero if should trap after one instruction.
- -1 means return after that and print nothing.
- You should probably set various step_... variables
- before calling here, if you are stepping.
+ SIGGNAL is the signal to give it, or GDB_SIGNAL_0 for none,
+ or GDB_SIGNAL_DEFAULT for act according to how it stopped.
You should call clear_proceed_status before calling proceed. */
{
struct regcache *regcache;
struct gdbarch *gdbarch;
- struct thread_info *tp;
CORE_ADDR pc;
- struct address_space *aspace;
ptid_t resume_ptid;
struct execution_control_state ecss;
struct execution_control_state *ecs = &ecss;
- struct cleanup *old_chain;
int started;
/* If we're stopped at a fork/vfork, follow the branch set by the
previous_inferior_ptid = inferior_ptid;
regcache = get_current_regcache ();
- gdbarch = get_regcache_arch (regcache);
- aspace = get_regcache_aspace (regcache);
+ gdbarch = regcache->arch ();
+ const address_space *aspace = regcache->aspace ();
+
pc = regcache_read_pc (regcache);
- tp = inferior_thread ();
+ thread_info *cur_thr = inferior_thread ();
/* Fill in with reasonable starting values. */
- init_thread_stepping_state (tp);
+ init_thread_stepping_state (cur_thr);
- gdb_assert (!thread_is_in_step_over_chain (tp));
+ gdb_assert (!thread_is_in_step_over_chain (cur_thr));
if (addr == (CORE_ADDR) -1)
{
- if (pc == stop_pc
+ if (pc == cur_thr->suspend.stop_pc
&& breakpoint_here_p (aspace, pc) == ordinary_breakpoint_here
&& execution_direction != EXEC_REVERSE)
/* There is a breakpoint at the address we will resume at,
Note, we don't do this in reverse, because we won't
actually be executing the breakpoint insn anyway.
We'll be (un-)executing the previous instruction. */
- tp->stepping_over_breakpoint = 1;
+ cur_thr->stepping_over_breakpoint = 1;
else if (gdbarch_single_step_through_delay_p (gdbarch)
&& gdbarch_single_step_through_delay (gdbarch,
get_current_frame ()))
/* We stepped onto an instruction that needs to be stepped
again before re-inserting the breakpoint, do so. */
- tp->stepping_over_breakpoint = 1;
+ cur_thr->stepping_over_breakpoint = 1;
}
else
{
}
if (siggnal != GDB_SIGNAL_DEFAULT)
- tp->suspend.stop_signal = siggnal;
+ cur_thr->suspend.stop_signal = siggnal;
- resume_ptid = user_visible_resume_ptid (tp->control.stepping_command);
+ resume_ptid = user_visible_resume_ptid (cur_thr->control.stepping_command);
/* If an exception is thrown from this point on, make sure to
propagate GDB's knowledge of the executing state to the
frontend/user running state. */
- old_chain = make_cleanup (finish_thread_state_cleanup, &resume_ptid);
+ scoped_finish_thread_state finish_state (resume_ptid);
/* Even if RESUME_PTID is a wildcard, and we end up resuming fewer
threads (e.g., we might need to set threads stepping over
threads in RESUME_PTID are now running. Unless we're calling an
inferior function, as in that case we pretend the inferior
doesn't run at all. */
- if (!tp->control.in_infcall)
+ if (!cur_thr->control.in_infcall)
set_running (resume_ptid, 1);
if (debug_infrun)
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.
/* If scheduler locking applies, we can avoid iterating over all
threads. */
- if (!non_stop && !schedlock_applies (tp))
+ if (!non_stop && !schedlock_applies (cur_thr))
{
- struct thread_info *current = tp;
-
- ALL_NON_EXITED_THREADS (tp)
- {
+ for (thread_info *tp : all_non_exited_threads (resume_ptid))
+ {
/* Ignore the current thread here. It's handled
afterwards. */
- if (tp == current)
- continue;
-
- /* Ignore threads of processes we're not resuming. */
- if (!ptid_match (tp->ptid, resume_ptid))
+ if (tp == cur_thr)
continue;
if (!thread_still_needs_step_over (tp))
thread_step_over_chain_enqueue (tp);
}
-
- tp = current;
}
/* Enqueue the current thread last, so that we move all other
threads over their breakpoints first. */
- if (tp->stepping_over_breakpoint)
- thread_step_over_chain_enqueue (tp);
+ if (cur_thr->stepping_over_breakpoint)
+ thread_step_over_chain_enqueue (cur_thr);
/* If the thread isn't started, we'll still need to set its prev_pc,
so that switch_back_to_stepped_thread knows the thread hasn't
advanced. Must do this before resuming any thread, as in
all-stop/remote, once we resume we can't send any other packet
until the target stops again. */
- tp->prev_pc = regcache_read_pc (regcache);
+ cur_thr->prev_pc = regcache_read_pc (regcache);
- started = start_step_over ();
+ {
+ scoped_restore save_defer_tc = make_scoped_defer_target_commit_resume ();
- if (step_over_info_valid_p ())
- {
- /* Either this thread started a new in-line step over, or some
- other thread was already doing one. In either case, don't
- resume anything else until the step-over is finished. */
- }
- else if (started && !target_is_non_stop_p ())
- {
- /* A new displaced stepping sequence was started. In all-stop,
- we can't talk to the target anymore until it next stops. */
- }
- else if (!non_stop && target_is_non_stop_p ())
- {
- /* In all-stop, but the target is always in non-stop mode.
- Start all other threads that are implicitly resumed too. */
- ALL_NON_EXITED_THREADS (tp)
- {
- /* Ignore threads of processes we're not resuming. */
- if (!ptid_match (tp->ptid, resume_ptid))
- continue;
+ started = start_step_over ();
+ if (step_over_info_valid_p ())
+ {
+ /* Either this thread started a new in-line step over, or some
+ other thread was already doing one. In either case, don't
+ resume anything else until the step-over is finished. */
+ }
+ else if (started && !target_is_non_stop_p ())
+ {
+ /* A new displaced stepping sequence was started. In all-stop,
+ we can't talk to the target anymore until it next stops. */
+ }
+ else if (!non_stop && target_is_non_stop_p ())
+ {
+ /* In all-stop, but the target is always in non-stop mode.
+ Start all other threads that are implicitly resumed too. */
+ for (thread_info *tp : all_non_exited_threads (resume_ptid))
+ {
if (tp->resumed)
{
if (debug_infrun)
target_pid_to_str (tp->ptid));
reset_ecs (ecs, tp);
- switch_to_thread (tp->ptid);
+ switch_to_thread (tp);
keep_going_pass_signal (ecs);
if (!ecs->wait_some_more)
error (_("Command aborted."));
}
- }
- else if (!tp->resumed && !thread_is_in_step_over_chain (tp))
- {
- /* The thread wasn't started, and isn't queued, run it now. */
- reset_ecs (ecs, tp);
- switch_to_thread (tp->ptid);
- keep_going_pass_signal (ecs);
- if (!ecs->wait_some_more)
- error (_("Command aborted."));
- }
+ }
+ else if (!cur_thr->resumed && !thread_is_in_step_over_chain (cur_thr))
+ {
+ /* The thread wasn't started, and isn't queued, run it now. */
+ reset_ecs (ecs, cur_thr);
+ switch_to_thread (cur_thr);
+ keep_going_pass_signal (ecs);
+ if (!ecs->wait_some_more)
+ error (_("Command aborted."));
+ }
+ }
- discard_cleanups (old_chain);
+ target_commit_resume ();
+
+ finish_state.release ();
/* Tell the event loop to wait for it to stop. If the target
supports asynchronous execution, it'll do this from within
/* Now that the inferior has stopped, do any bookkeeping like
loading shared libraries. We want to do this before normal_stop,
so that the displayed frame is up to date. */
- post_create_inferior (¤t_target, from_tty);
+ post_create_inferior (current_top_target (), from_tty);
normal_stop ();
}
target_last_wait_ptid = minus_one_ptid;
previous_inferior_ptid = inferior_ptid;
-
- /* Discard any skipped inlined frames. */
- clear_inline_frame_state (minus_one_ptid);
}
\f
static void process_event_stop_test (struct execution_control_state *ecs);
static int switch_back_to_stepped_thread (struct execution_control_state *ecs);
-/* Callback for iterate over threads. If the thread is stopped, but
- the user/frontend doesn't know about that yet, go through
- normal_stop, as if the thread had just stopped now. ARG points at
- a ptid. If PTID is MINUS_ONE_PTID, applies to all threads. If
- ptid_is_pid(PTID) is true, applies to all threads of the process
- pointed at by PTID. Otherwise, apply only to the thread pointed by
- PTID. */
+/* This function is attached as a "thread_stop_requested" observer.
+ Cleanup local state that assumed the PTID was to be resumed, and
+ report the stop to the frontend. */
-static int
-infrun_thread_stop_requested_callback (struct thread_info *info, void *arg)
+static void
+infrun_thread_stop_requested (ptid_t ptid)
{
- ptid_t ptid = * (ptid_t *) arg;
-
- if ((ptid_equal (info->ptid, ptid)
- || ptid_equal (minus_one_ptid, ptid)
- || (ptid_is_pid (ptid)
- && ptid_get_pid (ptid) == ptid_get_pid (info->ptid)))
- && is_running (info->ptid)
- && !is_executing (info->ptid))
+ /* PTID was requested to stop. If the thread was already stopped,
+ but the user/frontend doesn't know about that yet (e.g., the
+ thread had been temporarily paused for some step-over), set up
+ for reporting the stop now. */
+ for (thread_info *tp : all_threads (ptid))
{
- struct cleanup *old_chain;
- struct execution_control_state ecss;
- struct execution_control_state *ecs = &ecss;
-
- memset (ecs, 0, sizeof (*ecs));
-
- old_chain = make_cleanup_restore_current_thread ();
-
- overlay_cache_invalid = 1;
- /* Flush target cache before starting to handle each event.
- Target was running and cache could be stale. This is just a
- heuristic. Running threads may modify target memory, but we
- don't get any event. */
- target_dcache_invalidate ();
-
- /* Go through handle_inferior_event/normal_stop, so we always
- have consistent output as if the stop event had been
- reported. */
- ecs->ptid = info->ptid;
- ecs->event_thread = info;
- ecs->ws.kind = TARGET_WAITKIND_STOPPED;
- ecs->ws.value.sig = GDB_SIGNAL_0;
+ if (tp->state != THREAD_RUNNING)
+ continue;
+ if (tp->executing)
+ continue;
- handle_inferior_event (ecs);
+ /* Remove matching threads from the step-over queue, so
+ start_step_over doesn't try to resume them
+ automatically. */
+ if (thread_is_in_step_over_chain (tp))
+ thread_step_over_chain_remove (tp);
- if (!ecs->wait_some_more)
+ /* If the thread is stopped, but the user/frontend doesn't
+ know about that yet, queue a pending event, as if the
+ thread had just stopped now. Unless the thread already had
+ a pending event. */
+ if (!tp->suspend.waitstatus_pending_p)
{
- /* Cancel any running execution command. */
- thread_cancel_execution_command (info);
-
- normal_stop ();
+ tp->suspend.waitstatus_pending_p = 1;
+ tp->suspend.waitstatus.kind = TARGET_WAITKIND_STOPPED;
+ tp->suspend.waitstatus.value.sig = GDB_SIGNAL_0;
}
- do_cleanups (old_chain);
- }
-
- return 0;
-}
-
-/* This function is attached as a "thread_stop_requested" observer.
- Cleanup local state that assumed the PTID was to be resumed, and
- report the stop to the frontend. */
+ /* Clear the inline-frame state, since we're re-processing the
+ stop. */
+ clear_inline_frame_state (tp->ptid);
-static void
-infrun_thread_stop_requested (ptid_t ptid)
-{
- struct thread_info *tp;
-
- /* PTID was requested to stop. Remove matching threads from the
- step-over queue, so we don't try to resume them
- automatically. */
- ALL_NON_EXITED_THREADS (tp)
- if (ptid_match (tp->ptid, ptid))
- {
- if (thread_is_in_step_over_chain (tp))
- thread_step_over_chain_remove (tp);
- }
+ /* If this thread was paused because some other thread was
+ doing an inline-step over, let that finish first. Once
+ that happens, we'll restart all threads and consume pending
+ stop events then. */
+ if (step_over_info_valid_p ())
+ continue;
- iterate_over_threads (infrun_thread_stop_requested_callback, &ptid);
+ /* Otherwise we can process the (new) pending event now. Set
+ it so this pending event is considered by
+ do_target_wait. */
+ tp->resumed = 1;
+ }
}
static void
infrun_thread_thread_exit (struct thread_info *tp, int silent)
{
- if (ptid_equal (target_last_wait_ptid, tp->ptid))
+ if (target_last_wait_ptid == tp->ptid)
nullify_last_target_wait_ptid ();
}
static void
for_each_just_stopped_thread (for_each_just_stopped_thread_callback_func func)
{
- if (!target_has_execution || ptid_equal (inferior_ptid, null_ptid))
+ if (!target_has_execution || inferior_ptid == null_ptid)
return;
if (target_is_non_stop_p ())
}
else
{
- struct thread_info *tp;
-
/* In all-stop mode, all threads have stopped. */
- ALL_NON_EXITED_THREADS (tp)
- {
- func (tp);
- }
+ for (thread_info *tp : all_non_exited_threads ())
+ func (tp);
}
}
print_target_wait_results (ptid_t waiton_ptid, ptid_t result_ptid,
const struct target_waitstatus *ws)
{
- char *status_string = target_waitstatus_to_string (ws);
- struct ui_file *tmp_stream = mem_fileopen ();
- char *text;
+ std::string status_string = target_waitstatus_to_string (ws);
+ string_file stb;
/* The text is split over several lines because it was getting too long.
Call fprintf_unfiltered (gdb_stdlog) once so that the text is still
output as a unit; we want only one timestamp printed if debug_timestamp
is set. */
- fprintf_unfiltered (tmp_stream,
- "infrun: target_wait (%d.%ld.%ld",
- ptid_get_pid (waiton_ptid),
- ptid_get_lwp (waiton_ptid),
- ptid_get_tid (waiton_ptid));
- if (ptid_get_pid (waiton_ptid) != -1)
- fprintf_unfiltered (tmp_stream,
- " [%s]", target_pid_to_str (waiton_ptid));
- fprintf_unfiltered (tmp_stream, ", status) =\n");
- fprintf_unfiltered (tmp_stream,
- "infrun: %d.%ld.%ld [%s],\n",
- ptid_get_pid (result_ptid),
- ptid_get_lwp (result_ptid),
- ptid_get_tid (result_ptid),
- target_pid_to_str (result_ptid));
- fprintf_unfiltered (tmp_stream,
- "infrun: %s\n",
- status_string);
-
- text = ui_file_xstrdup (tmp_stream, NULL);
+ stb.printf ("infrun: target_wait (%d.%ld.%ld",
+ waiton_ptid.pid (),
+ waiton_ptid.lwp (),
+ waiton_ptid.tid ());
+ if (waiton_ptid.pid () != -1)
+ stb.printf (" [%s]", target_pid_to_str (waiton_ptid));
+ stb.printf (", status) =\n");
+ stb.printf ("infrun: %d.%ld.%ld [%s],\n",
+ result_ptid.pid (),
+ result_ptid.lwp (),
+ result_ptid.tid (),
+ target_pid_to_str (result_ptid));
+ stb.printf ("infrun: %s\n", status_string.c_str ());
/* This uses %s in part to handle %'s in the text, but also to avoid
a gcc error: the format attribute requires a string literal. */
- fprintf_unfiltered (gdb_stdlog, "%s", text);
-
- xfree (status_string);
- xfree (text);
- ui_file_delete (tmp_stream);
+ fprintf_unfiltered (gdb_stdlog, "%s", stb.c_str ());
}
/* Select a thread at random, out of those which are resumed and have
static struct thread_info *
random_pending_event_thread (ptid_t waiton_ptid)
{
- struct thread_info *event_tp;
int num_events = 0;
- int random_selector;
+
+ auto has_event = [] (thread_info *tp)
+ {
+ return (tp->resumed
+ && tp->suspend.waitstatus_pending_p);
+ };
/* First see how many events we have. Count only resumed threads
that have an event pending. */
- ALL_NON_EXITED_THREADS (event_tp)
- if (ptid_match (event_tp->ptid, waiton_ptid)
- && event_tp->resumed
- && event_tp->suspend.waitstatus_pending_p)
+ for (thread_info *tp : all_non_exited_threads (waiton_ptid))
+ if (has_event (tp))
num_events++;
if (num_events == 0)
return NULL;
/* Now randomly pick a thread out of those that have had events. */
- random_selector = (int)
- ((num_events * (double) rand ()) / (RAND_MAX + 1.0));
+ int random_selector = (int) ((num_events * (double) rand ())
+ / (RAND_MAX + 1.0));
if (debug_infrun && num_events > 1)
fprintf_unfiltered (gdb_stdlog,
num_events, random_selector);
/* Select the Nth thread that has had an event. */
- ALL_NON_EXITED_THREADS (event_tp)
- if (ptid_match (event_tp->ptid, waiton_ptid)
- && event_tp->resumed
- && event_tp->suspend.waitstatus_pending_p)
+ for (thread_info *tp : all_non_exited_threads (waiton_ptid))
+ if (has_event (tp))
if (random_selector-- == 0)
- break;
+ return tp;
- return event_tp;
+ gdb_assert_not_reached ("event thread not found");
}
/* Wrapper for target_wait that first checks whether threads have
/* First check if there is a resumed thread with a wait status
pending. */
- if (ptid_equal (ptid, minus_one_ptid) || ptid_is_pid (ptid))
+ if (ptid == minus_one_ptid || ptid.is_pid ())
{
tp = random_pending_event_thread (ptid);
}
&& (tp->suspend.stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT
|| tp->suspend.stop_reason == TARGET_STOPPED_BY_HW_BREAKPOINT))
{
- struct regcache *regcache = get_thread_regcache (tp->ptid);
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct regcache *regcache = get_thread_regcache (tp);
+ struct gdbarch *gdbarch = regcache->arch ();
CORE_ADDR pc;
int discard = 0;
fprintf_unfiltered (gdb_stdlog,
"infrun: PC of %s changed. was=%s, now=%s\n",
target_pid_to_str (tp->ptid),
- paddress (gdbarch, tp->prev_pc),
+ paddress (gdbarch, tp->suspend.stop_pc),
paddress (gdbarch, pc));
discard = 1;
}
- else if (!breakpoint_inserted_here_p (get_regcache_aspace (regcache), pc))
+ else if (!breakpoint_inserted_here_p (regcache->aspace (), pc))
{
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog,
{
if (debug_infrun)
{
- char *statstr;
+ std::string statstr
+ = target_waitstatus_to_string (&tp->suspend.waitstatus);
- statstr = target_waitstatus_to_string (&tp->suspend.waitstatus);
fprintf_unfiltered (gdb_stdlog,
"infrun: Using pending wait status %s for %s.\n",
- statstr,
+ statstr.c_str (),
target_pid_to_str (tp->ptid));
- xfree (statstr);
}
/* Now that we've selected our final event LWP, un-adjust its PC
struct gdbarch *gdbarch;
int decr_pc;
- regcache = get_thread_regcache (tp->ptid);
- gdbarch = get_regcache_arch (regcache);
+ regcache = get_thread_regcache (tp);
+ gdbarch = regcache->arch ();
decr_pc = gdbarch_decr_pc_after_break (gdbarch);
if (decr_pc != 0)
prepare_for_detach (void)
{
struct inferior *inf = current_inferior ();
- ptid_t pid_ptid = pid_to_ptid (inf->pid);
- struct cleanup *old_chain_1;
- struct displaced_step_inferior_state *displaced;
+ ptid_t pid_ptid = ptid_t (inf->pid);
- displaced = get_displaced_stepping_state (inf->pid);
+ displaced_step_inferior_state *displaced = get_displaced_stepping_state (inf);
/* Is any thread of this process displaced stepping? If not,
there's nothing else to do. */
- if (displaced == NULL || ptid_equal (displaced->step_ptid, null_ptid))
+ if (displaced->step_thread == nullptr)
return;
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog,
"displaced-stepping in-process while detaching");
- old_chain_1 = make_cleanup_restore_integer (&inf->detaching);
- inf->detaching = 1;
+ scoped_restore restore_detaching = make_scoped_restore (&inf->detaching, true);
- while (!ptid_equal (displaced->step_ptid, null_ptid))
+ while (displaced->step_thread != nullptr)
{
- struct cleanup *old_chain_2;
struct execution_control_state ecss;
struct execution_control_state *ecs;
/* If an error happens while handling the event, propagate GDB's
knowledge of the executing state to the frontend/user running
state. */
- old_chain_2 = make_cleanup (finish_thread_state_cleanup,
- &minus_one_ptid);
+ scoped_finish_thread_state finish_state (minus_one_ptid);
/* Now figure out what to do with the result of the result. */
handle_inferior_event (ecs);
/* No error, don't finish the state yet. */
- discard_cleanups (old_chain_2);
+ finish_state.release ();
/* Breakpoints and watchpoints are not installed on the target
at this point, and signals are passed directly to the
inferior, so this must mean the process is gone. */
if (!ecs->wait_some_more)
{
- discard_cleanups (old_chain_1);
+ restore_detaching.release ();
error (_("Program exited while detaching"));
}
}
- discard_cleanups (old_chain_1);
+ restore_detaching.release ();
}
/* Wait for control to return from inferior to debugger.
wait_for_inferior (void)
{
struct cleanup *old_cleanups;
- struct cleanup *thread_state_chain;
if (debug_infrun)
fprintf_unfiltered
/* If an error happens while handling the event, propagate GDB's
knowledge of the executing state to the frontend/user running
state. */
- thread_state_chain = make_cleanup (finish_thread_state_cleanup, &minus_one_ptid);
+ scoped_finish_thread_state finish_state (minus_one_ptid);
while (1)
{
}
/* No error, don't finish the state yet. */
- discard_cleanups (thread_state_chain);
+ finish_state.release ();
do_cleanups (old_cleanups);
}
static void
clean_up_just_stopped_threads_fsms (struct execution_control_state *ecs)
{
- struct thread_info *thr = ecs->event_thread;
-
- if (thr != NULL && thr->thread_fsm != NULL)
- thread_fsm_clean_up (thr->thread_fsm, thr);
+ if (ecs->event_thread != NULL
+ && ecs->event_thread->thread_fsm != NULL)
+ thread_fsm_clean_up (ecs->event_thread->thread_fsm,
+ ecs->event_thread);
if (!non_stop)
{
- ALL_NON_EXITED_THREADS (thr)
+ for (thread_info *thr : all_non_exited_threads ())
{
if (thr->thread_fsm == NULL)
continue;
if (thr == ecs->event_thread)
continue;
- switch_to_thread (thr->ptid);
+ switch_to_thread (thr);
thread_fsm_clean_up (thr->thread_fsm, thr);
}
if (ecs->event_thread != NULL)
- switch_to_thread (ecs->event_thread->ptid);
+ switch_to_thread (ecs->event_thread);
}
}
&& ui->async
&& !gdb_in_secondary_prompt_p (ui))
{
- target_terminal_ours ();
- observer_notify_sync_execution_done ();
+ target_terminal::ours ();
+ gdb::observers::sync_execution_done.notify ();
ui_register_input_event_handler (ui);
}
}
void
all_uis_check_sync_execution_done (void)
{
- struct switch_thru_all_uis state;
-
- SWITCH_THRU_ALL_UIS (state)
+ SWITCH_THRU_ALL_UIS ()
{
check_curr_ui_sync_execution_done ();
}
void
all_uis_on_sync_execution_starting (void)
{
- struct switch_thru_all_uis state;
-
- SWITCH_THRU_ALL_UIS (state)
+ SWITCH_THRU_ALL_UIS ()
{
if (current_ui->prompt_state == PROMPT_NEEDED)
async_disable_stdin ();
struct execution_control_state ecss;
struct execution_control_state *ecs = &ecss;
struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
- struct cleanup *ts_old_chain;
int cmd_done = 0;
ptid_t waiton_ptid = minus_one_ptid;
debugging. If we're looking at traceframes while the target is
running, we're going to need to get back to that mode after
handling the event. */
+ gdb::optional<scoped_restore_current_traceframe> maybe_restore_traceframe;
if (non_stop)
{
- make_cleanup_restore_current_traceframe ();
+ maybe_restore_traceframe.emplace ();
set_current_traceframe (-1);
}
+ gdb::optional<scoped_restore_current_thread> maybe_restore_thread;
+
if (non_stop)
/* In non-stop mode, the user/frontend should not notice a thread
switch due to internal events. Make sure we reverse to the
user selected thread and frame after handling the event and
running any breakpoint commands. */
- make_cleanup_restore_current_thread ();
+ maybe_restore_thread.emplace ();
overlay_cache_invalid = 1;
/* Flush target cache before starting to handle each event. Target
/* If an error happens while handling the event, propagate GDB's
knowledge of the executing state to the frontend/user running
state. */
- if (!target_is_non_stop_p ())
- ts_old_chain = make_cleanup (finish_thread_state_cleanup, &minus_one_ptid);
- else
- ts_old_chain = make_cleanup (finish_thread_state_cleanup, &ecs->ptid);
+ ptid_t finish_ptid = !target_is_non_stop_p () ? minus_one_ptid : ecs->ptid;
+ scoped_finish_thread_state finish_state (finish_ptid);
/* Get executed before make_cleanup_restore_current_thread above to apply
still for the thread which has thrown the exception. */
- make_bpstat_clear_actions_cleanup ();
+ struct cleanup *ts_old_chain = make_bpstat_clear_actions_cleanup ();
make_cleanup (delete_just_stopped_threads_infrun_breakpoints_cleanup, NULL);
struct inferior *inf = find_inferior_ptid (ecs->ptid);
int should_stop = 1;
struct thread_info *thr = ecs->event_thread;
- int should_notify_stop = 1;
delete_just_stopped_threads_infrun_breakpoints ();
}
else
{
+ int should_notify_stop = 1;
+ int proceeded = 0;
+
clean_up_just_stopped_threads_fsms (ecs);
if (thr != NULL && thr->thread_fsm != NULL)
if (should_notify_stop)
{
- int proceeded = 0;
-
/* We may not find an inferior if this was a process exit. */
if (inf == NULL || inf->control.stop_soon == NO_STOP_QUIETLY)
proceeded = normal_stop ();
+ }
- if (!proceeded)
- {
- inferior_event_handler (INF_EXEC_COMPLETE, NULL);
- cmd_done = 1;
- }
+ if (!proceeded)
+ {
+ inferior_event_handler (INF_EXEC_COMPLETE, NULL);
+ cmd_done = 1;
}
}
}
- /* No error, don't finish the thread states yet. */
discard_cleanups (ts_old_chain);
+ /* No error, don't finish the thread states yet. */
+ finish_state.release ();
+
/* Revert thread and frame. */
do_cleanups (old_chain);
if (cmd_done
&& exec_done_display_p
- && (ptid_equal (inferior_ptid, null_ptid)
- || !is_running (inferior_ptid)))
+ && (inferior_ptid == null_ptid
+ || inferior_thread ()->state != THREAD_RUNNING))
printf_unfiltered (_("completed.\n"));
}
/* Switch thread contexts. */
static void
-context_switch (ptid_t ptid)
+context_switch (execution_control_state *ecs)
{
- if (debug_infrun && !ptid_equal (ptid, inferior_ptid))
+ if (debug_infrun
+ && ecs->ptid != inferior_ptid
+ && ecs->event_thread != inferior_thread ())
{
fprintf_unfiltered (gdb_stdlog, "infrun: Switching context from %s ",
target_pid_to_str (inferior_ptid));
fprintf_unfiltered (gdb_stdlog, "to %s\n",
- target_pid_to_str (ptid));
+ target_pid_to_str (ecs->ptid));
}
- switch_to_thread (ptid);
+ switch_to_thread (ecs->event_thread);
}
/* If the target can't tell whether we've hit breakpoints
{
struct regcache *regcache;
struct gdbarch *gdbarch;
- struct address_space *aspace;
CORE_ADDR breakpoint_pc, decr_pc;
/* If we've hit a breakpoint, we'll normally be stopped with SIGTRAP. If
/* If this target does not decrement the PC after breakpoints, then
we have nothing to do. */
- regcache = get_thread_regcache (thread->ptid);
- gdbarch = get_regcache_arch (regcache);
+ regcache = get_thread_regcache (thread);
+ gdbarch = regcache->arch ();
decr_pc = gdbarch_decr_pc_after_break (gdbarch);
if (decr_pc == 0)
return;
- aspace = get_regcache_aspace (regcache);
+ const address_space *aspace = regcache->aspace ();
/* Find the location where (if we've hit a breakpoint) the
breakpoint would be. */
|| (target_is_non_stop_p ()
&& moribund_breakpoint_here_p (aspace, breakpoint_pc)))
{
- struct cleanup *old_cleanups = make_cleanup (null_cleanup, NULL);
+ gdb::optional<scoped_restore_tmpl<int>> restore_operation_disable;
if (record_full_is_used ())
- record_full_gdb_operation_disable_set ();
+ restore_operation_disable.emplace
+ (record_full_gdb_operation_disable_set ());
/* When using hardware single-step, a SIGTRAP is reported for both
a completed single-step and a software breakpoint. Need to
|| (thread->stepped_breakpoint
&& thread->prev_pc == breakpoint_pc))
regcache_write_pc (regcache, breakpoint_pc);
-
- do_cleanups (old_cleanups);
}
}
return 0;
}
+/* If the event thread has the stop requested flag set, pretend it
+ stopped for a GDB_SIGNAL_0 (i.e., as if it stopped due to
+ target_stop). */
+
+static bool
+handle_stop_requested (struct execution_control_state *ecs)
+{
+ if (ecs->event_thread->stop_requested)
+ {
+ ecs->ws.kind = TARGET_WAITKIND_STOPPED;
+ ecs->ws.value.sig = GDB_SIGNAL_0;
+ handle_signal_stop (ecs);
+ return true;
+ }
+ return false;
+}
+
/* Auxiliary function that handles syscall entry/return events.
It returns 1 if the inferior should keep going (and GDB
should ignore the event), or 0 if the event deserves to be
struct regcache *regcache;
int syscall_number;
- if (!ptid_equal (ecs->ptid, inferior_ptid))
- context_switch (ecs->ptid);
+ context_switch (ecs);
- regcache = get_thread_regcache (ecs->ptid);
+ regcache = get_thread_regcache (ecs->event_thread);
syscall_number = ecs->ws.value.syscall_number;
- stop_pc = regcache_read_pc (regcache);
+ ecs->event_thread->suspend.stop_pc = regcache_read_pc (regcache);
if (catch_syscall_enabled () > 0
&& catching_syscall_number (syscall_number) > 0)
syscall_number);
ecs->event_thread->control.stop_bpstat
- = bpstat_stop_status (get_regcache_aspace (regcache),
- stop_pc, ecs->ptid, &ecs->ws);
+ = bpstat_stop_status (regcache->aspace (),
+ ecs->event_thread->suspend.stop_pc,
+ ecs->event_thread, &ecs->ws);
+
+ if (handle_stop_requested (ecs))
+ return 0;
if (bpstat_causes_stop (ecs->event_thread->control.stop_bpstat))
{
}
}
+ if (handle_stop_requested (ecs))
+ return 0;
+
/* If no catchpoint triggered for this, then keep going. */
keep_going (ecs);
return 1;
{
/* Don't care about return value; stop_func_start and stop_func_name
will both be 0 if it doesn't work. */
- find_pc_partial_function (stop_pc, &ecs->stop_func_name,
- &ecs->stop_func_start, &ecs->stop_func_end);
+ find_function_entry_range_from_pc (ecs->event_thread->suspend.stop_pc,
+ &ecs->stop_func_name,
+ &ecs->stop_func_start,
+ &ecs->stop_func_end);
ecs->stop_func_start
+= gdbarch_deprecated_function_start_offset (gdbarch);
}
-/* Return the STOP_SOON field of the inferior pointed at by PTID. */
+/* Return the STOP_SOON field of the inferior pointed at by ECS. */
static enum stop_kind
-get_inferior_stop_soon (ptid_t ptid)
+get_inferior_stop_soon (execution_control_state *ecs)
{
- struct inferior *inf = find_inferior_ptid (ptid);
+ struct inferior *inf = find_inferior_ptid (ecs->ptid);
gdb_assert (inf != NULL);
return inf->control.stop_soon;
static int \
thread_stopped_by_ ## REASON (ptid_t ptid) \
{ \
- struct cleanup *old_chain; \
- int res; \
- \
- old_chain = save_inferior_ptid (); \
+ scoped_restore save_inferior_ptid = make_scoped_restore (&inferior_ptid); \
inferior_ptid = ptid; \
\
- res = target_stopped_by_ ## REASON (); \
- \
- do_cleanups (old_chain); \
- \
- return res; \
+ return target_stopped_by_ ## REASON (); \
}
/* Generate thread_stopped_by_watchpoint. */
/* Generate thread_stopped_by_hw_breakpoint. */
THREAD_STOPPED_BY (hw_breakpoint)
-/* Cleanups that switches to the PTID pointed at by PTID_P. */
-
-static void
-switch_to_thread_cleanup (void *ptid_p)
-{
- ptid_t ptid = *(ptid_t *) ptid_p;
-
- switch_to_thread (ptid);
-}
-
/* Save the thread's event and stop reason to process it later. */
static void
save_waitstatus (struct thread_info *tp, struct target_waitstatus *ws)
{
- struct regcache *regcache;
- struct address_space *aspace;
-
if (debug_infrun)
{
- char *statstr;
+ std::string statstr = target_waitstatus_to_string (ws);
- statstr = target_waitstatus_to_string (ws);
fprintf_unfiltered (gdb_stdlog,
"infrun: saving status %s for %d.%ld.%ld\n",
- statstr,
- ptid_get_pid (tp->ptid),
- ptid_get_lwp (tp->ptid),
- ptid_get_tid (tp->ptid));
- xfree (statstr);
+ statstr.c_str (),
+ tp->ptid.pid (),
+ tp->ptid.lwp (),
+ tp->ptid.tid ());
}
/* Record for later. */
tp->suspend.waitstatus = *ws;
tp->suspend.waitstatus_pending_p = 1;
- regcache = get_thread_regcache (tp->ptid);
- aspace = get_regcache_aspace (regcache);
+ struct regcache *regcache = get_thread_regcache (tp);
+ const address_space *aspace = regcache->aspace ();
if (ws->kind == TARGET_WAITKIND_STOPPED
&& ws->value.sig == GDB_SIGNAL_TRAP)
/* We may need multiple passes to discover all threads. */
int pass;
int iterations = 0;
- ptid_t entry_ptid;
struct cleanup *old_chain;
gdb_assert (target_is_non_stop_p ());
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: stop_all_threads\n");
- entry_ptid = inferior_ptid;
- old_chain = make_cleanup (switch_to_thread_cleanup, &entry_ptid);
+ scoped_restore_current_thread restore_thread;
target_thread_events (1);
- make_cleanup (disable_thread_events, NULL);
+ old_chain = make_cleanup (disable_thread_events, NULL);
/* Request threads to stop, and then wait for the stops. Because
threads we already know about can spawn more threads while we're
ptid_t event_ptid;
struct target_waitstatus ws;
int need_wait = 0;
- struct thread_info *t;
update_thread_list ();
/* Go through all threads looking for threads that we need
to tell the target to stop. */
- ALL_NON_EXITED_THREADS (t)
+ for (thread_info *t : all_non_exited_threads ())
{
if (t->executing)
{
pass = -1;
event_ptid = wait_one (&ws);
+
if (ws.kind == TARGET_WAITKIND_NO_RESUMED)
{
/* All resumed threads exited. */
{
if (debug_infrun)
{
- ptid_t ptid = pid_to_ptid (ws.value.integer);
+ ptid_t ptid = ptid_t (ws.value.integer);
fprintf_unfiltered (gdb_stdlog,
"infrun: %s exited while "
}
else
{
- struct inferior *inf;
-
- t = find_thread_ptid (event_ptid);
+ thread_info *t = find_thread_ptid (event_ptid);
if (t == NULL)
t = add_thread (event_ptid);
/* This may be the first time we see the inferior report
a stop. */
- inf = find_inferior_ptid (event_ptid);
+ inferior *inf = find_inferior_ptid (event_ptid);
if (inf->needs_setup)
{
switch_to_thread_no_regs (t);
t->suspend.waitstatus.kind = TARGET_WAITKIND_IGNORE;
t->suspend.waitstatus_pending_p = 0;
- if (displaced_step_fixup (t->ptid, GDB_SIGNAL_0) < 0)
+ if (displaced_step_fixup (t, GDB_SIGNAL_0) < 0)
{
/* Add it back to the step-over queue. */
if (debug_infrun)
if (debug_infrun)
{
- char *statstr;
+ std::string statstr = target_waitstatus_to_string (&ws);
- statstr = target_waitstatus_to_string (&ws);
fprintf_unfiltered (gdb_stdlog,
"infrun: target_wait %s, saving "
"status for %d.%ld.%ld\n",
- statstr,
- ptid_get_pid (t->ptid),
- ptid_get_lwp (t->ptid),
- ptid_get_tid (t->ptid));
- xfree (statstr);
+ statstr.c_str (),
+ t->ptid.pid (),
+ t->ptid.lwp (),
+ t->ptid.tid ());
}
/* Record for later. */
sig = (ws.kind == TARGET_WAITKIND_STOPPED
? ws.value.sig : GDB_SIGNAL_0);
- if (displaced_step_fixup (t->ptid, sig) < 0)
+ if (displaced_step_fixup (t, sig) < 0)
{
/* Add it back to the step-over queue. */
t->control.trap_expected = 0;
thread_step_over_chain_enqueue (t);
}
- regcache = get_thread_regcache (t->ptid);
+ regcache = get_thread_regcache (t);
t->suspend.stop_pc = regcache_read_pc (regcache);
if (debug_infrun)
static int
handle_no_resumed (struct execution_control_state *ecs)
{
- struct inferior *inf;
- struct thread_info *thread;
-
if (target_can_async_p ())
{
struct ui *ui;
the synchronous command show "no unwaited-for " to the user. */
update_thread_list ();
- ALL_NON_EXITED_THREADS (thread)
+ for (thread_info *thread : all_non_exited_threads ())
{
if (thread->executing
|| thread->suspend.waitstatus_pending_p)
process exited meanwhile (thus updating the thread list results
in an empty thread list). In this case we know we'll be getting
a process exit event shortly. */
- ALL_INFERIORS (inf)
+ for (inferior *inf : all_inferiors ())
{
if (inf->pid == 0)
continue;
- thread = any_live_thread_of_process (inf->pid);
+ thread_info *thread = any_live_thread_of_inferior (inf);
if (thread == NULL)
{
if (debug_infrun)
|| ecs->ws.value.sig == GDB_SIGNAL_SEGV
|| ecs->ws.value.sig == GDB_SIGNAL_EMT))
{
- struct regcache *regcache = get_thread_regcache (ecs->ptid);
+ struct regcache *regcache = get_thread_regcache (ecs->event_thread);
- if (breakpoint_inserted_here_p (get_regcache_aspace (regcache),
+ if (breakpoint_inserted_here_p (regcache->aspace (),
regcache_read_pc (regcache)))
{
if (debug_infrun)
process as not-executing so that finish_thread_state marks
them stopped (in the user's perspective) if/when we present
the stop to the user. */
- mark_ptid = pid_to_ptid (ptid_get_pid (ecs->ptid));
+ mark_ptid = ptid_t (ecs->ptid.pid ());
}
else
mark_ptid = ecs->ptid;
case TARGET_WAITKIND_LOADED:
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_LOADED\n");
- if (!ptid_equal (ecs->ptid, inferior_ptid))
- context_switch (ecs->ptid);
+ context_switch (ecs);
/* Ignore gracefully during startup of the inferior, as it might
be the shell which has just loaded some objects, otherwise
add the symbols for the newly loaded objects. Also ignore at
the full list of libraries once the connection is
established. */
- stop_soon = get_inferior_stop_soon (ecs->ptid);
+ stop_soon = get_inferior_stop_soon (ecs);
if (stop_soon == NO_STOP_QUIETLY)
{
struct regcache *regcache;
- regcache = get_thread_regcache (ecs->ptid);
+ regcache = get_thread_regcache (ecs->event_thread);
handle_solib_event ();
ecs->event_thread->control.stop_bpstat
- = bpstat_stop_status (get_regcache_aspace (regcache),
- stop_pc, ecs->ptid, &ecs->ws);
+ = bpstat_stop_status (regcache->aspace (),
+ ecs->event_thread->suspend.stop_pc,
+ ecs->event_thread, &ecs->ws);
+
+ if (handle_stop_requested (ecs))
+ return;
if (bpstat_causes_stop (ecs->event_thread->control.stop_bpstat))
{
case TARGET_WAITKIND_SPURIOUS:
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_SPURIOUS\n");
- if (!ptid_equal (ecs->ptid, inferior_ptid))
- context_switch (ecs->ptid);
+ if (handle_stop_requested (ecs))
+ return;
+ context_switch (ecs);
resume (GDB_SIGNAL_0);
prepare_to_wait (ecs);
return;
case TARGET_WAITKIND_THREAD_CREATED:
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_THREAD_CREATED\n");
- if (!ptid_equal (ecs->ptid, inferior_ptid))
- context_switch (ecs->ptid);
+ if (handle_stop_requested (ecs))
+ return;
+ context_switch (ecs);
if (!switch_back_to_stepped_thread (ecs))
keep_going (ecs);
return;
set_current_inferior (find_inferior_ptid (ecs->ptid));
set_current_program_space (current_inferior ()->pspace);
handle_vfork_child_exec_or_exit (0);
- target_terminal_ours (); /* Must do this before mourn anyway. */
+ target_terminal::ours (); /* Must do this before mourn anyway. */
/* Clearing any previous state of convenience variables. */
clear_exit_convenience_vars ();
/* 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
{
- struct regcache *regcache = get_thread_regcache (ecs->ptid);
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = current_inferior ()->gdbarch;
if (gdbarch_gdb_signal_to_target_p (gdbarch))
{
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);
/* Check whether the inferior is displaced stepping. */
{
- struct regcache *regcache = get_thread_regcache (ecs->ptid);
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct regcache *regcache = get_thread_regcache (ecs->event_thread);
+ struct gdbarch *gdbarch = regcache->arch ();
/* If checking displaced stepping is supported, and thread
ecs->ptid is displaced stepping. */
- if (displaced_step_in_progress_thread (ecs->ptid))
+ if (displaced_step_in_progress_thread (ecs->event_thread))
{
struct inferior *parent_inf
= find_inferior_ptid (ecs->ptid);
has been done. Perform cleanup for parent process here. Note
that this operation also cleans up the child process for vfork,
because their pages are shared. */
- displaced_step_fixup (ecs->ptid, GDB_SIGNAL_TRAP);
+ displaced_step_fixup (ecs->event_thread, GDB_SIGNAL_TRAP);
/* Start a new step-over in another thread if there's one
that needs it. */
start_step_over ();
if (ecs->ws.kind == TARGET_WAITKIND_FORKED)
{
struct displaced_step_inferior_state *displaced
- = get_displaced_stepping_state (ptid_get_pid (ecs->ptid));
+ = get_displaced_stepping_state (parent_inf);
/* Restore scratch pad for child process. */
displaced_step_restore (displaced, ecs->ws.value.related_pid);
}
}
- if (!ptid_equal (ecs->ptid, inferior_ptid))
- context_switch (ecs->ptid);
+ context_switch (ecs);
/* Immediately detach breakpoints from the child before there's
any chance of letting the user delete breakpoints from the
and not immediately. */
ecs->event_thread->pending_follow = ecs->ws;
- stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid));
+ ecs->event_thread->suspend.stop_pc
+ = regcache_read_pc (get_thread_regcache (ecs->event_thread));
ecs->event_thread->control.stop_bpstat
- = bpstat_stop_status (get_regcache_aspace (get_current_regcache ()),
- stop_pc, ecs->ptid, &ecs->ws);
+ = bpstat_stop_status (get_current_regcache ()->aspace (),
+ ecs->event_thread->suspend.stop_pc,
+ ecs->event_thread, &ecs->ws);
+
+ if (handle_stop_requested (ecs))
+ return;
/* If no catchpoint triggered for this, then keep going. Note
that we're interested in knowing the bpstat actually causes a
watchpoints, for example, always appear in the bpstat. */
if (!bpstat_causes_stop (ecs->event_thread->control.stop_bpstat))
{
- ptid_t parent;
- ptid_t child;
int should_resume;
int follow_child
= (follow_fork_mode_string == follow_fork_mode_child);
should_resume = follow_fork ();
- parent = ecs->ptid;
- child = ecs->ws.value.related_pid;
+ thread_info *parent = ecs->event_thread;
+ thread_info *child = find_thread_ptid (ecs->ws.value.related_pid);
/* At this point, the parent is marked running, and the
child is marked stopped. */
/* If not resuming the parent, mark it stopped. */
if (follow_child && !detach_fork && !non_stop && !sched_multi)
- set_running (parent, 0);
+ parent->set_running (false);
/* If resuming the child, mark it running. */
if (follow_child || (!detach_fork && (non_stop || sched_multi)))
- set_running (child, 1);
+ child->set_running (true);
/* In non-stop mode, also resume the other branch. */
if (!detach_fork && (non_stop
fprintf_unfiltered (gdb_stdlog,
"infrun: TARGET_WAITKIND_VFORK_DONE\n");
- if (!ptid_equal (ecs->ptid, inferior_ptid))
- context_switch (ecs->ptid);
+ context_switch (ecs);
current_inferior ()->waiting_for_vfork_done = 0;
current_inferior ()->pspace->breakpoints_not_allowed = 0;
+
+ if (handle_stop_requested (ecs))
+ return;
+
/* This also takes care of reinserting breakpoints in the
previously locked inferior. */
keep_going (ecs);
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_EXECD\n");
- if (!ptid_equal (ecs->ptid, inferior_ptid))
- context_switch (ecs->ptid);
-
- stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid));
+ /* Note we can't read registers yet (the stop_pc), because we
+ don't yet know the inferior's post-exec architecture.
+ 'stop_pc' is explicitly read below instead. */
+ switch_to_thread_no_regs (ecs->event_thread);
/* Do whatever is necessary to the parent branch of the vfork. */
handle_vfork_child_exec_or_exit (1);
execd thread for that case (this is a nop otherwise). */
ecs->event_thread = inferior_thread ();
+ ecs->event_thread->suspend.stop_pc
+ = regcache_read_pc (get_thread_regcache (ecs->event_thread));
+
ecs->event_thread->control.stop_bpstat
- = bpstat_stop_status (get_regcache_aspace (get_current_regcache ()),
- stop_pc, ecs->ptid, &ecs->ws);
+ = bpstat_stop_status (get_current_regcache ()->aspace (),
+ ecs->event_thread->suspend.stop_pc,
+ ecs->event_thread, &ecs->ws);
/* Note that this may be referenced from inside
bpstat_stop_status above, through inferior_has_execd. */
xfree (ecs->ws.value.execd_pathname);
ecs->ws.value.execd_pathname = NULL;
+ if (handle_stop_requested (ecs))
+ return;
+
/* If no catchpoint triggered for this, then keep going. */
if (!bpstat_causes_stop (ecs->event_thread->control.stop_bpstat))
{
case TARGET_WAITKIND_STOPPED:
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_STOPPED\n");
- ecs->event_thread->suspend.stop_signal = ecs->ws.value.sig;
handle_signal_stop (ecs);
return;
/* Reverse execution: target ran out of history info. */
/* Switch to the stopped thread. */
- if (!ptid_equal (ecs->ptid, inferior_ptid))
- context_switch (ecs->ptid);
+ context_switch (ecs);
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: stopped\n");
delete_just_stopped_threads_single_step_breakpoints ();
- stop_pc = regcache_read_pc (get_thread_regcache (inferior_ptid));
- observer_notify_no_history ();
+ ecs->event_thread->suspend.stop_pc
+ = regcache_read_pc (get_thread_regcache (inferior_thread ()));
+
+ if (handle_stop_requested (ecs))
+ return;
+
+ gdb::observers::no_history.notify ();
stop_waiting (ecs);
return;
}
static void
restart_threads (struct thread_info *event_thread)
{
- struct thread_info *tp;
-
/* In case the instruction just stepped spawned a new thread. */
update_thread_list ();
- ALL_NON_EXITED_THREADS (tp)
+ for (thread_info *tp : all_non_exited_threads ())
{
if (tp == event_thread)
{
continue;
}
+ gdb_assert (!tp->stop_requested);
+
/* If some thread needs to start a step-over at this point, it
should still be in the step-over queue, and thus skipped
above. */
"infrun: restart threads: [%s] continuing\n",
target_pid_to_str (tp->ptid));
reset_ecs (ecs, tp);
- switch_to_thread (tp->ptid);
+ switch_to_thread (tp);
keep_going_pass_signal (ecs);
}
}
{
int had_step_over_info;
- displaced_step_fixup (ecs->ptid,
+ displaced_step_fixup (ecs->event_thread,
ecs->event_thread->suspend.stop_signal);
had_step_over_info = step_over_info_valid_p ();
back an event. */
gdb_assert (ecs->event_thread->control.trap_expected);
- if (ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP)
- clear_step_over_info ();
+ clear_step_over_info ();
}
if (!target_is_non_stop_p ())
another thread has a pending event for this breakpoint too,
we'd discard its event (because the breakpoint that
originally caused the event was no longer inserted). */
- context_switch (ecs->ptid);
+ context_switch (ecs);
insert_breakpoints ();
restart_threads (ecs->event_thread);
gdb_assert (!tp->executing);
- regcache = get_thread_regcache (tp->ptid);
+ regcache = get_thread_regcache (tp);
tp->suspend.stop_pc = regcache_read_pc (regcache);
if (debug_infrun)
gdb_assert (ecs->ws.kind == TARGET_WAITKIND_STOPPED);
+ ecs->event_thread->suspend.stop_signal = ecs->ws.value.sig;
+
/* Do we need to clean up the state of a thread that has
completed a displaced single-step? (Doing so usually affects
the PC, so do it here, before we set stop_pc.) */
&& ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP)
ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_0;
- stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid));
+ ecs->event_thread->suspend.stop_pc
+ = regcache_read_pc (get_thread_regcache (ecs->event_thread));
if (debug_infrun)
{
- struct regcache *regcache = get_thread_regcache (ecs->ptid);
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
- struct cleanup *old_chain = save_inferior_ptid ();
+ struct regcache *regcache = get_thread_regcache (ecs->event_thread);
+ struct gdbarch *reg_gdbarch = regcache->arch ();
+ scoped_restore save_inferior_ptid = make_scoped_restore (&inferior_ptid);
inferior_ptid = ecs->ptid;
fprintf_unfiltered (gdb_stdlog, "infrun: stop_pc = %s\n",
- paddress (gdbarch, stop_pc));
+ paddress (reg_gdbarch,
+ ecs->event_thread->suspend.stop_pc));
if (target_stopped_by_watchpoint ())
{
CORE_ADDR addr;
fprintf_unfiltered (gdb_stdlog, "infrun: stopped by watchpoint\n");
- if (target_stopped_data_address (¤t_target, &addr))
+ if (target_stopped_data_address (current_top_target (), &addr))
fprintf_unfiltered (gdb_stdlog,
"infrun: stopped data address = %s\n",
- paddress (gdbarch, addr));
+ paddress (reg_gdbarch, addr));
else
fprintf_unfiltered (gdb_stdlog,
"infrun: (no data address available)\n");
}
-
- do_cleanups (old_chain);
}
/* This is originated from start_remote(), start_inferior() and
shared libraries hook functions. */
- stop_soon = get_inferior_stop_soon (ecs->ptid);
+ stop_soon = get_inferior_stop_soon (ecs);
if (stop_soon == STOP_QUIETLY || stop_soon == STOP_QUIETLY_REMOTE)
{
- if (!ptid_equal (ecs->ptid, inferior_ptid))
- context_switch (ecs->ptid);
+ context_switch (ecs);
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: quietly stopped\n");
stop_print_frame = 1;
/* See if something interesting happened to the non-current thread. If
so, then switch to that thread. */
- if (!ptid_equal (ecs->ptid, inferior_ptid))
+ if (ecs->ptid != inferior_ptid)
{
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: context switch\n");
- context_switch (ecs->ptid);
+ context_switch (ecs);
if (deprecated_context_hook)
- deprecated_context_hook (ptid_to_global_thread_id (ecs->ptid));
+ deprecated_context_hook (ecs->event_thread->global_num);
}
/* At this point, get hold of the now-current thread's frame. */
if (ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP)
{
struct regcache *regcache;
- struct address_space *aspace;
CORE_ADDR pc;
- regcache = get_thread_regcache (ecs->ptid);
- aspace = get_regcache_aspace (regcache);
+ regcache = get_thread_regcache (ecs->event_thread);
+ const address_space *aspace = regcache->aspace ();
+
pc = regcache_read_pc (regcache);
/* However, before doing so, if this single-step breakpoint was
ecs->event_thread->control.stop_step = 0;
stop_print_frame = 1;
stopped_by_random_signal = 0;
+ bpstat stop_chain = NULL;
/* Hide inlined functions starting here, unless we just performed stepi or
nexti. After stepi and nexti, always show the innermost frame (not any
inline function call sites). */
if (ecs->event_thread->control.step_range_end != 1)
{
- struct address_space *aspace =
- get_regcache_aspace (get_thread_regcache (ecs->ptid));
+ const address_space *aspace
+ = get_thread_regcache (ecs->event_thread)->aspace ();
/* skip_inline_frames is expensive, so we avoid it if we can
determine that the address is one where functions cannot have
user had set a breakpoint on that inlined code, the missing
skip_inline_frames call would break things. Fortunately
that's an extremely unlikely scenario. */
- if (!pc_at_non_inline_function (aspace, stop_pc, &ecs->ws)
+ if (!pc_at_non_inline_function (aspace,
+ ecs->event_thread->suspend.stop_pc,
+ &ecs->ws)
&& !(ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP
&& ecs->event_thread->control.trap_expected
&& pc_at_non_inline_function (aspace,
ecs->event_thread->prev_pc,
&ecs->ws)))
{
- skip_inline_frames (ecs->ptid);
+ stop_chain = build_bpstat_chain (aspace,
+ ecs->event_thread->suspend.stop_pc,
+ &ecs->ws);
+ skip_inline_frames (ecs->event_thread, stop_chain);
/* Re-fetch current thread's frame in case that invalidated
the frame cache. */
/* See if there is a breakpoint/watchpoint/catchpoint/etc. that
handles this event. */
ecs->event_thread->control.stop_bpstat
- = bpstat_stop_status (get_regcache_aspace (get_current_regcache ()),
- stop_pc, ecs->ptid, &ecs->ws);
+ = bpstat_stop_status (get_current_regcache ()->aspace (),
+ ecs->event_thread->suspend.stop_pc,
+ ecs->event_thread, &ecs->ws, stop_chain);
/* Following in case break condition called a
function. */
been removed. */
if (random_signal && target_stopped_by_sw_breakpoint ())
{
- if (program_breakpoint_here_p (gdbarch, stop_pc))
+ if (program_breakpoint_here_p (gdbarch,
+ ecs->event_thread->suspend.stop_pc))
{
struct regcache *regcache;
int decr_pc;
/* Re-adjust PC to what the program would see if GDB was not
debugging it. */
- regcache = get_thread_regcache (ecs->event_thread->ptid);
+ regcache = get_thread_regcache (ecs->event_thread);
decr_pc = gdbarch_decr_pc_after_break (gdbarch);
if (decr_pc != 0)
{
- struct cleanup *old_cleanups = make_cleanup (null_cleanup, NULL);
+ gdb::optional<scoped_restore_tmpl<int>>
+ restore_operation_disable;
if (record_full_is_used ())
- record_full_gdb_operation_disable_set ();
-
- regcache_write_pc (regcache, stop_pc + decr_pc);
+ restore_operation_disable.emplace
+ (record_full_gdb_operation_disable_set ());
- do_cleanups (old_cleanups);
+ regcache_write_pc (regcache,
+ ecs->event_thread->suspend.stop_pc + decr_pc);
}
}
else
if (random_signal)
random_signal = !stopped_by_watchpoint;
+ /* Always stop if the user explicitly requested this thread to
+ remain stopped. */
+ if (ecs->event_thread->stop_requested)
+ {
+ random_signal = 1;
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog, "infrun: user-requested stop\n");
+ }
+
/* For the program's own signals, act according to
the signal handling tables. */
if (signal_print[ecs->event_thread->suspend.stop_signal])
{
/* 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);
- target_terminal_inferior ();
+ target_terminal::ours_for_output ();
+ gdb::observers::signal_received.notify (ecs->event_thread->suspend.stop_signal);
+ target_terminal::inferior ();
}
/* Clear the signal if it should not be passed. */
if (signal_program[ecs->event_thread->suspend.stop_signal] == 0)
ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_0;
- if (ecs->event_thread->prev_pc == stop_pc
+ if (ecs->event_thread->prev_pc == ecs->event_thread->suspend.stop_pc
&& ecs->event_thread->control.trap_expected
&& ecs->event_thread->control.step_resume_breakpoint == NULL)
{
- int was_in_line;
-
/* We were just starting a new sequence, attempting to
single-step off of a breakpoint and expecting a SIGTRAP.
Instead this signal arrives. This signal will take us out
"infrun: signal arrived while stepping over "
"breakpoint\n");
- was_in_line = step_over_info_valid_p ();
- clear_step_over_info ();
insert_hp_step_resume_breakpoint_at_frame (frame);
ecs->event_thread->step_after_step_resume_breakpoint = 1;
/* Reset trap_expected to ensure breakpoints are re-inserted. */
ecs->event_thread->control.trap_expected = 0;
- if (target_is_non_stop_p ())
- {
- /* Either "set non-stop" is "on", or the target is
- always in non-stop mode. In this case, we have a bit
- more work to do. Resume the current thread, and if
- we had paused all threads, restart them while the
- signal handler runs. */
- keep_going (ecs);
-
- if (was_in_line)
- {
- restart_threads (ecs->event_thread);
- }
- else if (debug_infrun)
- {
- fprintf_unfiltered (gdb_stdlog,
- "infrun: no need to restart threads\n");
- }
- return;
- }
-
/* If we were nexting/stepping some other thread, switch to
it, so that we don't continue it, losing control. */
if (!switch_back_to_stepped_thread (ecs))
}
if (ecs->event_thread->suspend.stop_signal != GDB_SIGNAL_0
- && (pc_in_thread_step_range (stop_pc, ecs->event_thread)
+ && (pc_in_thread_step_range (ecs->event_thread->suspend.stop_pc,
+ ecs->event_thread)
|| ecs->event_thread->control.step_range_end == 1)
&& frame_id_eq (get_stack_frame_id (frame),
ecs->event_thread->control.step_stack_frame_id)
return;
}
fill_in_stop_func (gdbarch, ecs);
- if (stop_pc == ecs->stop_func_start
+ if (ecs->event_thread->suspend.stop_pc == ecs->stop_func_start
&& execution_direction == EXEC_REVERSE)
{
/* We are stepping over a function call in reverse, and just
through a function epilogue and therefore must detect when
the current-frame changes in the middle of a line. */
- if (pc_in_thread_step_range (stop_pc, ecs->event_thread)
+ if (pc_in_thread_step_range (ecs->event_thread->suspend.stop_pc,
+ ecs->event_thread)
&& (execution_direction != EXEC_REVERSE
|| frame_id_eq (get_frame_id (frame),
ecs->event_thread->control.step_frame_id)))
/* When stepping backward, stop at beginning of line range
(unless it's the function entry point, in which case
keep going back to the call point). */
+ CORE_ADDR stop_pc = ecs->event_thread->suspend.stop_pc;
if (stop_pc == ecs->event_thread->control.step_range_start
&& stop_pc != ecs->stop_func_start
&& execution_direction == EXEC_REVERSE)
if (execution_direction != EXEC_REVERSE
&& ecs->event_thread->control.step_over_calls == STEP_OVER_UNDEBUGGABLE
- && in_solib_dynsym_resolve_code (stop_pc))
+ && in_solib_dynsym_resolve_code (ecs->event_thread->suspend.stop_pc))
{
CORE_ADDR pc_after_resolver =
- gdbarch_skip_solib_resolver (gdbarch, stop_pc);
+ gdbarch_skip_solib_resolver (gdbarch,
+ ecs->event_thread->suspend.stop_pc);
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog,
{
/* Set up a step-resume breakpoint at the address
indicated by SKIP_SOLIB_RESOLVER. */
- struct symtab_and_line sr_sal;
-
- init_sal (&sr_sal);
+ symtab_and_line sr_sal;
sr_sal.pc = pc_after_resolver;
sr_sal.pspace = get_frame_program_space (frame);
return;
}
+ /* Step through an indirect branch thunk. */
+ if (ecs->event_thread->control.step_over_calls != STEP_OVER_NONE
+ && gdbarch_in_indirect_branch_thunk (gdbarch,
+ ecs->event_thread->suspend.stop_pc))
+ {
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: stepped into indirect branch thunk\n");
+ keep_going (ecs);
+ return;
+ }
+
if (ecs->event_thread->control.step_range_end != 1
&& (ecs->event_thread->control.step_over_calls == STEP_OVER_UNDEBUGGABLE
|| ecs->event_thread->control.step_over_calls == STEP_OVER_ALL)
call check below as on some targets return trampolines look
like subroutine calls (MIPS16 return thunks). */
if (gdbarch_in_solib_return_trampoline (gdbarch,
- stop_pc, ecs->stop_func_name)
+ ecs->event_thread->suspend.stop_pc,
+ ecs->stop_func_name)
&& ecs->event_thread->control.step_over_calls != STEP_OVER_NONE)
{
/* Determine where this trampoline returns. */
- CORE_ADDR real_stop_pc;
-
- real_stop_pc = gdbarch_skip_trampoline_code (gdbarch, frame, stop_pc);
+ CORE_ADDR stop_pc = ecs->event_thread->suspend.stop_pc;
+ CORE_ADDR real_stop_pc
+ = gdbarch_skip_trampoline_code (gdbarch, frame, stop_pc);
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog,
if (real_stop_pc)
{
/* And put the step-breakpoint there and go until there. */
- struct symtab_and_line sr_sal;
-
- init_sal (&sr_sal); /* initialize to zeroes */
+ symtab_and_line sr_sal;
sr_sal.pc = real_stop_pc;
sr_sal.section = find_pc_overlay (sr_sal.pc);
sr_sal.pspace = get_frame_program_space (frame);
&& (!frame_id_eq (ecs->event_thread->control.step_stack_frame_id,
outer_frame_id)
|| (ecs->event_thread->control.step_start_function
- != find_pc_function (stop_pc)))))
+ != find_pc_function (ecs->event_thread->suspend.stop_pc)))))
{
+ CORE_ADDR stop_pc = ecs->event_thread->suspend.stop_pc;
CORE_ADDR real_stop_pc;
if (debug_infrun)
to the caller. */
if (ecs->stop_func_start != stop_pc && ecs->stop_func_start != 0)
{
- struct symtab_and_line sr_sal;
-
/* Normal function call return (static or dynamic). */
- init_sal (&sr_sal);
+ symtab_and_line sr_sal;
sr_sal.pc = ecs->stop_func_start;
sr_sal.pspace = get_frame_program_space (frame);
insert_step_resume_breakpoint_at_sal (gdbarch,
if (real_stop_pc != 0 && in_solib_dynsym_resolve_code (real_stop_pc))
{
- struct symtab_and_line sr_sal;
-
- init_sal (&sr_sal);
+ symtab_and_line sr_sal;
sr_sal.pc = ecs->stop_func_start;
sr_sal.pspace = get_frame_program_space (frame);
tmp_sal = find_pc_line (ecs->stop_func_start, 0);
if (tmp_sal.line != 0
&& !function_name_is_marked_for_skip (ecs->stop_func_name,
- &tmp_sal))
+ tmp_sal))
{
if (execution_direction == EXEC_REVERSE)
handle_step_into_function_backward (gdbarch, ecs);
{
/* Set a breakpoint at callee's start address.
From there we can step once and be back in the caller. */
- struct symtab_and_line sr_sal;
-
- init_sal (&sr_sal);
+ symtab_and_line sr_sal;
sr_sal.pc = ecs->stop_func_start;
sr_sal.pspace = get_frame_program_space (frame);
insert_step_resume_breakpoint_at_sal (gdbarch,
if (execution_direction == EXEC_REVERSE
&& ecs->event_thread->control.step_over_calls != STEP_OVER_NONE)
{
+ CORE_ADDR stop_pc = ecs->event_thread->suspend.stop_pc;
+
if (gdbarch_skip_trampoline_code (gdbarch, frame, stop_pc)
|| (ecs->stop_func_start == 0
&& in_solib_dynsym_resolve_code (stop_pc)))
/* Stepped backward into the solib dynsym resolver.
Set a breakpoint at its start and continue, then
one more step will take us out. */
- struct symtab_and_line sr_sal;
-
- init_sal (&sr_sal);
+ symtab_and_line sr_sal;
sr_sal.pc = ecs->stop_func_start;
sr_sal.pspace = get_frame_program_space (frame);
insert_step_resume_breakpoint_at_sal (gdbarch,
}
}
- stop_pc_sal = find_pc_line (stop_pc, 0);
+ stop_pc_sal = find_pc_line (ecs->event_thread->suspend.stop_pc, 0);
/* NOTE: tausq/2004-05-24: This if block used to be done before all
the trampoline processing logic, however, there are some trampolines
if (frame_id_eq (get_frame_id (get_current_frame ()),
ecs->event_thread->control.step_frame_id)
- && inline_skipped_frames (ecs->ptid))
+ && inline_skipped_frames (ecs->event_thread))
{
- struct symtab_and_line call_sal;
-
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog,
"infrun: stepped into inlined function\n");
- find_frame_sal (get_current_frame (), &call_sal);
+ symtab_and_line call_sal = find_frame_sal (get_current_frame ());
if (ecs->event_thread->control.step_over_calls != STEP_OVER_ALL)
{
if (call_sal.line == ecs->event_thread->current_line
&& call_sal.symtab == ecs->event_thread->current_symtab)
- step_into_inline_frame (ecs->ptid);
+ step_into_inline_frame (ecs->event_thread);
end_stepping_range (ecs);
return;
return;
}
- if ((stop_pc == stop_pc_sal.pc)
+ if ((ecs->event_thread->suspend.stop_pc == stop_pc_sal.pc)
&& (ecs->event_thread->current_line != stop_pc_sal.line
|| ecs->event_thread->current_symtab != stop_pc_sal.symtab))
{
{
if (!target_is_non_stop_p ())
{
- struct thread_info *tp;
struct thread_info *stepping_thread;
/* If any thread is blocked on some internal breakpoint, and we
/* Look for the stepping/nexting thread. */
stepping_thread = NULL;
- ALL_NON_EXITED_THREADS (tp)
+ for (thread_info *tp : all_non_exited_threads ())
{
/* Ignore threads of processes the caller is not
resuming. */
if (!sched_multi
- && ptid_get_pid (tp->ptid) != ptid_get_pid (ecs->ptid))
+ && tp->ptid.pid () != ecs->ptid.pid ())
continue;
/* When stepping over a breakpoint, we lock all threads
stepping thread is still alive. For that reason, we need to
synchronously query the target now. */
- if (is_exited (tp->ptid)
- || !target_thread_alive (tp->ptid))
+ if (tp->state == THREAD_EXITED || !target_thread_alive (tp->ptid))
{
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog,
"infrun: not resuming previously "
"stepped thread, it has vanished\n");
- delete_thread (tp->ptid);
+ delete_thread (tp);
return 0;
}
"infrun: resuming previously stepped thread\n");
reset_ecs (ecs, tp);
- switch_to_thread (tp->ptid);
+ switch_to_thread (tp);
- stop_pc = regcache_read_pc (get_thread_regcache (tp->ptid));
+ tp->suspend.stop_pc = regcache_read_pc (get_thread_regcache (tp));
frame = get_current_frame ();
/* If the PC of the thread we were trying to single-step has
This prevents us continuously moving the single-step breakpoint
forward, one instruction at a time, overstepping. */
- if (stop_pc != tp->prev_pc)
+ if (tp->suspend.stop_pc != tp->prev_pc)
{
ptid_t resume_ptid;
fprintf_unfiltered (gdb_stdlog,
"infrun: expected thread advanced also (%s -> %s)\n",
paddress (target_gdbarch (), tp->prev_pc),
- paddress (target_gdbarch (), stop_pc));
+ paddress (target_gdbarch (), tp->suspend.stop_pc));
/* Clear the info of the previous step-over, as it's no longer
valid (if the thread was trying to step over a breakpoint, it
insert_single_step_breakpoint (get_frame_arch (frame),
get_frame_address_space (frame),
- stop_pc);
+ tp->suspend.stop_pc);
tp->resumed = 1;
resume_ptid = internal_resume_ptid (tp->control.stepping_command);
handle_step_into_function (struct gdbarch *gdbarch,
struct execution_control_state *ecs)
{
- struct compunit_symtab *cust;
- struct symtab_and_line stop_func_sal, sr_sal;
-
fill_in_stop_func (gdbarch, ecs);
- cust = find_pc_compunit_symtab (stop_pc);
+ compunit_symtab *cust
+ = find_pc_compunit_symtab (ecs->event_thread->suspend.stop_pc);
if (cust != NULL && compunit_language (cust) != language_asm)
- ecs->stop_func_start = gdbarch_skip_prologue (gdbarch,
- ecs->stop_func_start);
+ ecs->stop_func_start
+ = gdbarch_skip_prologue_noexcept (gdbarch, ecs->stop_func_start);
- stop_func_sal = find_pc_line (ecs->stop_func_start, 0);
+ symtab_and_line stop_func_sal = find_pc_line (ecs->stop_func_start, 0);
/* Use the step_resume_break to step until the end of the prologue,
even if that involves jumps (as it seems to on the vax under
4.2). */
ecs->stop_func_start);
}
- if (ecs->stop_func_start == stop_pc)
+ if (ecs->stop_func_start == ecs->event_thread->suspend.stop_pc)
{
/* We are already there: stop now. */
end_stepping_range (ecs);
else
{
/* Put the step-breakpoint there and go until there. */
- init_sal (&sr_sal); /* initialize to zeroes */
+ symtab_and_line sr_sal;
sr_sal.pc = ecs->stop_func_start;
sr_sal.section = find_pc_overlay (ecs->stop_func_start);
sr_sal.pspace = get_frame_program_space (get_current_frame ());
fill_in_stop_func (gdbarch, ecs);
- cust = find_pc_compunit_symtab (stop_pc);
+ cust = find_pc_compunit_symtab (ecs->event_thread->suspend.stop_pc);
if (cust != NULL && compunit_language (cust) != language_asm)
- ecs->stop_func_start = gdbarch_skip_prologue (gdbarch,
- ecs->stop_func_start);
+ ecs->stop_func_start
+ = gdbarch_skip_prologue_noexcept (gdbarch, ecs->stop_func_start);
- stop_func_sal = find_pc_line (stop_pc, 0);
+ stop_func_sal = find_pc_line (ecs->event_thread->suspend.stop_pc, 0);
/* OK, we're just going to keep stepping here. */
- if (stop_func_sal.pc == stop_pc)
+ if (stop_func_sal.pc == ecs->event_thread->suspend.stop_pc)
{
/* We're there already. Just stop stepping now. */
end_stepping_range (ecs);
paddress (gdbarch, sr_sal.pc));
inferior_thread ()->control.step_resume_breakpoint
- = set_momentary_breakpoint (gdbarch, sr_sal, sr_id, sr_type);
+ = set_momentary_breakpoint (gdbarch, sr_sal, sr_id, sr_type).release ();
}
void
static void
insert_hp_step_resume_breakpoint_at_frame (struct frame_info *return_frame)
{
- struct symtab_and_line sr_sal;
- struct gdbarch *gdbarch;
-
gdb_assert (return_frame != NULL);
- init_sal (&sr_sal); /* initialize to zeros */
- gdbarch = get_frame_arch (return_frame);
+ struct gdbarch *gdbarch = get_frame_arch (return_frame);
+
+ symtab_and_line sr_sal;
sr_sal.pc = gdbarch_addr_bits_remove (gdbarch, get_frame_pc (return_frame));
sr_sal.section = find_pc_overlay (sr_sal.pc);
sr_sal.pspace = get_frame_program_space (return_frame);
static void
insert_step_resume_breakpoint_at_caller (struct frame_info *next_frame)
{
- struct symtab_and_line sr_sal;
- struct gdbarch *gdbarch;
-
/* We shouldn't have gotten here if we don't know where the call site
is. */
gdb_assert (frame_id_p (frame_unwind_caller_id (next_frame)));
- init_sal (&sr_sal); /* initialize to zeros */
+ struct gdbarch *gdbarch = frame_unwind_caller_arch (next_frame);
- gdbarch = frame_unwind_caller_arch (next_frame);
+ symtab_and_line sr_sal;
sr_sal.pc = gdbarch_addr_bits_remove (gdbarch,
frame_unwind_caller_pc (next_frame));
sr_sal.section = find_pc_overlay (sr_sal.pc);
paddress (gdbarch, pc));
inferior_thread ()->control.exception_resume_breakpoint =
- set_momentary_breakpoint_at_pc (gdbarch, pc, bp_longjmp_resume);
+ set_momentary_breakpoint_at_pc (gdbarch, pc, bp_longjmp_resume).release ();
}
/* Insert an exception resume breakpoint. TP is the thread throwing
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))
(unsigned long) handler);
bp = set_momentary_breakpoint_at_pc (get_frame_arch (frame),
- handler, bp_exception_resume);
+ handler,
+ bp_exception_resume).release ();
/* set_momentary_breakpoint_at_pc invalidates FRAME. */
frame = NULL;
handler));
bp = set_momentary_breakpoint_at_pc (get_frame_arch (frame),
- handler, bp_exception_resume);
+ handler, bp_exception_resume).release ();
bp->thread = tp->global_num;
inferior_thread ()->control.exception_resume_breakpoint = bp;
}
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;
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: stop_waiting\n");
- clear_step_over_info ();
-
/* Let callers know we don't want to wait for the inferior anymore. */
ecs->wait_some_more = 0;
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->ptid == inferior_ptid);
gdb_assert (!ecs->event_thread->resumed);
/* Save the pc before execution, to compare with pc after stop. */
ecs->event_thread->prev_pc
- = regcache_read_pc (get_thread_regcache (ecs->ptid));
+ = regcache_read_pc (get_thread_regcache (ecs->event_thread));
if (ecs->event_thread->control.trap_expected)
{
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
{
if (remove_bp
&& (remove_wps || !use_displaced_stepping (ecs->event_thread)))
{
- set_step_over_info (get_regcache_aspace (regcache),
+ set_step_over_info (regcache->aspace (),
regcache_read_pc (regcache), remove_wps,
ecs->event_thread->global_num);
}
{
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);
}
{
/* For CLI-like interpreters, print nothing. */
- if (ui_out_is_mi_like_p (uiout))
+ if (uiout->is_mi_like_p ())
{
- ui_out_field_string (uiout, "reason",
+ uiout->field_string ("reason",
async_reason_lookup (EXEC_ASYNC_END_STEPPING_RANGE));
}
}
print_signal_exited_reason (struct ui_out *uiout, enum gdb_signal siggnal)
{
annotate_signalled ();
- if (ui_out_is_mi_like_p (uiout))
- ui_out_field_string
- (uiout, "reason", async_reason_lookup (EXEC_ASYNC_EXITED_SIGNALLED));
- ui_out_text (uiout, "\nProgram terminated with signal ");
+ if (uiout->is_mi_like_p ())
+ uiout->field_string
+ ("reason", async_reason_lookup (EXEC_ASYNC_EXITED_SIGNALLED));
+ uiout->text ("\nProgram terminated with signal ");
annotate_signal_name ();
- ui_out_field_string (uiout, "signal-name",
+ uiout->field_string ("signal-name",
gdb_signal_to_name (siggnal));
annotate_signal_name_end ();
- ui_out_text (uiout, ", ");
+ uiout->text (", ");
annotate_signal_string ();
- ui_out_field_string (uiout, "signal-meaning",
+ uiout->field_string ("signal-meaning",
gdb_signal_to_string (siggnal));
annotate_signal_string_end ();
- ui_out_text (uiout, ".\n");
- ui_out_text (uiout, "The program no longer exists.\n");
+ uiout->text (".\n");
+ uiout->text ("The program no longer exists.\n");
}
void
print_exited_reason (struct ui_out *uiout, int exitstatus)
{
struct inferior *inf = current_inferior ();
- const char *pidstr = target_pid_to_str (pid_to_ptid (inf->pid));
+ const char *pidstr = target_pid_to_str (ptid_t (inf->pid));
annotate_exited (exitstatus);
if (exitstatus)
{
- if (ui_out_is_mi_like_p (uiout))
- ui_out_field_string (uiout, "reason",
- async_reason_lookup (EXEC_ASYNC_EXITED));
- ui_out_text (uiout, "[Inferior ");
- ui_out_text (uiout, plongest (inf->num));
- ui_out_text (uiout, " (");
- ui_out_text (uiout, pidstr);
- ui_out_text (uiout, ") exited with code ");
- ui_out_field_fmt (uiout, "exit-code", "0%o", (unsigned int) exitstatus);
- ui_out_text (uiout, "]\n");
+ if (uiout->is_mi_like_p ())
+ uiout->field_string ("reason", async_reason_lookup (EXEC_ASYNC_EXITED));
+ uiout->text ("[Inferior ");
+ uiout->text (plongest (inf->num));
+ uiout->text (" (");
+ uiout->text (pidstr);
+ uiout->text (") exited with code ");
+ uiout->field_fmt ("exit-code", "0%o", (unsigned int) exitstatus);
+ uiout->text ("]\n");
}
else
{
- if (ui_out_is_mi_like_p (uiout))
- ui_out_field_string
- (uiout, "reason", async_reason_lookup (EXEC_ASYNC_EXITED_NORMALLY));
- ui_out_text (uiout, "[Inferior ");
- ui_out_text (uiout, plongest (inf->num));
- ui_out_text (uiout, " (");
- ui_out_text (uiout, pidstr);
- ui_out_text (uiout, ") exited normally]\n");
+ if (uiout->is_mi_like_p ())
+ uiout->field_string
+ ("reason", async_reason_lookup (EXEC_ASYNC_EXITED_NORMALLY));
+ uiout->text ("[Inferior ");
+ uiout->text (plongest (inf->num));
+ uiout->text (" (");
+ uiout->text (pidstr);
+ uiout->text (") exited normally]\n");
}
}
handle_segmentation_fault (struct ui_out *uiout)
{
struct regcache *regcache = get_current_regcache ();
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = regcache->arch ();
if (gdbarch_handle_segmentation_fault_p (gdbarch))
gdbarch_handle_segmentation_fault (gdbarch, uiout);
annotate_signal ();
- if (ui_out_is_mi_like_p (uiout))
+ if (uiout->is_mi_like_p ())
;
else if (show_thread_that_caused_stop ())
{
const char *name;
- ui_out_text (uiout, "\nThread ");
- ui_out_field_fmt (uiout, "thread-id", "%s", print_thread_id (thr));
+ uiout->text ("\nThread ");
+ uiout->field_fmt ("thread-id", "%s", print_thread_id (thr));
name = thr->name != NULL ? thr->name : target_thread_name (thr);
if (name != NULL)
{
- ui_out_text (uiout, " \"");
- ui_out_field_fmt (uiout, "name", "%s", name);
- ui_out_text (uiout, "\"");
+ uiout->text (" \"");
+ uiout->field_fmt ("name", "%s", name);
+ uiout->text ("\"");
}
}
else
- ui_out_text (uiout, "\nProgram");
+ uiout->text ("\nProgram");
- if (siggnal == GDB_SIGNAL_0 && !ui_out_is_mi_like_p (uiout))
- ui_out_text (uiout, " stopped");
+ if (siggnal == GDB_SIGNAL_0 && !uiout->is_mi_like_p ())
+ uiout->text (" stopped");
else
{
- ui_out_text (uiout, " received signal ");
+ uiout->text (" received signal ");
annotate_signal_name ();
- if (ui_out_is_mi_like_p (uiout))
- ui_out_field_string
- (uiout, "reason", async_reason_lookup (EXEC_ASYNC_SIGNAL_RECEIVED));
- ui_out_field_string (uiout, "signal-name",
- gdb_signal_to_name (siggnal));
+ if (uiout->is_mi_like_p ())
+ uiout->field_string
+ ("reason", async_reason_lookup (EXEC_ASYNC_SIGNAL_RECEIVED));
+ uiout->field_string ("signal-name", gdb_signal_to_name (siggnal));
annotate_signal_name_end ();
- ui_out_text (uiout, ", ");
+ uiout->text (", ");
annotate_signal_string ();
- ui_out_field_string (uiout, "signal-meaning",
- gdb_signal_to_string (siggnal));
+ uiout->field_string ("signal-meaning", gdb_signal_to_string (siggnal));
if (siggnal == GDB_SIGNAL_SEGV)
handle_segmentation_fault (uiout);
annotate_signal_string_end ();
}
- ui_out_text (uiout, ".\n");
+ uiout->text (".\n");
}
void
print_no_history_reason (struct ui_out *uiout)
{
- ui_out_text (uiout, "\nNo more reverse-execution history.\n");
+ uiout->text ("\nNo more reverse-execution history.\n");
}
/* Print current location without a level number, if we have changed
if (tp->control.stop_step
&& frame_id_eq (tp->control.step_frame_id,
get_frame_id (get_current_frame ()))
- && tp->control.step_start_function == find_pc_function (stop_pc))
+ && (tp->control.step_start_function
+ == find_pc_function (tp->suspend.stop_pc)))
{
/* Finished step, just print source line. */
source_flag = SRC_LINE;
void
print_stop_event (struct ui_out *uiout)
{
- struct cleanup *old_chain;
struct target_waitstatus last;
ptid_t last_ptid;
struct thread_info *tp;
get_last_target_status (&last_ptid, &last);
- old_chain = make_cleanup_restore_current_uiout ();
- current_uiout = uiout;
-
- print_stop_location (&last);
+ {
+ scoped_restore save_uiout = make_scoped_restore (¤t_uiout, uiout);
- /* Display the auto-display expressions. */
- do_displays ();
+ print_stop_location (&last);
- do_cleanups (old_chain);
+ /* Display the auto-display expressions. */
+ do_displays ();
+ }
tp = inferior_thread ();
if (tp->thread_fsm != NULL
{
if (remove_breakpoints ())
{
- target_terminal_ours_for_output ();
+ target_terminal::ours_for_output ();
printf_filtered (_("Cannot remove breakpoints because "
"program is no longer writable.\nFurther "
"execution is probably impossible.\n"));
struct stop_context
{
+ stop_context ();
+ ~stop_context ();
+
+ DISABLE_COPY_AND_ASSIGN (stop_context);
+
+ bool changed () const;
+
/* The stop ID. */
ULONGEST stop_id;
int inf_num;
};
-/* Returns a new stop context. If stopped for a thread event, this
+/* Initializes a new stop context. If stopped for a thread event, this
takes a strong reference to the thread. */
-static struct stop_context *
-save_stop_context (void)
+stop_context::stop_context ()
{
- struct stop_context *sc = XNEW (struct stop_context);
-
- sc->stop_id = get_stop_id ();
- sc->ptid = inferior_ptid;
- sc->inf_num = current_inferior ()->num;
+ stop_id = get_stop_id ();
+ ptid = inferior_ptid;
+ inf_num = current_inferior ()->num;
- if (!ptid_equal (inferior_ptid, null_ptid))
+ if (inferior_ptid != null_ptid)
{
/* Take a strong reference so that the thread can't be deleted
yet. */
- sc->thread = inferior_thread ();
- sc->thread->refcount++;
+ thread = inferior_thread ();
+ thread->incref ();
}
else
- sc->thread = NULL;
-
- return sc;
+ thread = NULL;
}
/* Release a stop context previously created with save_stop_context.
Releases the strong reference to the thread as well. */
-static void
-release_stop_context_cleanup (void *arg)
+stop_context::~stop_context ()
{
- struct stop_context *sc = (struct stop_context *) arg;
-
- if (sc->thread != NULL)
- sc->thread->refcount--;
- xfree (sc);
+ if (thread != NULL)
+ thread->decref ();
}
/* Return true if the current context no longer matches the saved stop
context. */
-static int
-stop_context_changed (struct stop_context *prev)
-{
- if (!ptid_equal (prev->ptid, inferior_ptid))
- return 1;
- if (prev->inf_num != current_inferior ()->num)
- return 1;
- if (prev->thread != NULL && prev->thread->state != THREAD_STOPPED)
- return 1;
- if (get_stop_id () != prev->stop_id)
- return 1;
- return 0;
+bool
+stop_context::changed () const
+{
+ if (ptid != inferior_ptid)
+ return true;
+ if (inf_num != current_inferior ()->num)
+ return true;
+ if (thread != NULL && thread->state != THREAD_STOPPED)
+ return true;
+ if (get_stop_id () != stop_id)
+ return true;
+ return false;
}
/* See infrun.h. */
{
struct target_waitstatus last;
ptid_t last_ptid;
- struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
- ptid_t pid_ptid;
- struct switch_thru_all_uis state;
get_last_target_status (&last_ptid, &last);
propagate GDB's knowledge of the executing state to the
frontend/user running state. A QUIT is an easy exception to see
here, so do this before any filtered output. */
+
+ gdb::optional<scoped_finish_thread_state> maybe_finish_thread_state;
+
if (!non_stop)
- make_cleanup (finish_thread_state_cleanup, &minus_one_ptid);
+ maybe_finish_thread_state.emplace (minus_one_ptid);
else if (last.kind == TARGET_WAITKIND_SIGNALLED
|| last.kind == TARGET_WAITKIND_EXITED)
{
"checkpoint", when the current checkpoint/fork exits,
linux-fork.c automatically switches to another fork from
within target_mourn_inferior. */
- if (!ptid_equal (inferior_ptid, null_ptid))
- {
- pid_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
- make_cleanup (finish_thread_state_cleanup, &pid_ptid);
- }
+ if (inferior_ptid != null_ptid)
+ maybe_finish_thread_state.emplace (ptid_t (inferior_ptid.pid ()));
}
else if (last.kind != TARGET_WAITKIND_NO_RESUMED)
- make_cleanup (finish_thread_state_cleanup, &inferior_ptid);
+ maybe_finish_thread_state.emplace (inferior_ptid);
/* As we're presenting a stop, and potentially removing breakpoints,
update the thread list so we can tell whether there are threads
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
after this event is handled, so we're not really switching, only
informing of a stop. */
if (!non_stop
- && !ptid_equal (previous_inferior_ptid, inferior_ptid)
+ && previous_inferior_ptid != inferior_ptid
&& target_has_execution
&& last.kind != TARGET_WAITKIND_SIGNALLED
&& last.kind != TARGET_WAITKIND_EXITED
&& last.kind != TARGET_WAITKIND_NO_RESUMED)
{
- SWITCH_THRU_ALL_UIS (state)
+ SWITCH_THRU_ALL_UIS ()
{
- target_terminal_ours_for_output ();
+ target_terminal::ours_for_output ();
printf_filtered (_("[Switching to %s]\n"),
target_pid_to_str (inferior_ptid));
annotate_thread_changed ();
if (last.kind == TARGET_WAITKIND_NO_RESUMED)
{
- SWITCH_THRU_ALL_UIS (state)
+ SWITCH_THRU_ALL_UIS ()
if (current_ui->prompt_state == PROMPT_BLOCKED)
{
- target_terminal_ours_for_output ();
+ target_terminal::ours_for_output ();
printf_filtered (_("No unwaited-for children left.\n"));
}
}
if (stopped_by_random_signal)
disable_current_display ();
- SWITCH_THRU_ALL_UIS (state)
+ SWITCH_THRU_ALL_UIS ()
{
async_enable_stdin ();
}
/* Let the user/frontend see the threads as stopped. */
- do_cleanups (old_chain);
+ maybe_finish_thread_state.reset ();
/* Select innermost stack frame - i.e., current frame is frame 0,
and current location is based on that. Handle the case where the
of stop_command's pre-hook not existing). */
if (stop_command != NULL)
{
- struct stop_context *saved_context = save_stop_context ();
- struct cleanup *old_chain
- = make_cleanup (release_stop_context_cleanup, saved_context);
+ stop_context saved_context;
- catch_errors (hook_stop_stub, stop_command,
- "Error while running hook_stop:\n", RETURN_MASK_ALL);
+ TRY
+ {
+ execute_cmd_pre_hook (stop_command);
+ }
+ CATCH (ex, RETURN_MASK_ALL)
+ {
+ exception_fprintf (gdb_stderr, ex,
+ "Error while running hook_stop:\n");
+ }
+ END_CATCH
/* If the stop hook resumes the target, then there's no point in
trying to notify about the previous stop; its context is
gone. Likewise if the command switches thread or inferior --
the observers would print a stop for the wrong
thread/inferior. */
- if (stop_context_changed (saved_context))
- {
- do_cleanups (old_chain);
- return 1;
- }
- do_cleanups (old_chain);
+ if (saved_context.changed ())
+ return 1;
}
/* 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,
+ if (inferior_ptid != null_ptid)
+ 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 ();
return 0;
}
-
-static int
-hook_stop_stub (void *cmd)
-{
- execute_cmd_pre_hook ((struct cmd_list_element *) cmd);
- return (0);
-}
\f
int
signal_stop_state (int signo)
/* Specify how various signals in the inferior should be handled. */
static void
-handle_command (char *args, int from_tty)
+handle_command (const char *args, int from_tty)
{
- char **argv;
int digits, wordlen;
- int sigfirst, signum, siglast;
+ int sigfirst, siglast;
enum gdb_signal oursig;
int allsigs;
int nsigs;
unsigned char *sigs;
- struct cleanup *old_chain;
if (args == NULL)
{
/* Break the command line up into args. */
- argv = gdb_buildargv (args);
- old_chain = make_cleanup_freeargv (argv);
+ gdb_argv built_argv (args);
/* Walk through the args, looking for signal oursigs, signal names, and
actions. Signal numbers and signal names may be interspersed with
actions, with the actions being performed for all signals cumulatively
specified. Signal ranges can be specified as <LOW>-<HIGH>. */
- while (*argv != NULL)
+ for (char *arg : built_argv)
{
- wordlen = strlen (*argv);
- for (digits = 0; isdigit ((*argv)[digits]); digits++)
+ wordlen = strlen (arg);
+ for (digits = 0; isdigit (arg[digits]); digits++)
{;
}
allsigs = 0;
sigfirst = siglast = -1;
- if (wordlen >= 1 && !strncmp (*argv, "all", wordlen))
+ if (wordlen >= 1 && !strncmp (arg, "all", wordlen))
{
/* Apply action to all signals except those used by the
debugger. Silently skip those. */
sigfirst = 0;
siglast = nsigs - 1;
}
- else if (wordlen >= 1 && !strncmp (*argv, "stop", wordlen))
+ else if (wordlen >= 1 && !strncmp (arg, "stop", wordlen))
{
SET_SIGS (nsigs, sigs, signal_stop);
SET_SIGS (nsigs, sigs, signal_print);
}
- else if (wordlen >= 1 && !strncmp (*argv, "ignore", wordlen))
+ else if (wordlen >= 1 && !strncmp (arg, "ignore", wordlen))
{
UNSET_SIGS (nsigs, sigs, signal_program);
}
- else if (wordlen >= 2 && !strncmp (*argv, "print", wordlen))
+ else if (wordlen >= 2 && !strncmp (arg, "print", wordlen))
{
SET_SIGS (nsigs, sigs, signal_print);
}
- else if (wordlen >= 2 && !strncmp (*argv, "pass", wordlen))
+ else if (wordlen >= 2 && !strncmp (arg, "pass", wordlen))
{
SET_SIGS (nsigs, sigs, signal_program);
}
- else if (wordlen >= 3 && !strncmp (*argv, "nostop", wordlen))
+ else if (wordlen >= 3 && !strncmp (arg, "nostop", wordlen))
{
UNSET_SIGS (nsigs, sigs, signal_stop);
}
- else if (wordlen >= 3 && !strncmp (*argv, "noignore", wordlen))
+ else if (wordlen >= 3 && !strncmp (arg, "noignore", wordlen))
{
SET_SIGS (nsigs, sigs, signal_program);
}
- else if (wordlen >= 4 && !strncmp (*argv, "noprint", wordlen))
+ else if (wordlen >= 4 && !strncmp (arg, "noprint", wordlen))
{
UNSET_SIGS (nsigs, sigs, signal_print);
UNSET_SIGS (nsigs, sigs, signal_stop);
}
- else if (wordlen >= 4 && !strncmp (*argv, "nopass", wordlen))
+ else if (wordlen >= 4 && !strncmp (arg, "nopass", wordlen))
{
UNSET_SIGS (nsigs, sigs, signal_program);
}
SIGHUP, SIGINT, SIGALRM, etc. will work right anyway. */
sigfirst = siglast = (int)
- gdb_signal_from_command (atoi (*argv));
- if ((*argv)[digits] == '-')
+ gdb_signal_from_command (atoi (arg));
+ if (arg[digits] == '-')
{
siglast = (int)
- gdb_signal_from_command (atoi ((*argv) + digits + 1));
+ gdb_signal_from_command (atoi (arg + digits + 1));
}
if (sigfirst > siglast)
{
/* Bet he didn't figure we'd think of this case... */
- signum = sigfirst;
- sigfirst = siglast;
- siglast = signum;
+ std::swap (sigfirst, siglast);
}
}
else
{
- oursig = gdb_signal_from_name (*argv);
+ oursig = gdb_signal_from_name (arg);
if (oursig != GDB_SIGNAL_UNKNOWN)
{
sigfirst = siglast = (int) oursig;
else
{
/* Not a number and not a recognized flag word => complain. */
- error (_("Unrecognized or ambiguous flag word: \"%s\"."), *argv);
+ error (_("Unrecognized or ambiguous flag word: \"%s\"."), arg);
}
}
/* If any signal numbers or symbol names were found, set flags for
which signals to apply actions to. */
- for (signum = sigfirst; signum >= 0 && signum <= siglast; signum++)
+ for (int signum = sigfirst; signum >= 0 && signum <= siglast; signum++)
{
switch ((enum gdb_signal) signum)
{
break;
}
}
-
- argv++;
}
- for (signum = 0; signum < nsigs; signum++)
+ for (int signum = 0; signum < nsigs; signum++)
if (sigs[signum])
{
signal_cache_update (-1);
break;
}
-
- do_cleanups (old_chain);
}
/* Complete the "handle" command. */
-static VEC (char_ptr) *
+static void
handle_completer (struct cmd_list_element *ignore,
+ completion_tracker &tracker,
const char *text, const char *word)
{
- VEC (char_ptr) *vec_signals, *vec_keywords, *return_val;
static const char * const keywords[] =
{
"all",
NULL,
};
- vec_signals = signal_completer (ignore, text, word);
- vec_keywords = complete_on_enum (keywords, word, word);
-
- return_val = VEC_merge (char_ptr, vec_signals, vec_keywords);
- VEC_free (char_ptr, vec_signals);
- VEC_free (char_ptr, vec_keywords);
- return return_val;
+ signal_completer (ignore, tracker, text, word);
+ complete_on_enum (tracker, keywords, word, word);
}
enum gdb_signal
targets, all signals should be in the signal tables). */
static void
-signals_info (char *signum_exp, int from_tty)
+info_signals_command (const char *signum_exp, int from_tty)
{
enum gdb_signal oursig;
validate_registers_access ();
transferred =
- target_read (¤t_target, TARGET_OBJECT_SIGNAL_INFO,
+ target_read (current_top_target (), TARGET_OBJECT_SIGNAL_INFO,
NULL,
value_contents_all_raw (v),
value_offset (v),
vice versa. */
validate_registers_access ();
- transferred = target_write (¤t_target,
+ transferred = target_write (current_top_target (),
TARGET_OBJECT_SIGNAL_INFO,
NULL,
value_contents_all_raw (fromval),
void *ignore)
{
if (target_has_stack
- && !ptid_equal (inferior_ptid, null_ptid)
+ && inferior_ptid != null_ptid
&& gdbarch_get_siginfo_type_p (gdbarch))
{
struct type *type = gdbarch_get_siginfo_type (gdbarch);
ends (either successfully, or after it hits a breakpoint or signal)
if the program is to properly continue where it left off. */
-struct infcall_suspend_state
+class infcall_suspend_state
{
- struct thread_suspend_state thread_suspend;
+public:
+ /* Capture state from GDBARCH, TP, and REGCACHE that must be restored
+ once the inferior function call has finished. */
+ infcall_suspend_state (struct gdbarch *gdbarch,
+ const struct thread_info *tp,
+ struct regcache *regcache)
+ : m_thread_suspend (tp->suspend),
+ m_registers (new readonly_detached_regcache (*regcache))
+ {
+ gdb::unique_xmalloc_ptr<gdb_byte> siginfo_data;
- /* Other fields: */
- CORE_ADDR stop_pc;
- struct regcache *registers;
+ if (gdbarch_get_siginfo_type_p (gdbarch))
+ {
+ struct type *type = gdbarch_get_siginfo_type (gdbarch);
+ size_t len = TYPE_LENGTH (type);
+
+ siginfo_data.reset ((gdb_byte *) xmalloc (len));
+
+ if (target_read (current_top_target (), TARGET_OBJECT_SIGNAL_INFO, NULL,
+ siginfo_data.get (), 0, len) != len)
+ {
+ /* Errors ignored. */
+ siginfo_data.reset (nullptr);
+ }
+ }
+
+ if (siginfo_data)
+ {
+ m_siginfo_gdbarch = gdbarch;
+ m_siginfo_data = std::move (siginfo_data);
+ }
+ }
+
+ /* Return a pointer to the stored register state. */
+
+ readonly_detached_regcache *registers () const
+ {
+ return m_registers.get ();
+ }
+
+ /* Restores the stored state into GDBARCH, TP, and REGCACHE. */
+
+ void restore (struct gdbarch *gdbarch,
+ struct thread_info *tp,
+ struct regcache *regcache) const
+ {
+ tp->suspend = m_thread_suspend;
+
+ if (m_siginfo_gdbarch == gdbarch)
+ {
+ struct type *type = gdbarch_get_siginfo_type (gdbarch);
+
+ /* Errors ignored. */
+ target_write (current_top_target (), TARGET_OBJECT_SIGNAL_INFO, NULL,
+ m_siginfo_data.get (), 0, TYPE_LENGTH (type));
+ }
+
+ /* The inferior can be gone if the user types "print exit(0)"
+ (and perhaps other times). */
+ if (target_has_execution)
+ /* NB: The register write goes through to the target. */
+ regcache->restore (registers ());
+ }
+
+private:
+ /* How the current thread stopped before the inferior function call was
+ executed. */
+ struct thread_suspend_state m_thread_suspend;
+
+ /* The registers before the inferior function call was executed. */
+ std::unique_ptr<readonly_detached_regcache> m_registers;
/* Format of SIGINFO_DATA or NULL if it is not present. */
- struct gdbarch *siginfo_gdbarch;
+ struct gdbarch *m_siginfo_gdbarch = nullptr;
/* The inferior format depends on SIGINFO_GDBARCH and it has a length of
TYPE_LENGTH (gdbarch_get_siginfo_type ()). For different gdbarch the
content would be invalid. */
- gdb_byte *siginfo_data;
+ gdb::unique_xmalloc_ptr<gdb_byte> m_siginfo_data;
};
-struct infcall_suspend_state *
-save_infcall_suspend_state (void)
+infcall_suspend_state_up
+save_infcall_suspend_state ()
{
- struct infcall_suspend_state *inf_state;
struct thread_info *tp = inferior_thread ();
struct regcache *regcache = get_current_regcache ();
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
- gdb_byte *siginfo_data = NULL;
-
- if (gdbarch_get_siginfo_type_p (gdbarch))
- {
- struct type *type = gdbarch_get_siginfo_type (gdbarch);
- size_t len = TYPE_LENGTH (type);
- struct cleanup *back_to;
-
- siginfo_data = (gdb_byte *) xmalloc (len);
- back_to = make_cleanup (xfree, siginfo_data);
+ struct gdbarch *gdbarch = regcache->arch ();
- if (target_read (¤t_target, TARGET_OBJECT_SIGNAL_INFO, NULL,
- siginfo_data, 0, len) == len)
- discard_cleanups (back_to);
- else
- {
- /* Errors ignored. */
- do_cleanups (back_to);
- siginfo_data = NULL;
- }
- }
-
- inf_state = XCNEW (struct infcall_suspend_state);
-
- if (siginfo_data)
- {
- inf_state->siginfo_gdbarch = gdbarch;
- inf_state->siginfo_data = siginfo_data;
- }
+ infcall_suspend_state_up inf_state
+ (new struct infcall_suspend_state (gdbarch, tp, regcache));
- inf_state->thread_suspend = tp->suspend;
-
- /* run_inferior_call will not use the signal due to its `proceed' call with
- GDB_SIGNAL_0 anyway. */
+ /* Having saved the current state, adjust the thread state, discarding
+ any stop signal information. The stop signal is not useful when
+ starting an inferior function call, and run_inferior_call will not use
+ the signal due to its `proceed' call with GDB_SIGNAL_0. */
tp->suspend.stop_signal = GDB_SIGNAL_0;
- inf_state->stop_pc = stop_pc;
-
- inf_state->registers = regcache_dup (regcache);
-
return inf_state;
}
{
struct thread_info *tp = inferior_thread ();
struct regcache *regcache = get_current_regcache ();
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
-
- tp->suspend = inf_state->thread_suspend;
-
- stop_pc = inf_state->stop_pc;
-
- if (inf_state->siginfo_gdbarch == gdbarch)
- {
- struct type *type = gdbarch_get_siginfo_type (gdbarch);
-
- /* Errors ignored. */
- target_write (¤t_target, TARGET_OBJECT_SIGNAL_INFO, NULL,
- inf_state->siginfo_data, 0, TYPE_LENGTH (type));
- }
-
- /* The inferior can be gone if the user types "print exit(0)"
- (and perhaps other times). */
- if (target_has_execution)
- /* NB: The register write goes through to the target. */
- regcache_cpy (regcache, inf_state->registers);
+ struct gdbarch *gdbarch = regcache->arch ();
+ inf_state->restore (gdbarch, tp, regcache);
discard_infcall_suspend_state (inf_state);
}
-static void
-do_restore_infcall_suspend_state_cleanup (void *state)
-{
- restore_infcall_suspend_state ((struct infcall_suspend_state *) state);
-}
-
-struct cleanup *
-make_cleanup_restore_infcall_suspend_state
- (struct infcall_suspend_state *inf_state)
-{
- return make_cleanup (do_restore_infcall_suspend_state_cleanup, inf_state);
-}
-
void
discard_infcall_suspend_state (struct infcall_suspend_state *inf_state)
{
- regcache_xfree (inf_state->registers);
- xfree (inf_state->siginfo_data);
- xfree (inf_state);
+ delete inf_state;
}
-struct regcache *
+readonly_detached_regcache *
get_infcall_suspend_state_regcache (struct infcall_suspend_state *inf_state)
{
- return inf_state->registers;
+ return inf_state->registers ();
}
/* infcall_control_state contains state regarding gdb's control of the
struct inferior_control_state inferior_control;
/* Other fields: */
- enum stop_stack_kind stop_stack_dummy;
- int stopped_by_random_signal;
+ enum stop_stack_kind stop_stack_dummy = STOP_NONE;
+ int stopped_by_random_signal = 0;
/* ID if the selected frame when the inferior function call was made. */
- struct frame_id selected_frame_id;
+ struct frame_id selected_frame_id {};
};
/* Save all of the information associated with the inferior<==>gdb
connection. */
-struct infcall_control_state *
-save_infcall_control_state (void)
+infcall_control_state_up
+save_infcall_control_state ()
{
- struct infcall_control_state *inf_status =
- XNEW (struct infcall_control_state);
+ infcall_control_state_up inf_status (new struct infcall_control_state);
struct thread_info *tp = inferior_thread ();
struct inferior *inf = current_inferior ();
return inf_status;
}
-static int
-restore_selected_frame (void *args)
+static void
+restore_selected_frame (const frame_id &fid)
{
- struct frame_id *fid = (struct frame_id *) args;
- struct frame_info *frame;
-
- frame = frame_find_by_id (*fid);
+ frame_info *frame = frame_find_by_id (fid);
/* If inf_status->selected_frame_id is NULL, there was no previously
selected frame. */
if (frame == NULL)
{
warning (_("Unable to restore previously selected frame."));
- return 0;
+ return;
}
select_frame (frame);
-
- return (1);
}
/* Restore inferior session state to INF_STATUS. */
if (target_has_stack)
{
- /* The point of catch_errors is that if the stack is clobbered,
+ /* The point of the try/catch is that if the stack is clobbered,
walking the stack might encounter a garbage pointer and
error() trying to dereference it. */
- if (catch_errors
- (restore_selected_frame, &inf_status->selected_frame_id,
- "Unable to restore previously selected frame:\n",
- RETURN_MASK_ERROR) == 0)
- /* Error in restoring the selected frame. Select the innermost
- frame. */
- select_frame (get_current_frame ());
+ TRY
+ {
+ restore_selected_frame (inf_status->selected_frame_id);
+ }
+ CATCH (ex, RETURN_MASK_ERROR)
+ {
+ exception_fprintf (gdb_stderr, ex,
+ "Unable to restore previously selected frame:\n");
+ /* Error in restoring the selected frame. Select the
+ innermost frame. */
+ select_frame (get_current_frame ());
+ }
+ END_CATCH
}
- xfree (inf_status);
-}
-
-static void
-do_restore_infcall_control_state_cleanup (void *sts)
-{
- restore_infcall_control_state ((struct infcall_control_state *) sts);
-}
-
-struct cleanup *
-make_cleanup_restore_infcall_control_state
- (struct infcall_control_state *inf_status)
-{
- return make_cleanup (do_restore_infcall_control_state_cleanup, inf_status);
+ delete inf_status;
}
void
/* See save_infcall_control_state for info on stop_bpstat. */
bpstat_clear (&inf_status->thread_control.stop_bpstat);
- xfree (inf_status);
+ delete inf_status;
}
\f
-/* restore_inferior_ptid() will be used by the cleanup machinery
- to restore the inferior_ptid value saved in a call to
- save_inferior_ptid(). */
-
-static void
-restore_inferior_ptid (void *arg)
-{
- ptid_t *saved_ptid_ptr = (ptid_t *) arg;
-
- inferior_ptid = *saved_ptid_ptr;
- xfree (arg);
-}
-
-/* Save the value of inferior_ptid so that it may be restored by a
- later call to do_cleanups(). Returns the struct cleanup pointer
- needed for later doing the cleanup. */
-
-struct cleanup *
-save_inferior_ptid (void)
-{
- ptid_t *saved_ptid_ptr = XNEW (ptid_t);
-
- *saved_ptid_ptr = inferior_ptid;
- return make_cleanup (restore_inferior_ptid, saved_ptid_ptr);
-}
-
/* See infrun.h. */
void
};
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)
infrun_async_inferior_event_token
= create_async_event_handler (infrun_async_inferior_event_handler, NULL);
- add_info ("signals", signals_info, _("\
+ add_info ("signals", info_signals_command, _("\
What debugger does when program gets various signals.\n\
Specify a signal as argument to print info on that signal only."));
add_info_alias ("handle", "signals", 0);
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