#include "progspace-and-thread.h"
#include "common/gdb_optional.h"
#include "arch-utils.h"
+#include "common/scope-exit.h"
/* Prototypes for local functions */
/* Tables of how to react to signals; the user sets them. */
-static unsigned char *signal_stop;
-static unsigned char *signal_print;
-static unsigned char *signal_program;
+static unsigned char signal_stop[GDB_SIGNAL_LAST];
+static unsigned char signal_print[GDB_SIGNAL_LAST];
+static unsigned char signal_program[GDB_SIGNAL_LAST];
/* Table of signals that are registered with "catch signal". A
non-zero entry indicates that the signal is caught by some "catch
- signal" command. This has size GDB_SIGNAL_LAST, to accommodate all
- signals. */
-static unsigned char *signal_catch;
+ signal" command. */
+static unsigned char signal_catch[GDB_SIGNAL_LAST];
/* Table of signals that the target may silently handle.
This is automatically determined from the flags above,
and simply cached here. */
-static unsigned char *signal_pass;
+static unsigned char signal_pass[GDB_SIGNAL_LAST];
#define SET_SIGS(nsigs,sigs,flags) \
do { \
void
update_signals_program_target (void)
{
- target_program_signals ((int) GDB_SIGNAL_LAST, signal_program);
+ target_program_signals (signal_program);
}
/* Value to pass to target_resume() to cause all threads to resume. */
displaced_step_closure::~displaced_step_closure () = default;
-/* Per-inferior displaced stepping state. */
-struct displaced_step_inferior_state
-{
- /* The process this displaced step state refers to. */
- inferior *inf;
-
- /* 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 nullptr, 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. */
- thread_info *step_thread;
-
- /* The architecture the thread had when we stepped it. */
- struct gdbarch *step_gdbarch;
-
- /* 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 std::forward_list<displaced_step_inferior_state *>
- displaced_step_inferior_states;
-
/* Get the displaced stepping state of process PID. */
static displaced_step_inferior_state *
get_displaced_stepping_state (inferior *inf)
{
- for (auto *state : displaced_step_inferior_states)
- {
- if (state->inf == inf)
- return state;
- }
-
- return nullptr;
+ return &inf->displaced_step_state;
}
/* Returns true if any inferior has a thread doing a displaced
static bool
displaced_step_in_progress_any_inferior ()
{
- for (auto *state : displaced_step_inferior_states)
+ for (inferior *i : all_inferiors ())
{
- if (state->step_thread != nullptr)
+ if (i->displaced_step_state.step_thread != nullptr)
return true;
}
static int
displaced_step_in_progress_thread (thread_info *thread)
{
- struct displaced_step_inferior_state *displaced;
-
gdb_assert (thread != NULL);
- displaced = get_displaced_stepping_state (thread->inf);
-
- return (displaced != NULL && displaced->step_thread == thread);
+ 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 (inferior *inf)
{
- struct displaced_step_inferior_state *displaced;
-
- displaced = get_displaced_stepping_state (inf);
- if (displaced != NULL && displaced->step_thread != nullptr)
- 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 displaced_step_inferior_state *
-add_displaced_stepping_state (inferior *inf)
-{
- displaced_step_inferior_state *state
- = get_displaced_stepping_state (inf);
-
- if (state != nullptr)
- return state;
-
- state = XCNEW (struct displaced_step_inferior_state);
- state->inf = inf;
-
- displaced_step_inferior_states.push_front (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
+ displaced_step_inferior_state *displaced
= get_displaced_stepping_state (current_inferior ());
/* If checking the mode of displaced instruction in copy area. */
- if (displaced != NULL
- && displaced->step_thread != nullptr
+ 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 (inferior *inf)
-{
- gdb_assert (inf != nullptr);
-
- 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
infrun_inferior_exit (struct inferior *inf)
{
- remove_displaced_stepping_state (inf);
+ inf->displaced_step_state.reset ();
}
/* If ON, and the architecture supports it, GDB will use displaced
{
struct regcache *regcache = get_thread_regcache (tp);
struct gdbarch *gdbarch = regcache->arch ();
- struct displaced_step_inferior_state *displaced_state;
-
- displaced_state = get_displaced_stepping_state (tp->inf);
+ 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. */
static int
displaced_step_prepare_throw (thread_info *tp)
{
- struct cleanup *ignore_cleanups;
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 (tp->inf);
+ displaced_step_inferior_state *displaced
+ = get_displaced_stepping_state (tp->inf);
if (displaced->step_thread != nullptr)
{
}
/* 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 (ignore_cleanups);
return -1;
}
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);
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),
= 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 thread we displaced? */
if (displaced->step_thread != event_thread)
return 0;
valid. */
if (step_over_info_valid_p ()
|| displaced_step_in_progress (tp->inf))
- target_pass_signals (0, NULL);
+ target_pass_signals ({});
else
- target_pass_signals ((int) GDB_SIGNAL_LAST, signal_pass);
+ target_pass_signals (signal_pass);
target_resume (resume_ptid, step, sig);
for_each_just_stopped_thread (delete_single_step_breakpoints);
}
-/* A cleanup wrapper. */
-
-static void
-delete_just_stopped_threads_infrun_breakpoints_cleanup (void *arg)
-{
- delete_just_stopped_threads_infrun_breakpoints ();
-}
-
/* See infrun.h. */
void
/* Is any thread of this process displaced stepping? If not,
there's nothing else to do. */
- if (displaced == NULL || displaced->step_thread == nullptr)
+ if (displaced->step_thread == nullptr)
return;
if (debug_infrun)
void
wait_for_inferior (void)
{
- struct cleanup *old_cleanups;
-
if (debug_infrun)
fprintf_unfiltered
(gdb_stdlog, "infrun: wait_for_inferior ()\n");
- old_cleanups
- = make_cleanup (delete_just_stopped_threads_infrun_breakpoints_cleanup,
- NULL);
+ SCOPE_EXIT { delete_just_stopped_threads_infrun_breakpoints (); };
/* If an error happens while handling the event, propagate GDB's
knowledge of the executing state to the frontend/user running
/* No error, don't finish the state yet. */
finish_state.release ();
-
- do_cleanups (old_cleanups);
}
/* Cleanup that reinstalls the readline callback handler, if the
input. */
static void
-reinstall_readline_callback_handler_cleanup (void *arg)
+reinstall_readline_callback_handler_cleanup ()
{
struct ui *ui = current_ui;
{
struct execution_control_state ecss;
struct execution_control_state *ecs = &ecss;
- struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
int cmd_done = 0;
ptid_t waiton_ptid = minus_one_ptid;
scoped_restore save_ui = make_scoped_restore (¤t_ui, main_ui);
/* End up with readline processing input, if necessary. */
- make_cleanup (reinstall_readline_callback_handler_cleanup, NULL);
-
- /* We're handling a live event, so make sure we're doing live
- 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)
- {
- 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. */
- maybe_restore_thread.emplace ();
-
- 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 ();
-
- scoped_restore save_exec_dir
- = make_scoped_restore (&execution_direction, target_execution_direction ());
-
- ecs->ptid = do_target_wait (waiton_ptid, &ecs->ws,
- target_can_async_p () ? TARGET_WNOHANG : 0);
-
- if (debug_infrun)
- print_target_wait_results (waiton_ptid, ecs->ptid, &ecs->ws);
-
- /* If an error happens while handling the event, propagate GDB's
- knowledge of the executing state to the frontend/user running
- state. */
- 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. */
- struct cleanup *ts_old_chain = make_bpstat_clear_actions_cleanup ();
-
- make_cleanup (delete_just_stopped_threads_infrun_breakpoints_cleanup, NULL);
-
- /* Now figure out what to do with the result of the result. */
- handle_inferior_event (ecs);
+ {
+ SCOPE_EXIT { reinstall_readline_callback_handler_cleanup (); };
+
+ /* We're handling a live event, so make sure we're doing live
+ 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)
+ {
+ maybe_restore_traceframe.emplace ();
+ set_current_traceframe (-1);
+ }
- if (!ecs->wait_some_more)
- {
- struct inferior *inf = find_inferior_ptid (ecs->ptid);
- int should_stop = 1;
- struct thread_info *thr = ecs->event_thread;
+ 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. */
+ maybe_restore_thread.emplace ();
+
+ 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 ();
+
+ scoped_restore save_exec_dir
+ = make_scoped_restore (&execution_direction,
+ target_execution_direction ());
+
+ ecs->ptid = do_target_wait (waiton_ptid, &ecs->ws,
+ target_can_async_p () ? TARGET_WNOHANG : 0);
+
+ if (debug_infrun)
+ print_target_wait_results (waiton_ptid, ecs->ptid, &ecs->ws);
+
+ /* If an error happens while handling the event, propagate GDB's
+ knowledge of the executing state to the frontend/user running
+ state. */
+ 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 scoped_restore_current_thread above to apply
+ still for the thread which has thrown the exception. */
+ auto defer_bpstat_clear
+ = make_scope_exit (bpstat_clear_actions);
+ auto defer_delete_threads
+ = make_scope_exit (delete_just_stopped_threads_infrun_breakpoints);
+
+ /* Now figure out what to do with the result of the result. */
+ handle_inferior_event (ecs);
+
+ if (!ecs->wait_some_more)
+ {
+ struct inferior *inf = find_inferior_ptid (ecs->ptid);
+ int should_stop = 1;
+ struct thread_info *thr = ecs->event_thread;
- delete_just_stopped_threads_infrun_breakpoints ();
+ delete_just_stopped_threads_infrun_breakpoints ();
- if (thr != NULL)
- {
- struct thread_fsm *thread_fsm = thr->thread_fsm;
+ if (thr != NULL)
+ {
+ struct thread_fsm *thread_fsm = thr->thread_fsm;
- if (thread_fsm != NULL)
- should_stop = thread_fsm_should_stop (thread_fsm, thr);
- }
+ if (thread_fsm != NULL)
+ should_stop = thread_fsm_should_stop (thread_fsm, thr);
+ }
- if (!should_stop)
- {
- keep_going (ecs);
- }
- else
- {
- int should_notify_stop = 1;
- int proceeded = 0;
+ if (!should_stop)
+ {
+ keep_going (ecs);
+ }
+ else
+ {
+ int should_notify_stop = 1;
+ int proceeded = 0;
- clean_up_just_stopped_threads_fsms (ecs);
+ clean_up_just_stopped_threads_fsms (ecs);
- if (thr != NULL && thr->thread_fsm != NULL)
- {
- should_notify_stop
- = thread_fsm_should_notify_stop (thr->thread_fsm);
- }
+ if (thr != NULL && thr->thread_fsm != NULL)
+ {
+ should_notify_stop
+ = thread_fsm_should_notify_stop (thr->thread_fsm);
+ }
- if (should_notify_stop)
- {
- /* 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 (should_notify_stop)
+ {
+ /* 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;
+ }
+ }
+ }
- discard_cleanups (ts_old_chain);
+ defer_delete_threads.release ();
+ defer_bpstat_clear.release ();
- /* No error, don't finish the thread states yet. */
- finish_state.release ();
+ /* No error, don't finish the thread states yet. */
+ finish_state.release ();
- /* Revert thread and frame. */
- do_cleanups (old_chain);
+ /* This scope is used to ensure that readline callbacks are
+ reinstalled here. */
+ }
/* If a UI was in sync execution mode, and now isn't, restore its
prompt (a synchronous execution command has finished, and we're
}
}
-/* A cleanup that disables thread create/exit events. */
-
-static void
-disable_thread_events (void *arg)
-{
- target_thread_events (0);
-}
-
/* See infrun.h. */
void
/* We may need multiple passes to discover all threads. */
int pass;
int iterations = 0;
- struct cleanup *old_chain;
gdb_assert (target_is_non_stop_p ());
scoped_restore_current_thread restore_thread;
target_thread_events (1);
- old_chain = make_cleanup (disable_thread_events, NULL);
+ SCOPE_EXIT { target_thread_events (0); };
/* Request threads to stop, and then wait for the stops. Because
threads we already know about can spawn more threads while we're
}
}
- do_cleanups (old_chain);
-
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: stop_all_threads done\n");
}
for (i = 0; i < GDB_SIGNAL_LAST; ++i)
signal_catch[i] = info[i] > 0;
signal_cache_update (-1);
- target_pass_signals ((int) GDB_SIGNAL_LAST, signal_pass);
+ target_pass_signals (signal_pass);
}
static void
int sigfirst, siglast;
enum gdb_signal oursig;
int allsigs;
- int nsigs;
- unsigned char *sigs;
if (args == NULL)
{
/* Allocate and zero an array of flags for which signals to handle. */
- nsigs = (int) GDB_SIGNAL_LAST;
- sigs = (unsigned char *) alloca (nsigs);
- memset (sigs, 0, nsigs);
+ const size_t nsigs = GDB_SIGNAL_LAST;
+ unsigned char sigs[nsigs] {};
/* Break the command line up into args. */
if (sigs[signum])
{
signal_cache_update (-1);
- target_pass_signals ((int) GDB_SIGNAL_LAST, signal_pass);
- target_program_signals ((int) GDB_SIGNAL_LAST, signal_program);
+ target_pass_signals (signal_pass);
+ target_program_signals (signal_program);
if (from_tty)
{
void
_initialize_infrun (void)
{
- int i;
- int numsigs;
struct cmd_list_element *c;
/* Register extra event sources in the event loop. */
&setlist,
&showlist);
- numsigs = (int) GDB_SIGNAL_LAST;
- signal_stop = XNEWVEC (unsigned char, numsigs);
- signal_print = XNEWVEC (unsigned char, numsigs);
- signal_program = XNEWVEC (unsigned char, numsigs);
- signal_catch = XNEWVEC (unsigned char, numsigs);
- signal_pass = XNEWVEC (unsigned char, numsigs);
- for (i = 0; i < numsigs; i++)
+ for (size_t i = 0; i < GDB_SIGNAL_LAST; i++)
{
signal_stop[i] = 1;
signal_print[i] = 1;