/* Target-struct-independent code to start (run) and stop an inferior
process.
- Copyright (C) 1986-2018 Free Software Foundation, Inc.
+ Copyright (C) 1986-2019 Free Software Foundation, Inc.
This file is part of GDB.
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
follow_exec (ptid_t ptid, char *exec_file_target)
{
- struct thread_info *th, *tmp;
struct inferior *inf = current_inferior ();
int pid = ptid.pid ();
ptid_t process_ptid;
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)
+ for (thread_info *th : all_threads_safe ())
if (th->ptid.pid () == pid && th->ptid != ptid)
delete_thread (th);
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;
/* 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. */
+ /* 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 = add_inferior_with_spaces ();
inf->pid = pid;
target_follow_exec (inf, exec_file_target);
set_current_inferior (inf);
set_current_program_space (inf->pspace);
+ add_thread (ptid);
}
else
{
registers. */
target_find_description ();
- /* The add_thread call ends up reading registers, so do it after updating the
- target description. */
- if (follow_exec_mode_string == follow_exec_mode_new)
- add_thread (ptid);
-
solib_create_inferior_hook (0);
jit_inferior_created_hook ();
/* 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. */
inferior *inf;
/* The list of states of processes involved in displaced stepping
presently. */
-static struct displaced_step_inferior_state *displaced_step_inferior_states;
+static std::forward_list<displaced_step_inferior_state *>
+ displaced_step_inferior_states;
/* Get the displaced stepping state of process PID. */
-static struct displaced_step_inferior_state *
+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->inf == inf)
- return state;
+ for (auto *state : displaced_step_inferior_states)
+ {
+ if (state->inf == inf)
+ return state;
+ }
- return NULL;
+ return nullptr;
}
/* 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 (state->step_thread != nullptr)
- return 1;
+ for (auto *state : displaced_step_inferior_states)
+ {
+ if (state->step_thread != nullptr)
+ return true;
+ }
- return 0;
+ return false;
}
/* Return true if thread represented by PTID is doing a 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 *
+static displaced_step_inferior_state *
add_displaced_stepping_state (inferior *inf)
{
- struct displaced_step_inferior_state *state;
+ displaced_step_inferior_state *state
+ = get_displaced_stepping_state (inf);
- for (state = displaced_step_inferior_states;
- state != NULL;
- state = state->next)
- if (state->inf == inf)
- return state;
+ if (state != nullptr)
+ return state;
state = XCNEW (struct displaced_step_inferior_state);
state->inf = inf;
- state->next = displaced_step_inferior_states;
- displaced_step_inferior_states = state;
+
+ displaced_step_inferior_states.push_front (state);
return state;
}
static void
remove_displaced_stepping_state (inferior *inf)
{
- struct displaced_step_inferior_state *it, **prev_next_p;
-
gdb_assert (inf != nullptr);
- it = displaced_step_inferior_states;
- prev_next_p = &displaced_step_inferior_states;
- while (it)
- {
- if (it->inf == inf)
- {
- *prev_next_p = it->next;
- xfree (it);
- return;
- }
-
- prev_next_p = &it->next;
- it = *prev_next_p;
- }
+ displaced_step_inferior_states.remove_if
+ ([inf] (displaced_step_inferior_state *state)
+ {
+ if (state->inf == inf)
+ {
+ xfree (state);
+ return true;
+ }
+ else
+ return false;
+ });
}
static void
static void
infrun_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid)
{
- struct displaced_step_inferior_state *displaced;
-
if (inferior_ptid == old_ptid)
inferior_ptid = new_ptid;
}
(GDB_SIGNAL_0 for none). This is a wrapper around 'resume_1' that
rolls back state on error. */
-void
+static void
resume (gdb_signal sig)
{
TRY
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 (!tp->ptid.matches (resume_ptid))
- continue;
- clear_proceed_status_thread (tp);
- }
+ for (thread_info *tp : all_non_exited_threads (resume_ptid))
+ clear_proceed_status_thread (tp);
}
if (inferior_ptid != null_ptid)
/* 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;
ptid_t resume_ptid;
struct execution_control_state ecss;
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 == tp->suspend.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
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)
/* 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 (!tp->ptid.matches (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);
{
scoped_restore save_defer_tc = make_scoped_defer_target_commit_resume ();
{
/* 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)
+ for (thread_info *tp : all_non_exited_threads (resume_ptid))
{
- /* Ignore threads of processes we're not resuming. */
- if (!tp->ptid.matches (resume_ptid))
- continue;
-
if (tp->resumed)
{
if (debug_infrun)
error (_("Command aborted."));
}
}
- else if (!tp->resumed && !thread_is_in_step_over_chain (tp))
+ 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, tp);
- switch_to_thread (tp);
+ reset_ecs (ecs, cur_thr);
+ switch_to_thread (cur_thr);
keep_going_pass_signal (ecs);
if (!ecs->wait_some_more)
error (_("Command aborted."));
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
infrun_thread_stop_requested (ptid_t ptid)
{
- struct thread_info *tp;
-
/* 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. */
- ALL_NON_EXITED_THREADS (tp)
- if (tp->ptid.matches (ptid))
- {
- if (tp->state != THREAD_RUNNING)
- continue;
- if (tp->executing)
- continue;
+ for (thread_info *tp : all_threads (ptid))
+ {
+ if (tp->state != THREAD_RUNNING)
+ continue;
+ if (tp->executing)
+ continue;
- /* 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 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)
- {
- tp->suspend.waitstatus_pending_p = 1;
- tp->suspend.waitstatus.kind = TARGET_WAITKIND_STOPPED;
- tp->suspend.waitstatus.value.sig = GDB_SIGNAL_0;
- }
+ /* 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);
- /* Clear the inline-frame state, since we're re-processing the
- stop. */
- clear_inline_frame_state (tp->ptid);
+ /* 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)
+ {
+ tp->suspend.waitstatus_pending_p = 1;
+ tp->suspend.waitstatus.kind = TARGET_WAITKIND_STOPPED;
+ tp->suspend.waitstatus.value.sig = GDB_SIGNAL_0;
+ }
- /* 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;
+ /* Clear the inline-frame state, since we're re-processing the
+ stop. */
+ clear_inline_frame_state (tp->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;
- }
+ /* 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;
+
+ /* 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
}
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);
}
}
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 (event_tp->ptid.matches (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 (event_tp->ptid.matches (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
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;
{
/* 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 (ecs->event_thread->suspend.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);
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)
{
}
else
{
- 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);
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;
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)
{
if (debug_infrun)
{
struct regcache *regcache = get_thread_regcache (ecs->event_thread);
- struct gdbarch *gdbarch = regcache->arch ();
+ 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,
+ paddress (reg_gdbarch,
ecs->event_thread->suspend.stop_pc));
if (target_stopped_by_watchpoint ())
{
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");
{
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. */
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 (inferior_ptid != null_ptid)
{
/* Take a strong reference so that the thread can't be deleted
yet. */
- sc->thread = inferior_thread ();
- sc->thread->incref ();
+ 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->decref ();
- 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 (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. */
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;
TRY
{
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
handle_command (const char *args, int from_tty)
{
int digits, wordlen;
- int sigfirst, signum, siglast;
+ int sigfirst, siglast;
enum gdb_signal oursig;
int allsigs;
int nsigs;
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
/* 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)
{
}
}
- for (signum = 0; signum < nsigs; signum++)
+ for (int signum = 0; signum < nsigs; signum++)
if (sigs[signum])
{
signal_cache_update (-1);
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: */
- readonly_detached_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 = regcache->arch ();
- 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);
+ infcall_suspend_state_up inf_state
+ (new struct infcall_suspend_state (gdbarch, tp, regcache));
- if (target_read (current_top_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;
- }
-
- 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->registers = new readonly_detached_regcache (*regcache);
-
return inf_state;
}
struct regcache *regcache = get_current_regcache ();
struct gdbarch *gdbarch = regcache->arch ();
- tp->suspend = inf_state->thread_suspend;
-
- if (inf_state->siginfo_gdbarch == gdbarch)
- {
- struct type *type = gdbarch_get_siginfo_type (gdbarch);
-
- /* Errors ignored. */
- target_write (current_top_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->restore (inf_state->registers);
-
+ 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)
{
- delete inf_state->registers;
- xfree (inf_state->siginfo_data);
- xfree (inf_state);
+ delete inf_state;
}
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 ();
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
/* See infrun.h. */