X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Finfrun.c;h=7870f703e6c76041d0c831b28545f3a5536e1513;hb=8550d3b32f4ac17bdb9e4768bb905da181b77ded;hp=51540b33425b276ac880abfe0849f17d53bd7aa7;hpb=ecd75fc8eed3bde86036141228074a20e55dcfc9;p=deliverable%2Fbinutils-gdb.git
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 51540b3342..7870f703e6 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -1,7 +1,7 @@
/* Target-struct-independent code to start (run) and stop an inferior
process.
- Copyright (C) 1986-2014 Free Software Foundation, Inc.
+ Copyright (C) 1986-2015 Free Software Foundation, Inc.
This file is part of GDB.
@@ -19,12 +19,11 @@
along with this program. If not, see . */
#include "defs.h"
-#include
+#include "infrun.h"
#include
#include "symtab.h"
#include "frame.h"
#include "inferior.h"
-#include "exceptions.h"
#include "breakpoint.h"
#include "gdb_wait.h"
#include "gdbcore.h"
@@ -45,7 +44,6 @@
#include "main.h"
#include "dictionary.h"
#include "block.h"
-#include "gdb_assert.h"
#include "mi/mi-common.h"
#include "event-top.h"
#include "record.h"
@@ -61,6 +59,7 @@
#include "completer.h"
#include "target-descriptions.h"
#include "target-dcache.h"
+#include "terminal.h"
/* Prototypes for local functions */
@@ -80,28 +79,15 @@ 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);
-static int currently_stepping_or_nexting_callback (struct thread_info *tp,
- void *data);
-
-static void xdb_handle_command (char *args, int from_tty);
-
-static int prepare_to_proceed (int);
-
-static void print_exited_reason (int exitstatus);
-
-static void print_signal_exited_reason (enum gdb_signal siggnal);
-
-static void print_no_history_reason (void);
-
-static void print_signal_received_reason (enum gdb_signal siggnal);
-
-static void print_end_stepping_range_reason (void);
-
void _initialize_infrun (void);
void nullify_last_target_wait_ptid (void);
@@ -112,6 +98,8 @@ static void insert_step_resume_breakpoint_at_caller (struct frame_info *);
static void insert_longjmp_resume_breakpoint (struct gdbarch *, CORE_ADDR);
+static int maybe_software_singlestep (struct gdbarch *gdbarch, CORE_ADDR pc);
+
/* When set, stop the 'step' command if we enter a function which has
no line number information. The normal behavior is that we step
over such function. */
@@ -127,9 +115,9 @@ show_step_stop_if_no_debug (struct ui_file *file, int from_tty,
int sync_execution = 0;
-/* wait_for_inferior and normal_stop use this to notify the user
- when the inferior stopped in a different thread than it had been
- running in. */
+/* proceed and normal_stop use this to notify the user when the
+ inferior stopped in a different thread than it had been running
+ in. */
static ptid_t previous_inferior_ptid;
@@ -247,7 +235,6 @@ set_observer_mode (char *args, int from_tty,
going out we leave it that way. */
if (observer_mode)
{
- target_async_permitted = 1;
pagination_enabled = 0;
non_stop = non_stop_1 = 1;
}
@@ -339,10 +326,6 @@ update_signals_program_target (void)
static struct cmd_list_element *stop_command;
-/* Function inferior was in as of last step command. */
-
-static struct symbol *step_start_function;
-
/* Nonzero if we want to give control to the user when we're notified
of shared library events by the dynamic linker. */
int stop_on_solib_events;
@@ -390,8 +373,6 @@ static void context_switch (ptid_t ptid);
void init_thread_stepping_state (struct thread_info *tss);
-static void init_infwait_state (void);
-
static const char follow_fork_mode_child[] = "child";
static const char follow_fork_mode_parent[] = "parent";
@@ -413,6 +394,244 @@ show_follow_fork_mode_string (struct ui_file *file, int from_tty,
}
+/* Handle changes to the inferior list based on the type of fork,
+ which process is being followed, and whether the other process
+ should be detached. On entry inferior_ptid must be the ptid of
+ the fork parent. At return inferior_ptid is the ptid of the
+ followed inferior. */
+
+static int
+follow_fork_inferior (int follow_child, int detach_fork)
+{
+ int has_vforked;
+ ptid_t parent_ptid, child_ptid;
+
+ has_vforked = (inferior_thread ()->pending_follow.kind
+ == TARGET_WAITKIND_VFORKED);
+ parent_ptid = inferior_ptid;
+ child_ptid = inferior_thread ()->pending_follow.value.related_pid;
+
+ if (has_vforked
+ && !non_stop /* Non-stop always resumes both branches. */
+ && (!target_is_async_p () || sync_execution)
+ && !(follow_child || detach_fork || sched_multi))
+ {
+ /* The parent stays blocked inside the vfork syscall until the
+ child execs or exits. If we don't let the child run, then
+ the parent stays blocked. If we're telling the parent to run
+ in the foreground, the user will not be able to ctrl-c to get
+ back the terminal, effectively hanging the debug session. */
+ fprintf_filtered (gdb_stderr, _("\
+Can not resume the parent process over vfork in the foreground while\n\
+holding the child stopped. Try \"set detach-on-fork\" or \
+\"set schedule-multiple\".\n"));
+ /* FIXME output string > 80 columns. */
+ return 1;
+ }
+
+ if (!follow_child)
+ {
+ /* Detach new forked process? */
+ if (detach_fork)
+ {
+ struct cleanup *old_chain;
+
+ /* Before detaching from the child, remove all breakpoints
+ from it. If we forked, then this has already been taken
+ care of by infrun.c. If we vforked however, any
+ breakpoint inserted in the parent is visible in the
+ child, even those added while stopped in a vfork
+ catchpoint. This will remove the breakpoints from the
+ parent also, but they'll be reinserted below. */
+ if (has_vforked)
+ {
+ /* Keep breakpoints list in sync. */
+ remove_breakpoints_pid (ptid_get_pid (inferior_ptid));
+ }
+
+ if (info_verbose || debug_infrun)
+ {
+ target_terminal_ours_for_output ();
+ fprintf_filtered (gdb_stdlog,
+ _("Detaching after %s from child %s.\n"),
+ has_vforked ? "vfork" : "fork",
+ target_pid_to_str (child_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));
+
+ parent_inf = current_inferior ();
+ child_inf->attach_flag = parent_inf->attach_flag;
+ copy_terminal_info (child_inf, parent_inf);
+ child_inf->gdbarch = parent_inf->gdbarch;
+ copy_inferior_target_desc_info (child_inf, parent_inf);
+
+ old_chain = save_inferior_ptid ();
+ save_current_program_space ();
+
+ inferior_ptid = child_ptid;
+ add_thread (inferior_ptid);
+ child_inf->symfile_flags = SYMFILE_NO_READ;
+
+ /* If this is a vfork child, then the address-space is
+ shared with the parent. */
+ if (has_vforked)
+ {
+ child_inf->pspace = parent_inf->pspace;
+ child_inf->aspace = parent_inf->aspace;
+
+ /* The parent will be frozen until the child is done
+ with the shared region. Keep track of the
+ parent. */
+ child_inf->vfork_parent = parent_inf;
+ child_inf->pending_detach = 0;
+ parent_inf->vfork_child = child_inf;
+ parent_inf->pending_detach = 0;
+ }
+ else
+ {
+ child_inf->aspace = new_address_space ();
+ child_inf->pspace = add_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);
+
+ /* Let the shared library layer (e.g., solib-svr4) learn
+ about this new process, relocate the cloned exec, pull
+ in shared libraries, and install the solib event
+ breakpoint. If a "cloned-VM" event was propagated
+ better throughout the core, this wouldn't be
+ required. */
+ solib_create_inferior_hook (0);
+ }
+
+ do_cleanups (old_chain);
+ }
+
+ if (has_vforked)
+ {
+ struct inferior *parent_inf;
+
+ parent_inf = current_inferior ();
+
+ /* If we detached from the child, then we have to be careful
+ to not insert breakpoints in the parent until the child
+ is done with the shared memory region. However, if we're
+ staying attached to the child, then we can and should
+ insert breakpoints, so that we can debug it. A
+ subsequent child exec or exit is enough to know when does
+ the child stops using the parent's address space. */
+ parent_inf->waiting_for_vfork_done = detach_fork;
+ parent_inf->pspace->breakpoints_not_allowed = detach_fork;
+ }
+ }
+ else
+ {
+ /* Follow the child. */
+ struct inferior *parent_inf, *child_inf;
+ struct program_space *parent_pspace;
+
+ if (info_verbose || debug_infrun)
+ {
+ target_terminal_ours_for_output ();
+ fprintf_filtered (gdb_stdlog,
+ _("Attaching after %s %s to child %s.\n"),
+ target_pid_to_str (parent_ptid),
+ has_vforked ? "vfork" : "fork",
+ target_pid_to_str (child_ptid));
+ }
+
+ /* 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));
+
+ parent_inf = current_inferior ();
+ child_inf->attach_flag = parent_inf->attach_flag;
+ copy_terminal_info (child_inf, parent_inf);
+ child_inf->gdbarch = parent_inf->gdbarch;
+ copy_inferior_target_desc_info (child_inf, parent_inf);
+
+ parent_pspace = parent_inf->pspace;
+
+ /* If we're vforking, we want to hold on to the parent until the
+ child exits or execs. At child exec or exit time we can
+ remove the old breakpoints from the parent and detach or
+ resume debugging it. Otherwise, detach the parent now; we'll
+ want to reuse it's program/address spaces, but we can't set
+ them to the child before removing breakpoints from the
+ parent, otherwise, the breakpoints module could decide to
+ remove breakpoints from the wrong process (since they'd be
+ assigned to the same address space). */
+
+ if (has_vforked)
+ {
+ gdb_assert (child_inf->vfork_parent == NULL);
+ gdb_assert (parent_inf->vfork_child == NULL);
+ child_inf->vfork_parent = parent_inf;
+ child_inf->pending_detach = 0;
+ parent_inf->vfork_child = child_inf;
+ parent_inf->pending_detach = detach_fork;
+ parent_inf->waiting_for_vfork_done = 0;
+ }
+ else if (detach_fork)
+ {
+ if (info_verbose || debug_infrun)
+ {
+ target_terminal_ours_for_output ();
+ fprintf_filtered (gdb_stdlog,
+ _("Detaching after fork from "
+ "child %s.\n"),
+ target_pid_to_str (child_ptid));
+ }
+
+ target_detach (NULL, 0);
+ }
+
+ /* Note that the detach above makes PARENT_INF dangling. */
+
+ /* Add the child thread to the appropriate lists, and switch to
+ this new thread, before cloning the program space, and
+ informing the solib layer about this new process. */
+
+ inferior_ptid = child_ptid;
+ add_thread (inferior_ptid);
+
+ /* If this is a vfork child, then the address-space is shared
+ with the parent. If we detached from the parent, then we can
+ reuse the parent's program/address spaces. */
+ if (has_vforked || detach_fork)
+ {
+ child_inf->pspace = parent_pspace;
+ child_inf->aspace = child_inf->pspace->aspace;
+ }
+ else
+ {
+ child_inf->aspace = new_address_space ();
+ child_inf->pspace = add_program_space (child_inf->aspace);
+ child_inf->removable = 1;
+ child_inf->symfile_flags = SYMFILE_NO_READ;
+ set_current_program_space (child_inf->pspace);
+ clone_program_space (child_inf->pspace, parent_pspace);
+
+ /* Let the shared library layer (e.g., solib-svr4) learn
+ about this new process, relocate the cloned exec, pull in
+ shared libraries, and install the solib event breakpoint.
+ If a "cloned-VM" event was propagated better throughout
+ the core, this wouldn't be required. */
+ solib_create_inferior_hook (0);
+ }
+ }
+
+ return target_follow_fork (follow_child, detach_fork);
+}
+
/* Tell the target to follow the fork we're stopped at. Returns true
if the inferior should be resumed; false, if the target for some
reason decided it's best not to resume. */
@@ -433,6 +652,7 @@ follow_fork (void)
CORE_ADDR step_range_start = 0;
CORE_ADDR step_range_end = 0;
struct frame_id step_frame_id = { 0 };
+ struct interp *command_interp = NULL;
if (!non_stop)
{
@@ -484,6 +704,7 @@ follow_fork (void)
step_frame_id = tp->control.step_frame_id;
exception_resume_breakpoint
= clone_momentary_breakpoint (tp->control.exception_resume_breakpoint);
+ command_interp = tp->control.command_interp;
/* For now, delete the parent's sr breakpoint, otherwise,
parent/child sr breakpoints are considered duplicates,
@@ -495,14 +716,16 @@ follow_fork (void)
tp->control.step_range_end = 0;
tp->control.step_frame_id = null_frame_id;
delete_exception_resume_breakpoint (tp);
+ tp->control.command_interp = NULL;
}
parent = inferior_ptid;
child = tp->pending_follow.value.related_pid;
- /* Tell the target to do whatever is necessary to follow
- either parent or child. */
- if (target_follow_fork (follow_child, detach_fork))
+ /* Set up inferior(s) as specified by the caller, and tell the
+ target to do whatever is necessary to follow either parent
+ or child. */
+ if (follow_fork_inferior (follow_child, detach_fork))
{
/* Target refused to follow, or there's some other reason
we shouldn't resume. */
@@ -539,6 +762,7 @@ follow_fork (void)
tp->control.step_frame_id = step_frame_id;
tp->control.exception_resume_breakpoint
= exception_resume_breakpoint;
+ tp->control.command_interp = command_interp;
}
else
{
@@ -573,14 +797,16 @@ follow_fork (void)
return should_resume;
}
-void
+static void
follow_inferior_reset_breakpoints (void)
{
struct thread_info *tp = inferior_thread ();
/* Was there a step_resume breakpoint? (There was if the user
did a "next" at the fork() call.) If so, explicitly reset its
- thread number.
+ thread number. Cloned step_resume breakpoints are disabled on
+ creation, so enable it here now that it is associated with the
+ correct thread.
step_resumes are a form of bp that are made to be per-thread.
Since we created the step_resume bp when the parent process
@@ -590,10 +816,17 @@ follow_inferior_reset_breakpoints (void)
it is for, or it'll be ignored when it triggers. */
if (tp->control.step_resume_breakpoint)
- breakpoint_re_set_thread (tp->control.step_resume_breakpoint);
+ {
+ breakpoint_re_set_thread (tp->control.step_resume_breakpoint);
+ tp->control.step_resume_breakpoint->loc->enabled = 1;
+ }
+ /* Treat exception_resume breakpoints like step_resume breakpoints. */
if (tp->control.exception_resume_breakpoint)
- breakpoint_re_set_thread (tp->control.exception_resume_breakpoint);
+ {
+ breakpoint_re_set_thread (tp->control.exception_resume_breakpoint);
+ tp->control.exception_resume_breakpoint->loc->enabled = 1;
+ }
/* Reinsert all breakpoints in the child. The user may have set
breakpoints after catching the fork, in which case those
@@ -625,8 +858,8 @@ proceed_after_vfork_done (struct thread_info *thread,
target_pid_to_str (thread->ptid));
switch_to_thread (thread->ptid);
- clear_proceed_status ();
- proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT, 0);
+ clear_proceed_status (0);
+ proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT);
}
return 0;
@@ -693,18 +926,22 @@ handle_vfork_child_exec_or_exit (int exec)
if (debug_infrun || info_verbose)
{
- target_terminal_ours ();
+ target_terminal_ours_for_output ();
if (exec)
- fprintf_filtered (gdb_stdlog,
- "Detaching vfork parent process "
- "%d after child exec.\n",
- inf->vfork_parent->pid);
+ {
+ fprintf_filtered (gdb_stdlog,
+ _("Detaching vfork parent process "
+ "%d after child exec.\n"),
+ inf->vfork_parent->pid);
+ }
else
- fprintf_filtered (gdb_stdlog,
- "Detaching vfork parent process "
- "%d after child exit.\n",
- inf->vfork_parent->pid);
+ {
+ fprintf_filtered (gdb_stdlog,
+ _("Detaching vfork parent process "
+ "%d after child exit.\n"),
+ inf->vfork_parent->pid);
+ }
}
target_detach (NULL, 0);
@@ -814,10 +1051,11 @@ show_follow_exec_mode_string (struct ui_file *file, int from_tty,
/* EXECD_PATHNAME is assumed to be non-NULL. */
static void
-follow_exec (ptid_t pid, char *execd_pathname)
+follow_exec (ptid_t ptid, char *execd_pathname)
{
- struct thread_info *th = inferior_thread ();
+ struct thread_info *th, *tmp;
struct inferior *inf = current_inferior ();
+ int pid = ptid_get_pid (ptid);
/* This is an exec event that we actually wish to pay attention to.
Refresh our symbol table to the newly exec'd program, remove any
@@ -842,23 +1080,47 @@ follow_exec (ptid_t pid, char *execd_pathname)
mark_breakpoints_out ();
- update_breakpoints_after_exec ();
-
- /* If there was one, it's gone now. We cannot truly step-to-next
- statement through an exec(). */
+ /* The target reports the exec event to the main thread, even if
+ some other thread does the exec, and even if the main thread was
+ stopped or already gone. We may still have non-leader threads of
+ the process on our list. E.g., on targets that don't have thread
+ exit events (like remote); or on native Linux in non-stop mode if
+ there were only two threads in the inferior and the non-leader
+ one is the one that execs (and nothing forces an update of the
+ thread list up to here). When debugging remotely, it's best to
+ avoid extra traffic, when possible, so avoid syncing the thread
+ list with the target, and instead go ahead and delete all threads
+ of the process but one that reported the event. Note this must
+ be done before calling update_breakpoints_after_exec, as
+ otherwise clearing the threads' resources would reference stale
+ thread breakpoints -- it may have been one of these threads that
+ stepped across the exec. We could just clear their stepping
+ states, but as long as we're iterating, might as well delete
+ 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);
+
+ /* 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 ();
th->control.step_resume_breakpoint = NULL;
th->control.exception_resume_breakpoint = NULL;
+ th->control.single_step_breakpoints = NULL;
th->control.step_range_start = 0;
th->control.step_range_end = 0;
- /* The target reports the exec event to the main thread, even if
- some other thread does the exec, and even if the main thread was
- already stopped --- if debugging in non-stop mode, it's possible
- the user had the main thread held stopped in the previous image
- --- release it now. This is the same behavior as step-over-exec
- with scheduler-locking on in all-stop mode. */
+ /* The user may have had the main thread held stopped in the
+ previous image (e.g., schedlock on, or non-stop). Release
+ it now. */
th->stop_requested = 0;
+ update_breakpoints_after_exec ();
+
/* What is this a.out's name? */
printf_unfiltered (_("%s is executing new program: %s\n"),
target_pid_to_str (inferior_ptid),
@@ -961,30 +1223,100 @@ follow_exec (ptid_t pid, char *execd_pathname)
matically get reset there in the new process.). */
}
-/* Non-zero if we just simulating a single-step. This is needed
- because we cannot remove the breakpoints in the inferior process
- until after the `wait' in `wait_for_inferior'. */
-static int singlestep_breakpoints_inserted_p = 0;
+/* Info about an instruction that is being stepped over. */
+
+struct step_over_info
+{
+ /* If we're stepping past a breakpoint, this is the address space
+ 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;
+ CORE_ADDR address;
+
+ /* The instruction being stepped over triggers a nonsteppable
+ watchpoint. If true, we'll skip inserting watchpoints. */
+ int nonsteppable_watchpoint_p;
+};
+
+/* The step-over info of the location that is being stepped over.
+
+ Note that with async/breakpoint always-inserted mode, a user might
+ set a new breakpoint/watchpoint/etc. exactly while a breakpoint is
+ being stepped over. As setting a new breakpoint inserts all
+ breakpoints, we need to make sure the breakpoint being stepped over
+ isn't inserted then. We do that by only clearing the step-over
+ info when the step-over is actually finished (or aborted).
+
+ Presently GDB can only step over one breakpoint at any given time.
+ Given threads that can't run code in the same address space as the
+ breakpoint's can't really miss the breakpoint, GDB could be taught
+ to step-over at most one breakpoint per address space (so this info
+ could move to the address space object if/when GDB is extended).
+ The set of breakpoints being stepped over will normally be much
+ smaller than the set of all breakpoints, so a flag in the
+ breakpoint location structure would be wasteful. A separate list
+ also saves complexity and run-time, as otherwise we'd have to go
+ through all breakpoint locations clearing their flag whenever we
+ start a new sequence. Similar considerations weigh against storing
+ this info in the thread object. Plus, not all step overs actually
+ have breakpoint locations -- e.g., stepping past a single-step
+ breakpoint, or stepping to complete a non-continuable
+ watchpoint. */
+static struct step_over_info step_over_info;
+
+/* Record the address of the breakpoint/instruction we're currently
+ stepping over. */
+
+static void
+set_step_over_info (struct address_space *aspace, CORE_ADDR address,
+ int nonsteppable_watchpoint_p)
+{
+ step_over_info.aspace = aspace;
+ step_over_info.address = address;
+ step_over_info.nonsteppable_watchpoint_p = nonsteppable_watchpoint_p;
+}
+
+/* Called when we're not longer stepping over a breakpoint / an
+ instruction, so all breakpoints are free to be (re)inserted. */
+
+static void
+clear_step_over_info (void)
+{
+ step_over_info.aspace = NULL;
+ step_over_info.address = 0;
+ step_over_info.nonsteppable_watchpoint_p = 0;
+}
+
+/* See infrun.h. */
+
+int
+stepping_past_instruction_at (struct address_space *aspace,
+ CORE_ADDR address)
+{
+ return (step_over_info.aspace != NULL
+ && breakpoint_address_match (aspace, address,
+ step_over_info.aspace,
+ step_over_info.address));
+}
-/* The thread we inserted single-step breakpoints for. */
-static ptid_t singlestep_ptid;
+/* See infrun.h. */
-/* PC when we started this single-step. */
-static CORE_ADDR singlestep_pc;
+int
+stepping_past_nonsteppable_watchpoint (void)
+{
+ return step_over_info.nonsteppable_watchpoint_p;
+}
-/* If another thread hit the singlestep breakpoint, we save the original
- thread here so that we can resume single-stepping it later. */
-static ptid_t saved_singlestep_ptid;
-static int stepping_past_singlestep_breakpoint;
+/* Returns true if step-over info is valid. */
-/* If not equal to null_ptid, this means that after stepping over breakpoint
- is finished, we need to switch to deferred_step_ptid, and step it.
+static int
+step_over_info_valid_p (void)
+{
+ return (step_over_info.aspace != NULL
+ || stepping_past_nonsteppable_watchpoint ());
+}
- The use case is when one thread has hit a breakpoint, and then the user
- has switched to another thread and issued 'step'. We need to step over
- breakpoint in the thread which hit the breakpoint, but then continue
- stepping the thread user has selected. */
-static ptid_t deferred_step_ptid;
/* Displaced stepping. */
@@ -1133,6 +1465,20 @@ get_displaced_stepping_state (int pid)
return NULL;
}
+/* Return true if process PID has a thread doing a displaced step. */
+
+static int
+displaced_step_in_progress (int pid)
+{
+ 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. */
@@ -1240,7 +1586,7 @@ use_displaced_stepping (struct gdbarch *gdbarch)
return (((can_use_displaced_stepping == AUTO_BOOLEAN_AUTO && non_stop)
|| can_use_displaced_stepping == AUTO_BOOLEAN_TRUE)
&& gdbarch_displaced_step_copy_insn_p (gdbarch)
- && !RECORD_IS_USED);
+ && find_record_target () == NULL);
}
/* Clean out any stray displaced stepping state. */
@@ -1464,8 +1810,16 @@ displaced_step_fixup (ptid_t event_ptid, enum gdb_signal signal)
displaced_step_restore (displaced, displaced->step_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);
+
/* Did the instruction complete successfully? */
- if (signal == GDB_SIGNAL_TRAP)
+ if (signal == GDB_SIGNAL_TRAP
+ && !(target_stopped_by_watchpoint ()
+ && (gdbarch_have_nonsteppable_watchpoint (displaced->step_gdbarch)
+ || target_have_steppable_watchpoint)))
{
/* Fix up the resulting state. */
gdbarch_displaced_step_fixup (displaced->step_gdbarch,
@@ -1511,6 +1865,7 @@ displaced_step_fixup (ptid_t event_ptid, enum gdb_signal signal)
regcache = get_thread_regcache (ptid);
actual_pc = regcache_read_pc (regcache);
aspace = get_regcache_aspace (regcache);
+ gdbarch = get_regcache_arch (regcache);
if (breakpoint_here_p (aspace, actual_pc))
{
@@ -1521,8 +1876,6 @@ displaced_step_fixup (ptid_t event_ptid, enum gdb_signal signal)
displaced_step_prepare (ptid);
- gdbarch = get_regcache_arch (regcache);
-
if (debug_displaced)
{
CORE_ADDR actual_pc = regcache_read_pc (regcache);
@@ -1555,6 +1908,9 @@ displaced_step_fixup (ptid_t event_ptid, enum gdb_signal signal)
/* Go back to what we were trying to do. */
step = currently_stepping (tp);
+ if (step)
+ step = maybe_software_singlestep (gdbarch, actual_pc);
+
if (debug_displaced)
fprintf_unfiltered (gdb_stdlog,
"displaced: breakpoint is gone: %s, step(%d)\n",
@@ -1580,12 +1936,6 @@ infrun_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid)
if (ptid_equal (inferior_ptid, old_ptid))
inferior_ptid = new_ptid;
- if (ptid_equal (singlestep_ptid, old_ptid))
- singlestep_ptid = new_ptid;
-
- if (ptid_equal (deferred_step_ptid, old_ptid))
- deferred_step_ptid = new_ptid;
-
for (displaced = displaced_step_inferior_states;
displaced;
displaced = displaced->next)
@@ -1606,6 +1956,9 @@ infrun_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid)
static void
resume_cleanups (void *ignore)
{
+ if (!ptid_equal (inferior_ptid, null_ptid))
+ delete_single_step_breakpoints (inferior_thread ());
+
normal_stop ();
}
@@ -1660,37 +2013,17 @@ maybe_software_singlestep (struct gdbarch *gdbarch, CORE_ADDR pc)
&& gdbarch_software_single_step (gdbarch, get_current_frame ()))
{
hw_step = 0;
- /* Do not pull these breakpoints until after a `wait' in
- `wait_for_inferior'. */
- singlestep_breakpoints_inserted_p = 1;
- singlestep_ptid = inferior_ptid;
- singlestep_pc = pc;
}
return hw_step;
}
-/* Return a ptid representing the set of threads that we will proceed,
- in the perspective of the user/frontend. We may actually resume
- fewer threads at first, e.g., if a thread is stopped at a
- breakpoint that needs stepping-off, but that should not be visible
- to the user/frontend, and neither should the frontend/user be
- allowed to proceed any of the threads that happen to be stopped for
- internal run control handling, if a previous command wanted them
- resumed. */
+/* See infrun.h. */
ptid_t
user_visible_resume_ptid (int step)
{
- /* By default, resume all threads of all processes. */
- ptid_t resume_ptid = RESUME_ALL;
-
- /* Maybe resume only all threads of the current process. */
- if (!sched_multi && target_supports_multi_process ())
- {
- resume_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
- }
+ ptid_t resume_ptid;
- /* Maybe resume a single thread after all. */
if (non_stop)
{
/* With non-stop mode on, threads are always handled
@@ -1698,37 +2031,104 @@ user_visible_resume_ptid (int step)
resume_ptid = inferior_ptid;
}
else if ((scheduler_mode == schedlock_on)
- || (scheduler_mode == schedlock_step
- && (step || singlestep_breakpoints_inserted_p)))
+ || (scheduler_mode == schedlock_step && step))
{
- /* User-settable 'scheduler' mode requires solo thread resume. */
+ /* User-settable 'scheduler' mode requires solo thread
+ resume. */
resume_ptid = inferior_ptid;
}
+ else if (!sched_multi && target_supports_multi_process ())
+ {
+ /* Resume all threads of the current process (and none of other
+ processes). */
+ resume_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
+ }
+ else
+ {
+ /* Resume all threads of all processes. */
+ resume_ptid = RESUME_ALL;
+ }
return resume_ptid;
}
+/* Wrapper for target_resume, that handles infrun-specific
+ bookkeeping. */
+
+static void
+do_target_resume (ptid_t resume_ptid, int step, enum gdb_signal sig)
+{
+ struct thread_info *tp = inferior_thread ();
+
+ /* Install inferior's terminal modes. */
+ target_terminal_inferior ();
+
+ /* Avoid confusing the next resume, if the next stop/resume
+ happens to apply to another thread. */
+ tp->suspend.stop_signal = GDB_SIGNAL_0;
+
+ /* Advise target which signals may be handled silently.
+
+ If we have removed breakpoints because we are stepping over one
+ in-line (in any thread), we need to receive all signals to avoid
+ accidentally skipping a breakpoint during execution of a signal
+ handler.
+
+ Likewise if we're displaced stepping, otherwise a trap for a
+ breakpoint in a signal handler might be confused with the
+ displaced step finishing. We don't make the displaced_step_fixup
+ step distinguish the cases instead, because:
+
+ - a backtrace while stopped in the signal handler would show the
+ scratch pad as frame older than the signal handler, instead of
+ the real mainline code.
+
+ - when the thread is later resumed, the signal handler would
+ 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)))
+ target_pass_signals (0, NULL);
+ else
+ target_pass_signals ((int) GDB_SIGNAL_LAST, signal_pass);
+
+ target_resume (resume_ptid, step, sig);
+}
+
/* 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).
- STEP nonzero if we should step (zero to continue instead).
SIG is the signal to give the inferior (zero for none). */
void
-resume (int step, enum gdb_signal sig)
+resume (enum gdb_signal sig)
{
- int should_resume = 1;
struct cleanup *old_cleanups = make_cleanup (resume_cleanups, 0);
struct regcache *regcache = get_current_regcache ();
struct gdbarch *gdbarch = get_regcache_arch (regcache);
struct thread_info *tp = inferior_thread ();
CORE_ADDR pc = regcache_read_pc (regcache);
struct address_space *aspace = get_regcache_aspace (regcache);
+ ptid_t resume_ptid;
+ /* This represents the user's step vs continue request. When
+ deciding whether "set scheduler-locking step" applies, it's the
+ user's intention that counts. */
+ const int user_step = tp->control.stepping_command;
+ /* This represents what we'll actually request the target to do.
+ This can decay from a step to a continue, if e.g., we need to
+ implement single-stepping with breakpoints (software
+ single-step). */
+ int step;
+
+ tp->stepped_breakpoint = 0;
QUIT;
+ /* Depends on stepped_breakpoint. */
+ step = currently_stepping (tp);
+
if (current_inferior ()->waiting_for_vfork_done)
{
/* Don't try to single-step a vfork parent that is waiting for
@@ -1763,13 +2163,76 @@ resume (int step, enum gdb_signal sig)
breakpoints can't be removed. So we have to test for it here. */
if (breakpoint_here_p (aspace, pc) == permanent_breakpoint_here)
{
- if (gdbarch_skip_permanent_breakpoint_p (gdbarch))
- gdbarch_skip_permanent_breakpoint (gdbarch, regcache);
+ if (sig != GDB_SIGNAL_0)
+ {
+ /* We have a signal to pass to the inferior. The resume
+ may, or may not take us to the signal handler. If this
+ is a step, we'll need to stop in the signal handler, if
+ there's one, (if the target supports stepping into
+ handlers), or in the next mainline instruction, if
+ there's no handler. If this is a continue, we need to be
+ sure to run the handler with all breakpoints inserted.
+ In all cases, set a breakpoint at the current address
+ (where the handler returns to), and once that breakpoint
+ is hit, resume skipping the permanent breakpoint. If
+ that breakpoint isn't hit, then we've stepped into the
+ signal handler (or hit some other event). We'll delete
+ the step-resume breakpoint then. */
+
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: resume: skipping permanent breakpoint, "
+ "deliver signal first\n");
+
+ clear_step_over_info ();
+ tp->control.trap_expected = 0;
+
+ if (tp->control.step_resume_breakpoint == NULL)
+ {
+ /* Set a "high-priority" step-resume, as we don't want
+ user breakpoints at PC to trigger (again) when this
+ hits. */
+ insert_hp_step_resume_breakpoint_at_frame (get_current_frame ());
+ gdb_assert (tp->control.step_resume_breakpoint->loc->permanent);
+
+ tp->step_after_step_resume_breakpoint = step;
+ }
+
+ insert_breakpoints ();
+ }
else
- error (_("\
-The program is stopped at a permanent breakpoint, but GDB does not know\n\
-how to step past a permanent breakpoint on this architecture. Try using\n\
-a command like `return' or `jump' to continue execution."));
+ {
+ /* There's no signal to pass, we can go ahead and skip the
+ permanent breakpoint manually. */
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: resume: skipping permanent breakpoint\n");
+ gdbarch_skip_permanent_breakpoint (gdbarch, regcache);
+ /* Update pc to reflect the new address from which we will
+ execute instructions. */
+ pc = regcache_read_pc (regcache);
+
+ if (step)
+ {
+ /* We've already advanced the PC, so the stepping part
+ is done. Now we need to arrange for a trap to be
+ reported to handle_inferior_event. Set a breakpoint
+ at the current PC, and run to it. Don't update
+ prev_pc, because if we end in
+ switch_back_to_stepped_thread, we want the "expected
+ thread advanced also" branch to be taken. IOW, we
+ don't want this thread to step further from PC
+ (overstep). */
+ gdb_assert (!step_over_info_valid_p ());
+ insert_single_step_breakpoint (gdbarch, aspace, pc);
+ insert_breakpoints ();
+
+ resume_ptid = user_visible_resume_ptid (user_step);
+ do_target_resume (resume_ptid, 0, GDB_SIGNAL_0);
+ discard_cleanups (old_cleanups);
+ return;
+ }
+ }
}
/* If we have a breakpoint to step over, make sure to do a single
@@ -1789,8 +2252,8 @@ a command like `return' or `jump' to continue execution."));
event, displaced stepping breaks the vfork child similarly as single
step software breakpoint. */
if (use_displaced_stepping (gdbarch)
- && (tp->control.trap_expected
- || (step && gdbarch_software_single_step_p (gdbarch)))
+ && tp->control.trap_expected
+ && !step_over_info_valid_p ()
&& sig == GDB_SIGNAL_0
&& !current_inferior ()->waiting_for_vfork_done)
{
@@ -1800,11 +2263,14 @@ a command like `return' or `jump' to continue execution."));
{
/* Got placed in displaced stepping queue. Will be resumed
later when all the currently queued displaced stepping
- requests finish. The thread is not executing at this point,
- and the call to set_executing will be made later. But we
- need to call set_running here, since from frontend point of view,
- the thread is running. */
- set_running (inferior_ptid, 1);
+ requests finish. The thread is not executing at this
+ point, and the call to set_executing will be made later.
+ But we need to call set_running here, since from the
+ user/frontend's point of view, threads were set 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)
+ set_running (user_visible_resume_ptid (user_step), 1);
discard_cleanups (old_cleanups);
return;
}
@@ -1846,8 +2312,9 @@ a command like `return' or `jump' to continue execution."));
at the current address, deliver the signal without stepping, and
once we arrive back at the step-resume breakpoint, actually step
over the breakpoint we originally wanted to step over. */
- if (singlestep_breakpoints_inserted_p
- && tp->control.trap_expected && sig != GDB_SIGNAL_0)
+ if (thread_has_single_step_breakpoints_set (tp)
+ && sig != GDB_SIGNAL_0
+ && step_over_info_valid_p ())
{
/* If we have nested signals or a pending signal is delivered
immediately after a handler returns, might might already have
@@ -1860,116 +2327,103 @@ a command like `return' or `jump' to continue execution."));
tp->step_after_step_resume_breakpoint = 1;
}
- remove_single_step_breakpoints ();
- singlestep_breakpoints_inserted_p = 0;
+ delete_single_step_breakpoints (tp);
- insert_breakpoints ();
+ clear_step_over_info ();
tp->control.trap_expected = 0;
+
+ insert_breakpoints ();
}
- if (should_resume)
- {
- ptid_t resume_ptid;
+ /* If STEP is set, it's a request to use hardware stepping
+ facilities. But in that case, we should never
+ use singlestep breakpoint. */
+ gdb_assert (!(thread_has_single_step_breakpoints_set (tp) && step));
- /* If STEP is set, it's a request to use hardware stepping
- facilities. But in that case, we should never
- use singlestep breakpoint. */
- gdb_assert (!(singlestep_breakpoints_inserted_p && step));
+ /* Decide the set of threads to ask the target to resume. Start
+ by assuming everything will be resumed, than narrow the set
+ by applying increasingly restricting conditions. */
+ resume_ptid = user_visible_resume_ptid (user_step);
- /* Decide the set of threads to ask the target to resume. Start
- by assuming everything will be resumed, than narrow the set
- by applying increasingly restricting conditions. */
- resume_ptid = user_visible_resume_ptid (step);
+ /* Even if RESUME_PTID is a wildcard, and we end up resuming less
+ (e.g., we might need to step over a breakpoint), from the
+ user/frontend's point of view, all threads in RESUME_PTID are now
+ running. Unless we're calling an inferior function, as in that
+ case pretend we inferior doesn't run at all. */
+ if (!tp->control.in_infcall)
+ set_running (resume_ptid, 1);
- /* Maybe resume a single thread after all. */
- if (singlestep_breakpoints_inserted_p
- && stepping_past_singlestep_breakpoint)
- {
- /* The situation here is as follows. In thread T1 we wanted to
- single-step. Lacking hardware single-stepping we've
- set breakpoint at the PC of the next instruction -- call it
- P. After resuming, we've hit that breakpoint in thread T2.
- Now we've removed original breakpoint, inserted breakpoint
- at P+1, and try to step to advance T2 past breakpoint.
- We need to step only T2, as if T1 is allowed to freely run,
- it can run past P, and if other threads are allowed to run,
- they can hit breakpoint at P+1, and nested hits of single-step
- breakpoints is not something we'd want -- that's complicated
- to support, and has no value. */
- resume_ptid = inferior_ptid;
- }
- else if ((step || singlestep_breakpoints_inserted_p)
- && tp->control.trap_expected)
- {
- /* We're allowing a thread to run past a breakpoint it has
- hit, by single-stepping the thread with the breakpoint
- removed. In which case, we need to single-step only this
- thread, and keep others stopped, as they can miss this
- breakpoint if allowed to run.
-
- The current code actually removes all breakpoints when
- doing this, not just the one being stepped over, so if we
- let other threads run, we can actually miss any
- breakpoint, not just the one at PC. */
- resume_ptid = inferior_ptid;
- }
+ /* Maybe resume a single thread after all. */
+ if ((step || thread_has_single_step_breakpoints_set (tp))
+ && tp->control.trap_expected)
+ {
+ /* We're allowing a thread to run past a breakpoint it has
+ hit, by single-stepping the thread with the breakpoint
+ removed. In which case, we need to single-step only this
+ thread, and keep others stopped, as they can miss this
+ breakpoint if allowed to run. */
+ resume_ptid = inferior_ptid;
+ }
+ if (execution_direction != EXEC_REVERSE
+ && step && breakpoint_inserted_here_p (aspace, pc))
+ {
+ /* The only case we currently need to step a breakpoint
+ instruction is when we have a signal to deliver. See
+ handle_signal_stop where we handle random signals that could
+ take out us out of the stepping range. Normally, in that
+ case we end up continuing (instead of stepping) over the
+ signal handler with a breakpoint at PC, but there are cases
+ where we should _always_ single-step, even if we have a
+ step-resume breakpoint, like when a software watchpoint is
+ set. Assuming single-stepping and delivering a signal at the
+ same time would takes us to the signal handler, then we could
+ have removed the breakpoint at PC to step over it. However,
+ some hardware step targets (like e.g., Mac OS) can't step
+ into signal handlers, and for those, we need to leave the
+ breakpoint at PC inserted, as otherwise if the handler
+ recurses and executes PC again, it'll miss the breakpoint.
+ So we leave the breakpoint inserted anyway, but we need to
+ record that we tried to step a breakpoint instruction, so
+ that adjust_pc_after_break doesn't end up confused. */
+ gdb_assert (sig != GDB_SIGNAL_0);
+
+ tp->stepped_breakpoint = 1;
+
+ /* Most targets can step a breakpoint instruction, thus
+ executing it normally. But if this one cannot, just
+ continue and we will hit it anyway. */
if (gdbarch_cannot_step_breakpoint (gdbarch))
- {
- /* Most targets can step a breakpoint instruction, thus
- executing it normally. But if this one cannot, just
- continue and we will hit it anyway. */
- if (step && breakpoint_inserted_here_p (aspace, pc))
- step = 0;
- }
+ step = 0;
+ }
- if (debug_displaced
- && use_displaced_stepping (gdbarch)
- && tp->control.trap_expected)
- {
- struct regcache *resume_regcache = get_thread_regcache (resume_ptid);
- struct gdbarch *resume_gdbarch = get_regcache_arch (resume_regcache);
- CORE_ADDR actual_pc = regcache_read_pc (resume_regcache);
- gdb_byte buf[4];
-
- fprintf_unfiltered (gdb_stdlog, "displaced: run %s: ",
- paddress (resume_gdbarch, actual_pc));
- read_memory (actual_pc, buf, sizeof (buf));
- displaced_step_dump_bytes (gdb_stdlog, buf, sizeof (buf));
- }
-
- if (tp->control.may_range_step)
- {
- /* If we're resuming a thread with the PC out of the step
- range, then we're doing some nested/finer run control
- operation, like stepping the thread out of the dynamic
- linker or the displaced stepping scratch pad. We
- shouldn't have allowed a range step then. */
- gdb_assert (pc_in_thread_step_range (pc, tp));
- }
+ if (debug_displaced
+ && use_displaced_stepping (gdbarch)
+ && tp->control.trap_expected
+ && !step_over_info_valid_p ())
+ {
+ struct regcache *resume_regcache = get_thread_regcache (tp->ptid);
+ struct gdbarch *resume_gdbarch = get_regcache_arch (resume_regcache);
+ CORE_ADDR actual_pc = regcache_read_pc (resume_regcache);
+ gdb_byte buf[4];
- /* Install inferior's terminal modes. */
- target_terminal_inferior ();
-
- /* Avoid confusing the next resume, if the next stop/resume
- happens to apply to another thread. */
- tp->suspend.stop_signal = GDB_SIGNAL_0;
-
- /* Advise target which signals may be handled silently. If we have
- removed breakpoints because we are stepping over one (which can
- happen only if we are not using displaced stepping), we need to
- receive all signals to avoid accidentally skipping a breakpoint
- during execution of a signal handler. */
- if ((step || singlestep_breakpoints_inserted_p)
- && tp->control.trap_expected
- && !use_displaced_stepping (gdbarch))
- target_pass_signals (0, NULL);
- else
- target_pass_signals ((int) GDB_SIGNAL_LAST, signal_pass);
+ fprintf_unfiltered (gdb_stdlog, "displaced: run %s: ",
+ paddress (resume_gdbarch, actual_pc));
+ read_memory (actual_pc, buf, sizeof (buf));
+ displaced_step_dump_bytes (gdb_stdlog, buf, sizeof (buf));
+ }
- target_resume (resume_ptid, step, sig);
+ if (tp->control.may_range_step)
+ {
+ /* If we're resuming a thread with the PC out of the step
+ range, then we're doing some nested/finer run control
+ operation, like stepping the thread out of the dynamic
+ linker or the displaced stepping scratch pad. We
+ shouldn't have allowed a range step then. */
+ gdb_assert (pc_in_thread_step_range (pc, tp));
}
+ do_target_resume (resume_ptid, step, sig);
discard_cleanups (old_cleanups);
}
@@ -1986,6 +2440,11 @@ clear_proceed_status_thread (struct thread_info *tp)
"infrun: clear_proceed_status_thread (%s)\n",
target_pid_to_str (tp->ptid));
+ /* If this signal should not be seen by program, give it zero.
+ Used for debugging signals. */
+ if (!signal_pass_state (tp->suspend.stop_signal))
+ tp->suspend.stop_signal = GDB_SIGNAL_0;
+
tp->control.trap_expected = 0;
tp->control.step_range_start = 0;
tp->control.step_range_end = 0;
@@ -1993,36 +2452,38 @@ clear_proceed_status_thread (struct thread_info *tp)
tp->control.step_frame_id = null_frame_id;
tp->control.step_stack_frame_id = null_frame_id;
tp->control.step_over_calls = STEP_OVER_UNDEBUGGABLE;
+ tp->control.step_start_function = NULL;
tp->stop_requested = 0;
tp->control.stop_step = 0;
tp->control.proceed_to_finish = 0;
+ tp->control.command_interp = NULL;
+ tp->control.stepping_command = 0;
+
/* Discard any remaining commands or status from previous stop. */
bpstat_clear (&tp->control.stop_bpstat);
}
-static int
-clear_proceed_status_callback (struct thread_info *tp, void *data)
-{
- if (is_exited (tp->ptid))
- return 0;
-
- clear_proceed_status_thread (tp);
- return 0;
-}
-
void
-clear_proceed_status (void)
+clear_proceed_status (int step)
{
if (!non_stop)
{
- /* In all-stop mode, delete the per-thread status of all
- threads, even if inferior_ptid is null_ptid, there may be
- threads on the list. E.g., we may be launching a new
- process, while selecting the executable. */
- iterate_over_threads (clear_proceed_status_callback, NULL);
+ struct thread_info *tp;
+ ptid_t resume_ptid;
+
+ 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);
+ }
}
if (!ptid_equal (inferior_ptid, null_ptid))
@@ -2042,6 +2503,8 @@ clear_proceed_status (void)
stop_after_trap = 0;
+ clear_step_over_info ();
+
observer_notify_about_to_proceed ();
if (stop_registers)
@@ -2051,79 +2514,79 @@ clear_proceed_status (void)
}
}
-/* Check the current thread against the thread that reported the most recent
- event. If a step-over is required return TRUE and set the current thread
- to the old thread. Otherwise return FALSE.
+/* Returns true if TP is still stopped at a breakpoint that needs
+ stepping-over in order to make progress. If the breakpoint is gone
+ meanwhile, we can skip the whole step-over dance. */
+
+static int
+thread_still_needs_step_over (struct thread_info *tp)
+{
+ if (tp->stepping_over_breakpoint)
+ {
+ struct regcache *regcache = get_thread_regcache (tp->ptid);
+
+ if (breakpoint_here_p (get_regcache_aspace (regcache),
+ regcache_read_pc (regcache))
+ == ordinary_breakpoint_here)
+ return 1;
+
+ tp->stepping_over_breakpoint = 0;
+ }
+
+ return 0;
+}
- This should be suitable for any targets that support threads. */
+/* Returns true if scheduler locking applies. STEP indicates whether
+ we're about to do a step/next-like command to a thread. */
static int
-prepare_to_proceed (int step)
+schedlock_applies (struct thread_info *tp)
{
- ptid_t wait_ptid;
- struct target_waitstatus wait_status;
- int schedlock_enabled;
+ return (scheduler_mode == schedlock_on
+ || (scheduler_mode == schedlock_step
+ && tp->control.stepping_command));
+}
+
+/* Look a thread other than EXCEPT that has previously reported a
+ breakpoint event, and thus needs a step-over in order to make
+ progress. Returns NULL is none is found. */
+
+static struct thread_info *
+find_thread_needs_step_over (struct thread_info *except)
+{
+ struct thread_info *tp, *current;
/* With non-stop mode on, threads are always handled individually. */
gdb_assert (! non_stop);
- /* Get the last target status returned by target_wait(). */
- get_last_target_status (&wait_ptid, &wait_status);
+ current = inferior_thread ();
- /* Make sure we were stopped at a breakpoint. */
- if (wait_status.kind != TARGET_WAITKIND_STOPPED
- || (wait_status.value.sig != GDB_SIGNAL_TRAP
- && wait_status.value.sig != GDB_SIGNAL_ILL
- && wait_status.value.sig != GDB_SIGNAL_SEGV
- && wait_status.value.sig != GDB_SIGNAL_EMT))
+ /* If scheduler locking applies, we can avoid iterating over all
+ threads. */
+ if (schedlock_applies (except))
{
- return 0;
+ if (except != current
+ && thread_still_needs_step_over (current))
+ return current;
+
+ return NULL;
}
- schedlock_enabled = (scheduler_mode == schedlock_on
- || (scheduler_mode == schedlock_step
- && step));
+ ALL_NON_EXITED_THREADS (tp)
+ {
+ /* Ignore the EXCEPT thread. */
+ if (tp == except)
+ continue;
+ /* Ignore threads of processes we're not resuming. */
+ if (!sched_multi
+ && ptid_get_pid (tp->ptid) != ptid_get_pid (inferior_ptid))
+ continue;
- /* Don't switch over to WAIT_PTID if scheduler locking is on. */
- if (schedlock_enabled)
- return 0;
+ if (thread_still_needs_step_over (tp))
+ return tp;
+ }
- /* Don't switch over if we're about to resume some other process
- other than WAIT_PTID's, and schedule-multiple is off. */
- if (!sched_multi
- && ptid_get_pid (wait_ptid) != ptid_get_pid (inferior_ptid))
- return 0;
-
- /* Switched over from WAIT_PID. */
- if (!ptid_equal (wait_ptid, minus_one_ptid)
- && !ptid_equal (inferior_ptid, wait_ptid))
- {
- struct regcache *regcache = get_thread_regcache (wait_ptid);
-
- if (breakpoint_here_p (get_regcache_aspace (regcache),
- regcache_read_pc (regcache)))
- {
- /* If stepping, remember current thread to switch back to. */
- if (step)
- deferred_step_ptid = inferior_ptid;
-
- /* Switch back to WAIT_PID thread. */
- switch_to_thread (wait_ptid);
-
- if (debug_infrun)
- fprintf_unfiltered (gdb_stdlog,
- "infrun: prepare_to_proceed (step=%d), "
- "switched to [%s]\n",
- step, target_pid_to_str (inferior_ptid));
-
- /* We return 1 to indicate that there is a breakpoint here,
- so we need to step over it before continuing to avoid
- hitting it straight away. */
- return 1;
- }
- }
-
- return 0;
+ return NULL;
}
/* Basic routine for continuing the program in various fashions.
@@ -2139,15 +2602,13 @@ prepare_to_proceed (int step)
You should call clear_proceed_status before calling proceed. */
void
-proceed (CORE_ADDR addr, enum gdb_signal siggnal, int step)
+proceed (CORE_ADDR addr, enum gdb_signal siggnal)
{
struct regcache *regcache;
struct gdbarch *gdbarch;
struct thread_info *tp;
CORE_ADDR pc;
struct address_space *aspace;
- /* GDB may force the inferior to step due to various reasons. */
- int force_step = 0;
/* If we're stopped at a fork/vfork, follow the branch set by the
"set follow-fork-mode" command; otherwise, we'll just proceed
@@ -2168,15 +2629,15 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal, int step)
gdbarch = get_regcache_arch (regcache);
aspace = get_regcache_aspace (regcache);
pc = regcache_read_pc (regcache);
+ tp = inferior_thread ();
- if (step > 0)
- step_start_function = find_pc_function (pc);
- if (step < 0)
- stop_after_trap = 1;
+ /* Fill in with reasonable starting values. */
+ init_thread_stepping_state (tp);
if (addr == (CORE_ADDR) -1)
{
- if (pc == stop_pc && breakpoint_here_p (aspace, pc)
+ if (pc == 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,
step one instruction before inserting breakpoints so that
@@ -2186,25 +2647,35 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal, int step)
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. */
-
- force_step = 1;
+ tp->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. */
- force_step = 1;
+ tp->stepping_over_breakpoint = 1;
}
else
{
regcache_write_pc (regcache, addr);
}
+ if (siggnal != GDB_SIGNAL_DEFAULT)
+ tp->suspend.stop_signal = siggnal;
+
+ /* Record the interpreter that issued the execution command that
+ caused this thread to resume. If the top level interpreter is
+ MI/async, and the execution command was a CLI command
+ (next/step/etc.), we'll want to print stop event output to the MI
+ console channel (the stepped-to line, etc.), as if the user
+ entered the execution command on a real GDB console. */
+ inferior_thread ()->control.command_interp = command_interp ();
+
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog,
- "infrun: proceed (addr=%s, signal=%s, step=%d)\n",
+ "infrun: proceed (addr=%s, signal=%s)\n",
paddress (gdbarch, addr),
- gdb_signal_to_symbol_string (siggnal), step);
+ gdb_signal_to_symbol_string (siggnal));
if (non_stop)
/* In non-stop, each thread is handled individually. The context
@@ -2212,6 +2683,8 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal, int step)
;
else
{
+ struct thread_info *step_over;
+
/* In a multi-threaded task we may select another thread and
then continue or step.
@@ -2220,66 +2693,41 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal, int step)
execution (i.e. it will report a breakpoint hit incorrectly).
So we must step over it first.
- prepare_to_proceed checks the current thread against the
- thread that reported the most recent event. If a step-over
- is required it returns TRUE and sets the current thread to
- the old thread. */
- if (prepare_to_proceed (step))
- force_step = 1;
- }
-
- /* prepare_to_proceed may change the current thread. */
- tp = inferior_thread ();
-
- if (force_step)
- {
- tp->control.trap_expected = 1;
- /* If displaced stepping is enabled, we can step over the
- breakpoint without hitting it, so leave all breakpoints
- inserted. Otherwise we need to disable all breakpoints, step
- one instruction, and then re-add them when that step is
- finished. */
- if (!use_displaced_stepping (gdbarch))
- remove_breakpoints ();
+ Look for a thread other than the current (TP) that reported a
+ breakpoint hit and hasn't been resumed yet since. */
+ step_over = find_thread_needs_step_over (tp);
+ if (step_over != NULL)
+ {
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: need to step-over [%s] first\n",
+ target_pid_to_str (step_over->ptid));
+
+ /* Store the prev_pc for the stepping thread too, needed by
+ switch_back_to_stepped_thread. */
+ tp->prev_pc = regcache_read_pc (get_current_regcache ());
+ switch_to_thread (step_over->ptid);
+ tp = step_over;
+ }
}
- /* We can insert breakpoints if we're not trying to step over one,
- or if we are stepping over one but we're using displaced stepping
- to do so. */
- if (! tp->control.trap_expected || use_displaced_stepping (gdbarch))
- insert_breakpoints ();
-
- if (!non_stop)
+ /* If we need to step over a breakpoint, and we're not using
+ displaced stepping to do so, insert all breakpoints (watchpoints,
+ etc.) but the one we're stepping over, step one instruction, and
+ then re-insert the breakpoint when that step is finished. */
+ if (tp->stepping_over_breakpoint && !use_displaced_stepping (gdbarch))
{
- /* Pass the last stop signal to the thread we're resuming,
- irrespective of whether the current thread is the thread that
- got the last event or not. This was historically GDB's
- behaviour before keeping a stop_signal per thread. */
+ struct regcache *regcache = get_current_regcache ();
- struct thread_info *last_thread;
- ptid_t last_ptid;
- struct target_waitstatus last_status;
-
- get_last_target_status (&last_ptid, &last_status);
- if (!ptid_equal (inferior_ptid, last_ptid)
- && !ptid_equal (last_ptid, null_ptid)
- && !ptid_equal (last_ptid, minus_one_ptid))
- {
- last_thread = find_thread_ptid (last_ptid);
- if (last_thread)
- {
- tp->suspend.stop_signal = last_thread->suspend.stop_signal;
- last_thread->suspend.stop_signal = GDB_SIGNAL_0;
- }
- }
+ set_step_over_info (get_regcache_aspace (regcache),
+ regcache_read_pc (regcache), 0);
}
+ else
+ clear_step_over_info ();
- if (siggnal != GDB_SIGNAL_DEFAULT)
- tp->suspend.stop_signal = siggnal;
- /* If this signal should not be seen by program,
- give it zero. Used for debugging signals. */
- else if (!signal_program[tp->suspend.stop_signal])
- tp->suspend.stop_signal = GDB_SIGNAL_0;
+ insert_breakpoints ();
+
+ tp->control.trap_expected = tp->stepping_over_breakpoint;
annotate_starting ();
@@ -2288,7 +2736,7 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal, int step)
gdb_flush (gdb_stdout);
/* Refresh prev_pc value just prior to resuming. This used to be
- done in stop_stepping, however, setting prev_pc there did not handle
+ done in stop_waiting, however, setting prev_pc there did not handle
scenarios such as inferior function calls or returning from
a function via the return command. In those cases, the prev_pc
value was not set properly for subsequent commands. The prev_pc value
@@ -2312,15 +2760,8 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal, int step)
correctly when the inferior is stopped. */
tp->prev_pc = regcache_read_pc (get_current_regcache ());
- /* Fill in with reasonable starting values. */
- init_thread_stepping_state (tp);
-
- /* Reset to normal state. */
- init_infwait_state ();
-
/* Resume inferior. */
- resume (force_step || step || bpstat_should_step (),
- tp->suspend.stop_signal);
+ resume (tp->suspend.stop_signal);
/* Wait for it to stop (if not standalone)
and in any case decode why it stopped, and act accordingly. */
@@ -2377,39 +2818,17 @@ init_wait_for_inferior (void)
breakpoint_init_inferior (inf_starting);
- clear_proceed_status ();
-
- stepping_past_singlestep_breakpoint = 0;
- deferred_step_ptid = null_ptid;
+ clear_proceed_status (0);
target_last_wait_ptid = minus_one_ptid;
previous_inferior_ptid = inferior_ptid;
- init_infwait_state ();
/* Discard any skipped inlined frames. */
clear_inline_frame_state (minus_one_ptid);
}
-/* This enum encodes possible reasons for doing a target_wait, so that
- wfi can call target_wait in one place. (Ultimately the call will be
- moved out of the infinite loop entirely.) */
-
-enum infwait_states
-{
- infwait_normal_state,
- infwait_thread_hop_state,
- infwait_step_watch_state,
- infwait_nonstep_watch_state
-};
-
-/* The PTID we'll do a target_wait on.*/
-ptid_t waiton_ptid;
-
-/* Current inferior wait state. */
-static enum infwait_states infwait_state;
-
/* Data to be passed around while handling an event. This data is
discarded between events. */
struct execution_control_state
@@ -2426,10 +2845,11 @@ struct execution_control_state
const char *stop_func_name;
int wait_some_more;
- /* We were in infwait_step_watch_state or
- infwait_nonstep_watch_state state, and the thread reported an
- event. */
- int stepped_after_stopped_by_watchpoint;
+ /* True if the event thread hit the single-step breakpoint of
+ another thread. Thus the event doesn't cause a stop, the thread
+ needs to be single-stepped past the single-step breakpoint before
+ we can switch back to the original stepping thread. */
+ int hit_singlestep_breakpoint;
};
static void handle_inferior_event (struct execution_control_state *ecs);
@@ -2442,7 +2862,8 @@ static void handle_signal_stop (struct execution_control_state *ecs);
static void check_exception_resume (struct execution_control_state *,
struct frame_info *);
-static void stop_stepping (struct execution_control_state *ecs);
+static void end_stepping_range (struct execution_control_state *ecs);
+static void stop_waiting (struct execution_control_state *ecs);
static void prepare_to_wait (struct execution_control_state *ecs);
static void keep_going (struct execution_control_state *ecs);
static void process_event_stop_test (struct execution_control_state *ecs);
@@ -2558,54 +2979,71 @@ infrun_thread_thread_exit (struct thread_info *tp, int silent)
nullify_last_target_wait_ptid ();
}
-/* Callback for iterate_over_threads. */
+/* Delete the step resume, single-step and longjmp/exception resume
+ breakpoints of TP. */
-static int
-delete_step_resume_breakpoint_callback (struct thread_info *info, void *data)
+static void
+delete_thread_infrun_breakpoints (struct thread_info *tp)
{
- if (is_exited (info->ptid))
- return 0;
-
- delete_step_resume_breakpoint (info);
- delete_exception_resume_breakpoint (info);
- return 0;
+ delete_step_resume_breakpoint (tp);
+ delete_exception_resume_breakpoint (tp);
+ delete_single_step_breakpoints (tp);
}
-/* In all-stop, delete the step resume breakpoint of any thread that
- had one. In non-stop, delete the step resume breakpoint of the
- thread that just stopped. */
+/* If the target still has execution, call FUNC for each thread that
+ just stopped. In all-stop, that's all the non-exited threads; in
+ non-stop, that's the current thread, only. */
+
+typedef void (*for_each_just_stopped_thread_callback_func)
+ (struct thread_info *tp);
static void
-delete_step_thread_step_resume_breakpoint (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 the inferior has exited, we have already deleted the step
- resume breakpoints out of GDB's lists. */
+ if (!target_has_execution || ptid_equal (inferior_ptid, null_ptid))
return;
if (non_stop)
{
- /* If in non-stop mode, only delete the step-resume or
- longjmp-resume breakpoint of the thread that just stopped
- stepping. */
- struct thread_info *tp = inferior_thread ();
-
- delete_step_resume_breakpoint (tp);
- delete_exception_resume_breakpoint (tp);
+ /* If in non-stop mode, only the current thread stopped. */
+ func (inferior_thread ());
}
else
- /* In all-stop mode, delete all step-resume and longjmp-resume
- breakpoints of any thread that had them. */
- iterate_over_threads (delete_step_resume_breakpoint_callback, NULL);
+ {
+ struct thread_info *tp;
+
+ /* In all-stop mode, all threads have stopped. */
+ ALL_NON_EXITED_THREADS (tp)
+ {
+ func (tp);
+ }
+ }
+}
+
+/* Delete the step resume and longjmp/exception resume breakpoints of
+ the threads that just stopped. */
+
+static void
+delete_just_stopped_threads_infrun_breakpoints (void)
+{
+ for_each_just_stopped_thread (delete_thread_infrun_breakpoints);
+}
+
+/* Delete the single-step breakpoints of the threads that just
+ stopped. */
+
+static void
+delete_just_stopped_threads_single_step_breakpoints (void)
+{
+ for_each_just_stopped_thread (delete_single_step_breakpoints);
}
/* A cleanup wrapper. */
static void
-delete_step_thread_step_resume_breakpoint_cleanup (void *arg)
+delete_just_stopped_threads_infrun_breakpoints_cleanup (void *arg)
{
- delete_step_thread_step_resume_breakpoint ();
+ delete_just_stopped_threads_infrun_breakpoints ();
}
/* Pretty print the results of target_wait, for debugging purposes. */
@@ -2624,14 +3062,19 @@ print_target_wait_results (ptid_t waiton_ptid, ptid_t result_ptid,
is set. */
fprintf_unfiltered (tmp_stream,
- "infrun: target_wait (%d", ptid_get_pid (waiton_ptid));
+ "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 [%s],\n",
+ "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",
@@ -2735,19 +3178,26 @@ void
wait_for_inferior (void)
{
struct cleanup *old_cleanups;
+ struct cleanup *thread_state_chain;
if (debug_infrun)
fprintf_unfiltered
(gdb_stdlog, "infrun: wait_for_inferior ()\n");
- old_cleanups =
- make_cleanup (delete_step_thread_step_resume_breakpoint_cleanup, NULL);
+ old_cleanups
+ = make_cleanup (delete_just_stopped_threads_infrun_breakpoints_cleanup,
+ NULL);
+
+ /* 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);
while (1)
{
struct execution_control_state ecss;
struct execution_control_state *ecs = &ecss;
- struct cleanup *old_chain;
+ ptid_t waiton_ptid = minus_one_ptid;
memset (ecs, 0, sizeof (*ecs));
@@ -2767,24 +3217,46 @@ wait_for_inferior (void)
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. */
- old_chain = make_cleanup (finish_thread_state_cleanup, &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);
-
if (!ecs->wait_some_more)
break;
}
+ /* No error, don't finish the state yet. */
+ discard_cleanups (thread_state_chain);
+
do_cleanups (old_cleanups);
}
+/* Cleanup that reinstalls the readline callback handler, if the
+ target is running in the background. If while handling the target
+ event something triggered a secondary prompt, like e.g., a
+ pagination prompt, we'll have removed the callback handler (see
+ gdb_readline_wrapper_line). Need to do this as we go back to the
+ event loop, ready to process further input. Note this has no
+ effect if the handler hasn't actually been removed, because calling
+ rl_callback_handler_install resets the line buffer, thus losing
+ input. */
+
+static void
+reinstall_readline_callback_handler_cleanup (void *arg)
+{
+ if (!interpreter_async)
+ {
+ /* We're not going back to the top level event loop yet. Don't
+ install the readline callback, as it'd prep the terminal,
+ readline-style (raw, noecho) (e.g., --batch). We'll install
+ it the next time the prompt is displayed, when we're ready
+ for input. */
+ return;
+ }
+
+ if (async_command_editing_p && !sync_execution)
+ gdb_rl_callback_handler_reinstall ();
+}
+
/* Asynchronous version of wait_for_inferior. It is called by the
event loop whenever a change of state is detected on the file
descriptor corresponding to the target. It can be called more than
@@ -2803,9 +3275,13 @@ fetch_inferior_event (void *client_data)
struct cleanup *ts_old_chain;
int was_sync = sync_execution;
int cmd_done = 0;
+ ptid_t waiton_ptid = minus_one_ptid;
memset (ecs, 0, sizeof (*ecs));
+ /* 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
@@ -2854,14 +3330,16 @@ fetch_inferior_event (void *client_data)
still for the thread which has thrown the exception. */
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);
if (!ecs->wait_some_more)
{
- struct inferior *inf = find_inferior_pid (ptid_get_pid (ecs->ptid));
+ struct inferior *inf = find_inferior_ptid (ecs->ptid);
- delete_step_thread_step_resume_breakpoint ();
+ delete_just_stopped_threads_infrun_breakpoints ();
/* We may not find an inferior if this was a process exit. */
if (inf == NULL || inf->control.stop_soon == NO_STOP_QUIETLY)
@@ -2891,7 +3369,7 @@ fetch_inferior_event (void *client_data)
restore the prompt (a synchronous execution command has finished,
and we're ready for input). */
if (interpreter_async && was_sync && !sync_execution)
- display_gdb_prompt (0);
+ observer_notify_sync_execution_done ();
if (cmd_done
&& !was_sync
@@ -2919,10 +3397,21 @@ set_step_info (struct frame_info *frame, struct symtab_and_line sal)
void
init_thread_stepping_state (struct thread_info *tss)
{
+ tss->stepped_breakpoint = 0;
tss->stepping_over_breakpoint = 0;
+ tss->stepping_over_watchpoint = 0;
tss->step_after_step_resume_breakpoint = 0;
}
+/* Set the cached copy of the last ptid/waitstatus. */
+
+static void
+set_last_target_status (ptid_t ptid, struct target_waitstatus status)
+{
+ target_last_wait_ptid = ptid;
+ target_last_waitstatus = status;
+}
+
/* Return the cached copy of the last pid/waitstatus returned by
target_wait()/deprecated_target_wait_hook(). The data is actually
cached by handle_inferior_event(), which gets called immediately
@@ -2963,7 +3452,7 @@ adjust_pc_after_break (struct execution_control_state *ecs)
struct regcache *regcache;
struct gdbarch *gdbarch;
struct address_space *aspace;
- CORE_ADDR breakpoint_pc;
+ CORE_ADDR breakpoint_pc, decr_pc;
/* If we've hit a breakpoint, we'll normally be stopped with SIGTRAP. If
we aren't, just return.
@@ -3021,19 +3510,37 @@ adjust_pc_after_break (struct execution_control_state *ecs)
if (execution_direction == EXEC_REVERSE)
return;
+ /* If the target can tell whether the thread hit a SW breakpoint,
+ trust it. Targets that can tell also adjust the PC
+ themselves. */
+ if (target_supports_stopped_by_sw_breakpoint ())
+ return;
+
+ /* Note that relying on whether a breakpoint is planted in memory to
+ determine this can fail. E.g,. the breakpoint could have been
+ removed since. Or the thread could have been told to step an
+ instruction the size of a breakpoint instruction, and only
+ _after_ was a breakpoint inserted at its address. */
+
/* If this target does not decrement the PC after breakpoints, then
we have nothing to do. */
regcache = get_thread_regcache (ecs->ptid);
gdbarch = get_regcache_arch (regcache);
- if (gdbarch_decr_pc_after_break (gdbarch) == 0)
+
+ decr_pc = gdbarch_decr_pc_after_break (gdbarch);
+ if (decr_pc == 0)
return;
aspace = get_regcache_aspace (regcache);
/* Find the location where (if we've hit a breakpoint) the
breakpoint would be. */
- breakpoint_pc = regcache_read_pc (regcache)
- - gdbarch_decr_pc_after_break (gdbarch);
+ breakpoint_pc = regcache_read_pc (regcache) - decr_pc;
+
+ /* If the target can't tell whether a software breakpoint triggered,
+ fallback to figuring it out based on breakpoints we think were
+ inserted in the target, and on whether the thread was stepped or
+ continued. */
/* Check whether there actually is a software breakpoint inserted at
that location.
@@ -3042,13 +3549,16 @@ adjust_pc_after_break (struct execution_control_state *ecs)
removed a breakpoint, but stop events for that breakpoint were
already queued and arrive later. To suppress those spurious
SIGTRAPs, we keep a list of such breakpoint locations for a bit,
- and retire them after a number of stop events are reported. */
+ and retire them after a number of stop events are reported. Note
+ this is an heuristic and can thus get confused. The real fix is
+ to get the "stopped by SW BP and needs adjustment" info out of
+ the target/kernel (and thus never reach here; see above). */
if (software_breakpoint_inserted_here_p (aspace, breakpoint_pc)
|| (non_stop && moribund_breakpoint_here_p (aspace, breakpoint_pc)))
{
struct cleanup *old_cleanups = make_cleanup (null_cleanup, NULL);
- if (RECORD_IS_USED)
+ if (record_full_is_used ())
record_full_gdb_operation_disable_set ();
/* When using hardware single-step, a SIGTRAP is reported for both
@@ -3058,7 +3568,6 @@ adjust_pc_after_break (struct execution_control_state *ecs)
The SIGTRAP can be due to a completed hardware single-step only if
- we didn't insert software single-step breakpoints
- - the thread to be examined is still the current thread
- this thread is currently being stepped
If any of these events did not occur, we must have stopped due
@@ -3069,23 +3578,16 @@ adjust_pc_after_break (struct execution_control_state *ecs)
software breakpoint. In this case (prev_pc == breakpoint_pc),
we also need to back up to the breakpoint address. */
- if (singlestep_breakpoints_inserted_p
- || !ptid_equal (ecs->ptid, inferior_ptid)
+ if (thread_has_single_step_breakpoints_set (ecs->event_thread)
|| !currently_stepping (ecs->event_thread)
- || ecs->event_thread->prev_pc == breakpoint_pc)
+ || (ecs->event_thread->stepped_breakpoint
+ && ecs->event_thread->prev_pc == breakpoint_pc))
regcache_write_pc (regcache, breakpoint_pc);
do_cleanups (old_cleanups);
}
}
-static void
-init_infwait_state (void)
-{
- waiton_ptid = pid_to_ptid (-1);
- infwait_state = infwait_normal_state;
-}
-
static int
stepped_in_from (struct frame_info *frame, struct frame_id step_frame_id)
{
@@ -3158,6 +3660,10 @@ fill_in_stop_func (struct gdbarch *gdbarch,
ecs->stop_func_start
+= gdbarch_deprecated_function_start_offset (gdbarch);
+ if (gdbarch_skip_entrypoint_p (gdbarch))
+ ecs->stop_func_start = gdbarch_skip_entrypoint (gdbarch,
+ ecs->stop_func_start);
+
ecs->stop_func_filled_in = 1;
}
}
@@ -3168,7 +3674,7 @@ fill_in_stop_func (struct gdbarch *gdbarch,
static enum stop_kind
get_inferior_stop_soon (ptid_t ptid)
{
- struct inferior *inf = find_inferior_pid (ptid_get_pid (ptid));
+ struct inferior *inf = find_inferior_ptid (ptid);
gdb_assert (inf != NULL);
return inf->control.stop_soon;
@@ -3180,7 +3686,7 @@ get_inferior_stop_soon (ptid_t ptid)
The alternatives are:
- 1) stop_stepping and return; to really stop and return to the
+ 1) stop_waiting and return; to really stop and return to the
debugger.
2) keep_going and return; to wait for the next event (set
@@ -3225,8 +3731,7 @@ handle_inferior_event (struct execution_control_state *ecs)
}
/* Cache the last pid/waitstatus. */
- target_last_wait_ptid = ecs->ptid;
- target_last_waitstatus = ecs->ws;
+ set_last_target_status (ecs->ptid, ecs->ws);
/* Always clear state belonging to the previous time we stopped. */
stop_stack_dummy = STOP_NONE;
@@ -3239,7 +3744,7 @@ handle_inferior_event (struct execution_control_state *ecs)
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_NO_RESUMED\n");
stop_print_frame = 0;
- stop_stepping (ecs);
+ stop_waiting (ecs);
return;
}
@@ -3303,45 +3808,6 @@ handle_inferior_event (struct execution_control_state *ecs)
&& ecs->ws.kind != TARGET_WAITKIND_EXITED)
set_executing (ecs->ptid, 0);
- switch (infwait_state)
- {
- case infwait_thread_hop_state:
- if (debug_infrun)
- fprintf_unfiltered (gdb_stdlog, "infrun: infwait_thread_hop_state\n");
- break;
-
- case infwait_normal_state:
- if (debug_infrun)
- fprintf_unfiltered (gdb_stdlog, "infrun: infwait_normal_state\n");
- break;
-
- case infwait_step_watch_state:
- if (debug_infrun)
- fprintf_unfiltered (gdb_stdlog,
- "infrun: infwait_step_watch_state\n");
-
- ecs->stepped_after_stopped_by_watchpoint = 1;
- break;
-
- case infwait_nonstep_watch_state:
- if (debug_infrun)
- fprintf_unfiltered (gdb_stdlog,
- "infrun: infwait_nonstep_watch_state\n");
- insert_breakpoints ();
-
- /* FIXME-maybe: is this cleaner than setting a flag? Does it
- handle things like signals arriving and other things happening
- in combination correctly? */
- ecs->stepped_after_stopped_by_watchpoint = 1;
- break;
-
- default:
- internal_error (__FILE__, __LINE__, _("bad switch"));
- }
-
- infwait_state = infwait_normal_state;
- waiton_ptid = pid_to_ptid (-1);
-
switch (ecs->ws.kind)
{
case TARGET_WAITKIND_LOADED:
@@ -3387,7 +3853,7 @@ handle_inferior_event (struct execution_control_state *ecs)
normal_stop. */
stop_print_frame = 1;
- stop_stepping (ecs);
+ stop_waiting (ecs);
return;
}
}
@@ -3399,10 +3865,9 @@ handle_inferior_event (struct execution_control_state *ecs)
{
/* Loading of shared libraries might have changed breakpoint
addresses. Make sure new breakpoints are inserted. */
- if (stop_soon == NO_STOP_QUIETLY
- && !breakpoints_always_inserted_mode ())
+ if (stop_soon == NO_STOP_QUIETLY)
insert_breakpoints ();
- resume (0, GDB_SIGNAL_0);
+ resume (GDB_SIGNAL_0);
prepare_to_wait (ecs);
return;
}
@@ -3414,7 +3879,7 @@ handle_inferior_event (struct execution_control_state *ecs)
{
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: quietly stopped\n");
- stop_stepping (ecs);
+ stop_waiting (ecs);
return;
}
@@ -3426,7 +3891,7 @@ handle_inferior_event (struct execution_control_state *ecs)
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_SPURIOUS\n");
if (!ptid_equal (ecs->ptid, inferior_ptid))
context_switch (ecs->ptid);
- resume (0, GDB_SIGNAL_0);
+ resume (GDB_SIGNAL_0);
prepare_to_wait (ecs);
return;
@@ -3443,7 +3908,7 @@ handle_inferior_event (struct execution_control_state *ecs)
}
inferior_ptid = ecs->ptid;
- set_current_inferior (find_inferior_pid (ptid_get_pid (ecs->ptid)));
+ 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. */
@@ -3462,7 +3927,10 @@ handle_inferior_event (struct execution_control_state *ecs)
current_inferior ()->has_exit_code = 1;
current_inferior ()->exit_code = (LONGEST) ecs->ws.value.integer;
- print_exited_reason (ecs->ws.value.integer);
+ /* Support the --return-child-result option. */
+ return_child_result_value = ecs->ws.value.integer;
+
+ observer_notify_exited (ecs->ws.value.integer);
}
else
{
@@ -3491,15 +3959,13 @@ handle_inferior_event (struct execution_control_state *ecs)
Cannot fill $_exitsignal with the correct signal number.\n"));
}
- print_signal_exited_reason (ecs->ws.value.sig);
+ observer_notify_signal_exited (ecs->ws.value.sig);
}
gdb_flush (gdb_stdout);
target_mourn_inferior ();
- singlestep_breakpoints_inserted_p = 0;
- cancel_single_step_breakpoints ();
stop_print_frame = 0;
- stop_stepping (ecs);
+ stop_waiting (ecs);
return;
/* The following are the only cases in which we keep going;
@@ -3526,7 +3992,7 @@ Cannot fill $_exitsignal with the correct signal number.\n"));
if (displaced && ptid_equal (displaced->step_ptid, ecs->ptid))
{
struct inferior *parent_inf
- = find_inferior_pid (ptid_get_pid (ecs->ptid));
+ = find_inferior_ptid (ecs->ptid);
struct regcache *child_regcache;
CORE_ADDR parent_pc;
@@ -3590,12 +4056,7 @@ Cannot fill $_exitsignal with the correct signal number.\n"));
detach_breakpoints (ecs->ws.value.related_pid);
}
- if (singlestep_breakpoints_inserted_p)
- {
- /* Pull the single step breakpoints out of the target. */
- remove_single_step_breakpoints ();
- singlestep_breakpoints_inserted_p = 0;
- }
+ delete_just_stopped_threads_single_step_breakpoints ();
/* In case the event is caught by a catchpoint, remember that
the event is to be followed at the next resume of the thread,
@@ -3651,7 +4112,7 @@ Cannot fill $_exitsignal with the correct signal number.\n"));
if (should_resume)
keep_going (ecs);
else
- stop_stepping (ecs);
+ stop_waiting (ecs);
return;
}
process_event_stop_test (ecs);
@@ -3682,9 +4143,6 @@ Cannot fill $_exitsignal with the correct signal number.\n"));
if (!ptid_equal (ecs->ptid, inferior_ptid))
context_switch (ecs->ptid);
- singlestep_breakpoints_inserted_p = 0;
- cancel_single_step_breakpoints ();
-
stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid));
/* Do whatever is necessary to the parent branch of the vfork. */
@@ -3750,17 +4208,10 @@ Cannot fill $_exitsignal with the correct signal number.\n"));
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_NO_HISTORY\n");
/* Reverse execution: target ran out of history info. */
- /* Pull the single step breakpoints out of the target. */
- if (singlestep_breakpoints_inserted_p)
- {
- if (!ptid_equal (ecs->ptid, inferior_ptid))
- context_switch (ecs->ptid);
- remove_single_step_breakpoints ();
- singlestep_breakpoints_inserted_p = 0;
- }
+ delete_just_stopped_threads_single_step_breakpoints ();
stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid));
- print_no_history_reason ();
- stop_stepping (ecs);
+ observer_notify_no_history ();
+ stop_waiting (ecs);
return;
}
}
@@ -3776,22 +4227,20 @@ handle_signal_stop (struct execution_control_state *ecs)
enum stop_kind stop_soon;
int random_signal;
- if (ecs->ws.kind == TARGET_WAITKIND_STOPPED)
- {
- /* 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.) */
- displaced_step_fixup (ecs->ptid,
- ecs->event_thread->suspend.stop_signal);
+ gdb_assert (ecs->ws.kind == TARGET_WAITKIND_STOPPED);
- /* If we either finished a single-step or hit a breakpoint, but
- the user wanted this thread to be stopped, pretend we got a
- SIG0 (generic unsignaled stop). */
+ /* 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.) */
+ displaced_step_fixup (ecs->ptid,
+ ecs->event_thread->suspend.stop_signal);
- if (ecs->event_thread->stop_requested
- && ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP)
- ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_0;
- }
+ /* If we either finished a single-step or hit a breakpoint, but
+ the user wanted this thread to be stopped, pretend we got a
+ SIG0 (generic unsignaled stop). */
+ if (ecs->event_thread->stop_requested
+ && 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));
@@ -3833,7 +4282,7 @@ handle_signal_stop (struct execution_control_state *ecs)
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: quietly stopped\n");
stop_print_frame = 1;
- stop_stepping (ecs);
+ stop_waiting (ecs);
return;
}
@@ -3845,7 +4294,7 @@ handle_signal_stop (struct execution_control_state *ecs)
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: stopped\n");
stop_print_frame = 0;
- stop_stepping (ecs);
+ stop_waiting (ecs);
return;
}
@@ -3875,226 +4324,11 @@ handle_signal_stop (struct execution_control_state *ecs)
|| ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_0))
{
stop_print_frame = 1;
- stop_stepping (ecs);
+ stop_waiting (ecs);
ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_0;
return;
}
- if (stepping_past_singlestep_breakpoint)
- {
- gdb_assert (singlestep_breakpoints_inserted_p);
- gdb_assert (ptid_equal (singlestep_ptid, ecs->ptid));
- gdb_assert (!ptid_equal (singlestep_ptid, saved_singlestep_ptid));
-
- stepping_past_singlestep_breakpoint = 0;
-
- /* We've either finished single-stepping past the single-step
- breakpoint, or stopped for some other reason. It would be nice if
- we could tell, but we can't reliably. */
- if (ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP)
- {
- if (debug_infrun)
- fprintf_unfiltered (gdb_stdlog,
- "infrun: stepping_past_"
- "singlestep_breakpoint\n");
- /* Pull the single step breakpoints out of the target. */
- if (!ptid_equal (ecs->ptid, inferior_ptid))
- context_switch (ecs->ptid);
- remove_single_step_breakpoints ();
- singlestep_breakpoints_inserted_p = 0;
-
- ecs->event_thread->control.trap_expected = 0;
-
- context_switch (saved_singlestep_ptid);
- if (deprecated_context_hook)
- deprecated_context_hook (pid_to_thread_id (saved_singlestep_ptid));
-
- resume (1, GDB_SIGNAL_0);
- prepare_to_wait (ecs);
- return;
- }
- }
-
- if (!ptid_equal (deferred_step_ptid, null_ptid))
- {
- /* In non-stop mode, there's never a deferred_step_ptid set. */
- gdb_assert (!non_stop);
-
- /* If we stopped for some other reason than single-stepping, ignore
- the fact that we were supposed to switch back. */
- if (ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP)
- {
- if (debug_infrun)
- fprintf_unfiltered (gdb_stdlog,
- "infrun: handling deferred step\n");
-
- /* Pull the single step breakpoints out of the target. */
- if (singlestep_breakpoints_inserted_p)
- {
- if (!ptid_equal (ecs->ptid, inferior_ptid))
- context_switch (ecs->ptid);
- remove_single_step_breakpoints ();
- singlestep_breakpoints_inserted_p = 0;
- }
-
- ecs->event_thread->control.trap_expected = 0;
-
- context_switch (deferred_step_ptid);
- deferred_step_ptid = null_ptid;
- /* Suppress spurious "Switching to ..." message. */
- previous_inferior_ptid = inferior_ptid;
-
- resume (1, GDB_SIGNAL_0);
- prepare_to_wait (ecs);
- return;
- }
-
- deferred_step_ptid = null_ptid;
- }
-
- /* See if a thread hit a thread-specific breakpoint that was meant for
- another thread. If so, then step that thread past the breakpoint,
- and continue it. */
-
- if (ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP)
- {
- int thread_hop_needed = 0;
- struct address_space *aspace =
- get_regcache_aspace (get_thread_regcache (ecs->ptid));
-
- /* Check if a regular breakpoint has been hit before checking
- for a potential single step breakpoint. Otherwise, GDB will
- not see this breakpoint hit when stepping onto breakpoints. */
- if (regular_breakpoint_inserted_here_p (aspace, stop_pc))
- {
- if (!breakpoint_thread_match (aspace, stop_pc, ecs->ptid))
- thread_hop_needed = 1;
- }
- else if (singlestep_breakpoints_inserted_p)
- {
- /* We have not context switched yet, so this should be true
- no matter which thread hit the singlestep breakpoint. */
- gdb_assert (ptid_equal (inferior_ptid, singlestep_ptid));
- if (debug_infrun)
- fprintf_unfiltered (gdb_stdlog, "infrun: software single step "
- "trap for %s\n",
- target_pid_to_str (ecs->ptid));
-
- /* The call to in_thread_list is necessary because PTIDs sometimes
- change when we go from single-threaded to multi-threaded. If
- the singlestep_ptid is still in the list, assume that it is
- really different from ecs->ptid. */
- if (!ptid_equal (singlestep_ptid, ecs->ptid)
- && in_thread_list (singlestep_ptid))
- {
- /* If the PC of the thread we were trying to single-step
- has changed, discard this event (which we were going
- to ignore anyway), and pretend we saw that thread
- trap. This prevents us continuously moving the
- single-step breakpoint forward, one instruction at a
- time. If the PC has changed, then the thread we were
- trying to single-step has trapped or been signalled,
- but the event has not been reported to GDB yet.
-
- There might be some cases where this loses signal
- information, if a signal has arrived at exactly the
- same time that the PC changed, but this is the best
- we can do with the information available. Perhaps we
- should arrange to report all events for all threads
- when they stop, or to re-poll the remote looking for
- this particular thread (i.e. temporarily enable
- schedlock). */
-
- CORE_ADDR new_singlestep_pc
- = regcache_read_pc (get_thread_regcache (singlestep_ptid));
-
- if (new_singlestep_pc != singlestep_pc)
- {
- enum gdb_signal stop_signal;
-
- if (debug_infrun)
- fprintf_unfiltered (gdb_stdlog, "infrun: unexpected thread,"
- " but expected thread advanced also\n");
-
- /* The current context still belongs to
- singlestep_ptid. Don't swap here, since that's
- the context we want to use. Just fudge our
- state and continue. */
- stop_signal = ecs->event_thread->suspend.stop_signal;
- ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_0;
- ecs->ptid = singlestep_ptid;
- ecs->event_thread = find_thread_ptid (ecs->ptid);
- ecs->event_thread->suspend.stop_signal = stop_signal;
- stop_pc = new_singlestep_pc;
- }
- else
- {
- if (debug_infrun)
- fprintf_unfiltered (gdb_stdlog,
- "infrun: unexpected thread\n");
-
- thread_hop_needed = 1;
- stepping_past_singlestep_breakpoint = 1;
- saved_singlestep_ptid = singlestep_ptid;
- }
- }
- }
-
- if (thread_hop_needed)
- {
- struct regcache *thread_regcache;
- int remove_status = 0;
-
- if (debug_infrun)
- fprintf_unfiltered (gdb_stdlog, "infrun: thread_hop_needed\n");
-
- /* Switch context before touching inferior memory, the
- previous thread may have exited. */
- if (!ptid_equal (inferior_ptid, ecs->ptid))
- context_switch (ecs->ptid);
-
- /* Saw a breakpoint, but it was hit by the wrong thread.
- Just continue. */
-
- if (singlestep_breakpoints_inserted_p)
- {
- /* Pull the single step breakpoints out of the target. */
- remove_single_step_breakpoints ();
- singlestep_breakpoints_inserted_p = 0;
- }
-
- /* If the arch can displace step, don't remove the
- breakpoints. */
- thread_regcache = get_thread_regcache (ecs->ptid);
- if (!use_displaced_stepping (get_regcache_arch (thread_regcache)))
- remove_status = remove_breakpoints ();
-
- /* Did we fail to remove breakpoints? If so, try
- to set the PC past the bp. (There's at least
- one situation in which we can fail to remove
- the bp's: On HP-UX's that use ttrace, we can't
- change the address space of a vforking child
- process until the child exits (well, okay, not
- then either :-) or execs. */
- if (remove_status != 0)
- error (_("Cannot step over breakpoint hit in wrong thread"));
- else
- { /* Single step */
- if (!non_stop)
- {
- /* Only need to require the next event from this
- thread in all-stop mode. */
- waiton_ptid = ecs->ptid;
- infwait_state = infwait_thread_hop_state;
- }
-
- ecs->event_thread->stepping_over_breakpoint = 1;
- keep_going (ecs);
- return;
- }
- }
- }
-
/* See if something interesting happened to the non-current thread. If
so, then switch to that thread. */
if (!ptid_equal (ecs->ptid, inferior_ptid))
@@ -4112,14 +4346,51 @@ handle_signal_stop (struct execution_control_state *ecs)
frame = get_current_frame ();
gdbarch = get_frame_arch (frame);
- if (singlestep_breakpoints_inserted_p)
+ /* Pull the single step breakpoints out of the target. */
+ if (ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP)
{
- /* Pull the single step breakpoints out of the target. */
- remove_single_step_breakpoints ();
- singlestep_breakpoints_inserted_p = 0;
+ struct regcache *regcache;
+ struct address_space *aspace;
+ CORE_ADDR pc;
+
+ regcache = get_thread_regcache (ecs->ptid);
+ aspace = get_regcache_aspace (regcache);
+ pc = regcache_read_pc (regcache);
+
+ /* However, before doing so, if this single-step breakpoint was
+ actually for another thread, set this thread up for moving
+ past it. */
+ if (!thread_has_single_step_breakpoint_here (ecs->event_thread,
+ aspace, pc))
+ {
+ if (single_step_breakpoint_inserted_here_p (aspace, pc))
+ {
+ if (debug_infrun)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: [%s] hit another thread's "
+ "single-step breakpoint\n",
+ target_pid_to_str (ecs->ptid));
+ }
+ ecs->hit_singlestep_breakpoint = 1;
+ }
+ }
+ else
+ {
+ if (debug_infrun)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: [%s] hit its "
+ "single-step breakpoint\n",
+ target_pid_to_str (ecs->ptid));
+ }
+ }
}
+ delete_just_stopped_threads_single_step_breakpoints ();
- if (ecs->stepped_after_stopped_by_watchpoint)
+ if (ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP
+ && ecs->event_thread->control.trap_expected
+ && ecs->event_thread->stepping_over_watchpoint)
stopped_by_watchpoint = 0;
else
stopped_by_watchpoint = watchpoints_triggered (&ecs->ws);
@@ -4142,36 +4413,28 @@ handle_signal_stop (struct execution_control_state *ecs)
watchpoint expression. We do this by single-stepping the
target.
- It may not be necessary to disable the watchpoint to stop over
+ It may not be necessary to disable the watchpoint to step over
it. For example, the PA can (with some kernel cooperation)
single step over a watchpoint without disabling the watchpoint.
It is far more common to need to disable a watchpoint to step
the inferior over it. If we have non-steppable watchpoints,
we must disable the current watchpoint; it's simplest to
- disable all watchpoints and breakpoints. */
- int hw_step = 1;
-
- if (!target_have_steppable_watchpoint)
- {
- remove_breakpoints ();
- /* See comment in resume why we need to stop bypassing signals
- while breakpoints have been removed. */
- target_pass_signals (0, NULL);
- }
- /* Single step */
- hw_step = maybe_software_singlestep (gdbarch, stop_pc);
- target_resume (ecs->ptid, hw_step, GDB_SIGNAL_0);
- waiton_ptid = ecs->ptid;
- if (target_have_steppable_watchpoint)
- infwait_state = infwait_step_watch_state;
- else
- infwait_state = infwait_nonstep_watch_state;
- prepare_to_wait (ecs);
+ disable all watchpoints.
+
+ Any breakpoint at PC must also be stepped over -- if there's
+ one, it will have already triggered before the watchpoint
+ triggered, and we either already reported it to the user, or
+ it didn't cause a stop and we called keep_going. In either
+ case, if there was a breakpoint at PC, we must be trying to
+ step past it. */
+ ecs->event_thread->stepping_over_watchpoint = 1;
+ keep_going (ecs);
return;
}
ecs->event_thread->stepping_over_breakpoint = 0;
+ ecs->event_thread->stepping_over_watchpoint = 0;
bpstat_clear (&ecs->event_thread->control.stop_bpstat);
ecs->event_thread->control.stop_step = 0;
stop_print_frame = 1;
@@ -4304,11 +4567,65 @@ handle_signal_stop (struct execution_control_state *ecs)
= !bpstat_explains_signal (ecs->event_thread->control.stop_bpstat,
ecs->event_thread->suspend.stop_signal);
+ /* Maybe this was a trap for a software breakpoint that has since
+ been removed. */
+ if (random_signal && target_stopped_by_sw_breakpoint ())
+ {
+ if (program_breakpoint_here_p (gdbarch, 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);
+ decr_pc = gdbarch_decr_pc_after_break (gdbarch);
+ if (decr_pc != 0)
+ {
+ struct cleanup *old_cleanups = make_cleanup (null_cleanup, NULL);
+
+ if (record_full_is_used ())
+ record_full_gdb_operation_disable_set ();
+
+ regcache_write_pc (regcache, stop_pc + decr_pc);
+
+ do_cleanups (old_cleanups);
+ }
+ }
+ else
+ {
+ /* A delayed software breakpoint event. Ignore the trap. */
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: delayed software breakpoint "
+ "trap, ignoring\n");
+ random_signal = 0;
+ }
+ }
+
+ /* Maybe this was a trap for a hardware breakpoint/watchpoint that
+ has since been removed. */
+ if (random_signal && target_stopped_by_hw_breakpoint ())
+ {
+ /* A delayed hardware breakpoint event. Ignore the trap. */
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: delayed hardware breakpoint/watchpoint "
+ "trap, ignoring\n");
+ random_signal = 0;
+ }
+
/* If not, perhaps stepping/nexting can. */
if (random_signal)
random_signal = !(ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP
&& currently_stepping (ecs->event_thread));
+ /* Perhaps the thread hit a single-step breakpoint of _another_
+ thread. Single-step breakpoints are transparent to the
+ breakpoints module. */
+ if (random_signal)
+ random_signal = !ecs->hit_singlestep_breakpoint;
+
/* No? Perhaps we got a moribund watchpoint. */
if (random_signal)
random_signal = !stopped_by_watchpoint;
@@ -4319,8 +4636,7 @@ handle_signal_stop (struct execution_control_state *ecs)
if (random_signal)
{
/* Signal not for debugging purposes. */
- int printed = 0;
- struct inferior *inf = find_inferior_pid (ptid_get_pid (ecs->ptid));
+ struct inferior *inf = find_inferior_ptid (ecs->ptid);
enum gdb_signal stop_signal = ecs->event_thread->suspend.stop_signal;
if (debug_infrun)
@@ -4329,13 +4645,6 @@ handle_signal_stop (struct execution_control_state *ecs)
stopped_by_random_signal = 1;
- if (signal_print[ecs->event_thread->suspend.stop_signal])
- {
- printed = 1;
- target_terminal_ours_for_output ();
- print_signal_received_reason
- (ecs->event_thread->suspend.stop_signal);
- }
/* Always stop on signals if we're either just gaining control
of the program, or the user explicitly requested this thread
to remain stopped. */
@@ -4344,13 +4653,20 @@ handle_signal_stop (struct execution_control_state *ecs)
|| (!inf->detaching
&& signal_stop_state (ecs->event_thread->suspend.stop_signal)))
{
- stop_stepping (ecs);
+ stop_waiting (ecs);
return;
}
- /* If not going to stop, give terminal back
- if we took it away. */
- else if (printed)
- target_terminal_inferior ();
+
+ /* Notify observers the signal has "handle print" set. Note we
+ returned early above if stopping; normal_stop handles the
+ printing in that case. */
+ 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 ();
+ }
/* Clear the signal if it should not be passed. */
if (signal_program[ecs->event_thread->suspend.stop_signal] == 0)
@@ -4379,13 +4695,17 @@ handle_signal_stop (struct execution_control_state *ecs)
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;
- keep_going (ecs);
+
+ /* 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))
+ keep_going (ecs);
return;
}
- if (ecs->event_thread->control.step_range_end != 0
- && ecs->event_thread->suspend.stop_signal != GDB_SIGNAL_0
- && pc_in_thread_step_range (stop_pc, ecs->event_thread)
+ if (ecs->event_thread->suspend.stop_signal != GDB_SIGNAL_0
+ && (pc_in_thread_step_range (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)
&& ecs->event_thread->control.step_resume_breakpoint == NULL)
@@ -4405,6 +4725,7 @@ handle_signal_stop (struct execution_control_state *ecs)
"single-step range\n");
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;
keep_going (ecs);
@@ -4487,7 +4808,10 @@ process_event_stop_test (struct execution_control_state *ecs)
is the third argument to the probe. */
arg_value = probe_safe_evaluate_at_pc (frame, 2);
if (arg_value)
- jmp_buf_pc = value_as_address (arg_value);
+ {
+ jmp_buf_pc = value_as_address (arg_value);
+ jmp_buf_pc = gdbarch_addr_bits_remove (gdbarch, jmp_buf_pc);
+ }
else if (!gdbarch_get_longjmp_target_p (gdbarch)
|| !gdbarch_get_longjmp_target (gdbarch,
frame, &jmp_buf_pc))
@@ -4540,7 +4864,7 @@ process_event_stop_test (struct execution_control_state *ecs)
if (what.is_longjmp)
{
- check_longjmp_breakpoint_for_call_dummy (ecs->event_thread->num);
+ check_longjmp_breakpoint_for_call_dummy (ecs->event_thread);
if (!frame_id_p (ecs->event_thread->initiating_frame))
{
@@ -4573,9 +4897,7 @@ process_event_stop_test (struct execution_control_state *ecs)
exists. */
delete_step_resume_breakpoint (ecs->event_thread);
- ecs->event_thread->control.stop_step = 1;
- print_end_stepping_range_reason ();
- stop_stepping (ecs);
+ end_stepping_range (ecs);
}
return;
@@ -4625,10 +4947,12 @@ process_event_stop_test (struct execution_control_state *ecs)
fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_STOP_NOISY\n");
stop_print_frame = 1;
- /* We are about to nuke the step_resume_breakpointt via the
- cleanup chain, so no need to worry about it here. */
+ /* Assume the thread stopped for a breapoint. We'll still check
+ whether a/the breakpoint is there when the thread is next
+ resumed. */
+ ecs->event_thread->stepping_over_breakpoint = 1;
- stop_stepping (ecs);
+ stop_waiting (ecs);
return;
case BPSTAT_WHAT_STOP_SILENT:
@@ -4636,10 +4960,11 @@ process_event_stop_test (struct execution_control_state *ecs)
fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_STOP_SILENT\n");
stop_print_frame = 0;
- /* We are about to nuke the step_resume_breakpoin via the
- cleanup chain, so no need to worry about it here. */
-
- stop_stepping (ecs);
+ /* Assume the thread stopped for a breapoint. We'll still check
+ whether a/the breakpoint is there when the thread is next
+ resumed. */
+ ecs->event_thread->stepping_over_breakpoint = 1;
+ stop_waiting (ecs);
return;
case BPSTAT_WHAT_HP_STEP_RESUME:
@@ -4663,6 +4988,31 @@ process_event_stop_test (struct execution_control_state *ecs)
break;
}
+ /* If we stepped a permanent breakpoint and we had a high priority
+ step-resume breakpoint for the address we stepped, but we didn't
+ hit it, then we must have stepped into the signal handler. The
+ step-resume was only necessary to catch the case of _not_
+ stepping into the handler, so delete it, and fall through to
+ checking whether the step finished. */
+ if (ecs->event_thread->stepped_breakpoint)
+ {
+ struct breakpoint *sr_bp
+ = ecs->event_thread->control.step_resume_breakpoint;
+
+ if (sr_bp != NULL
+ && sr_bp->loc->permanent
+ && sr_bp->type == bp_hp_step_resume
+ && sr_bp->loc->address == ecs->event_thread->prev_pc)
+ {
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: stepped permanent breakpoint, stopped in "
+ "handler\n");
+ delete_step_resume_breakpoint (ecs->event_thread);
+ ecs->event_thread->step_after_step_resume_breakpoint = 0;
+ }
+ }
+
/* We come here if we hit a breakpoint but should not stop for it.
Possibly we also were stepping and should stop for that. So fall
through and test for stepping. But, if not stepping, do not
@@ -4734,11 +5084,7 @@ process_event_stop_test (struct execution_control_state *ecs)
if (stop_pc == ecs->event_thread->control.step_range_start
&& stop_pc != ecs->stop_func_start
&& execution_direction == EXEC_REVERSE)
- {
- ecs->event_thread->control.stop_step = 1;
- print_end_stepping_range_reason ();
- stop_stepping (ecs);
- }
+ end_stepping_range (ecs);
else
keep_going (ecs);
@@ -4870,28 +5216,21 @@ process_event_stop_test (struct execution_control_state *ecs)
ecs->event_thread->control.step_stack_frame_id)
&& (!frame_id_eq (ecs->event_thread->control.step_stack_frame_id,
outer_frame_id)
- || step_start_function != find_pc_function (stop_pc))))
+ || (ecs->event_thread->control.step_start_function
+ != find_pc_function (stop_pc)))))
{
CORE_ADDR real_stop_pc;
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: stepped into subroutine\n");
- if ((ecs->event_thread->control.step_over_calls == STEP_OVER_NONE)
- || ((ecs->event_thread->control.step_range_end == 1)
- && in_prologue (gdbarch, ecs->event_thread->prev_pc,
- ecs->stop_func_start)))
+ if (ecs->event_thread->control.step_over_calls == STEP_OVER_NONE)
{
/* I presume that step_over_calls is only 0 when we're
supposed to be stepping at the assembly language level
("stepi"). Just stop. */
- /* Also, maybe we just did a "nexti" inside a prolog, so we
- thought it was a subroutine call but it was not. Stop as
- well. FENN */
/* And this works the same backward as frontward. MVS */
- ecs->event_thread->control.stop_step = 1;
- print_end_stepping_range_reason ();
- stop_stepping (ecs);
+ end_stepping_range (ecs);
return;
}
@@ -5005,9 +5344,7 @@ process_event_stop_test (struct execution_control_state *ecs)
if (ecs->event_thread->control.step_over_calls == STEP_OVER_UNDEBUGGABLE
&& step_stop_if_no_debug)
{
- ecs->event_thread->control.stop_step = 1;
- print_end_stepping_range_reason ();
- stop_stepping (ecs);
+ end_stepping_range (ecs);
return;
}
@@ -5101,9 +5438,7 @@ process_event_stop_test (struct execution_control_state *ecs)
/* If we have no line number and the step-stop-if-no-debug
is set, we stop the step so that the user has a chance to
switch in assembly mode. */
- ecs->event_thread->control.stop_step = 1;
- print_end_stepping_range_reason ();
- stop_stepping (ecs);
+ end_stepping_range (ecs);
return;
}
else
@@ -5122,9 +5457,7 @@ process_event_stop_test (struct execution_control_state *ecs)
one instruction. */
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: stepi/nexti\n");
- ecs->event_thread->control.stop_step = 1;
- print_end_stepping_range_reason ();
- stop_stepping (ecs);
+ end_stepping_range (ecs);
return;
}
@@ -5136,9 +5469,7 @@ process_event_stop_test (struct execution_control_state *ecs)
or can this happen as a result of a return or longjmp?). */
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: no line number info\n");
- ecs->event_thread->control.stop_step = 1;
- print_end_stepping_range_reason ();
- stop_stepping (ecs);
+ end_stepping_range (ecs);
return;
}
@@ -5169,9 +5500,7 @@ process_event_stop_test (struct execution_control_state *ecs)
&& call_sal.symtab == ecs->event_thread->current_symtab)
step_into_inline_frame (ecs->ptid);
- ecs->event_thread->control.stop_step = 1;
- print_end_stepping_range_reason ();
- stop_stepping (ecs);
+ end_stepping_range (ecs);
return;
}
else
@@ -5183,11 +5512,7 @@ process_event_stop_test (struct execution_control_state *ecs)
&& call_sal.symtab == ecs->event_thread->current_symtab)
keep_going (ecs);
else
- {
- ecs->event_thread->control.stop_step = 1;
- print_end_stepping_range_reason ();
- stop_stepping (ecs);
- }
+ end_stepping_range (ecs);
return;
}
}
@@ -5210,11 +5535,7 @@ process_event_stop_test (struct execution_control_state *ecs)
if (ecs->event_thread->control.step_over_calls == STEP_OVER_ALL)
keep_going (ecs);
else
- {
- ecs->event_thread->control.stop_step = 1;
- print_end_stepping_range_reason ();
- stop_stepping (ecs);
- }
+ end_stepping_range (ecs);
return;
}
@@ -5229,9 +5550,7 @@ process_event_stop_test (struct execution_control_state *ecs)
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog,
"infrun: stepped to a different line\n");
- ecs->event_thread->control.stop_step = 1;
- print_end_stepping_range_reason ();
- stop_stepping (ecs);
+ end_stepping_range (ecs);
return;
}
@@ -5263,22 +5582,144 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs)
if (!non_stop)
{
struct thread_info *tp;
+ struct thread_info *stepping_thread;
+ struct thread_info *step_over;
+
+ /* If any thread is blocked on some internal breakpoint, and we
+ simply need to step over that breakpoint to get it going
+ again, do that first. */
+
+ /* However, if we see an event for the stepping thread, then we
+ know all other threads have been moved past their breakpoints
+ already. Let the caller check whether the step is finished,
+ etc., before deciding to move it past a breakpoint. */
+ if (ecs->event_thread->control.step_range_end != 0)
+ return 0;
+
+ /* Check if the current thread is blocked on an incomplete
+ step-over, interrupted by a random signal. */
+ if (ecs->event_thread->control.trap_expected
+ && ecs->event_thread->suspend.stop_signal != GDB_SIGNAL_TRAP)
+ {
+ if (debug_infrun)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: need to finish step-over of [%s]\n",
+ target_pid_to_str (ecs->event_thread->ptid));
+ }
+ keep_going (ecs);
+ return 1;
+ }
+
+ /* Check if the current thread is blocked by a single-step
+ breakpoint of another thread. */
+ if (ecs->hit_singlestep_breakpoint)
+ {
+ if (debug_infrun)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: need to step [%s] over single-step "
+ "breakpoint\n",
+ target_pid_to_str (ecs->ptid));
+ }
+ keep_going (ecs);
+ return 1;
+ }
+
+ /* Otherwise, we no longer expect a trap in the current thread.
+ Clear the trap_expected flag before switching back -- this is
+ what keep_going does as well, if we call it. */
+ ecs->event_thread->control.trap_expected = 0;
+
+ /* Likewise, clear the signal if it should not be passed. */
+ if (!signal_program[ecs->event_thread->suspend.stop_signal])
+ ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_0;
+
+ /* If scheduler locking applies even if not stepping, there's no
+ need to walk over threads. Above we've checked whether the
+ current thread is stepping. If some other thread not the
+ event thread is stepping, then it must be that scheduler
+ locking is not in effect. */
+ if (schedlock_applies (ecs->event_thread))
+ return 0;
+
+ /* Look for the stepping/nexting thread, and check if any other
+ thread other than the stepping thread needs to start a
+ step-over. Do all step-overs before actually proceeding with
+ step/next/etc. */
+ stepping_thread = NULL;
+ step_over = NULL;
+ ALL_NON_EXITED_THREADS (tp)
+ {
+ /* Ignore threads of processes we're not resuming. */
+ if (!sched_multi
+ && ptid_get_pid (tp->ptid) != ptid_get_pid (inferior_ptid))
+ continue;
+
+ /* When stepping over a breakpoint, we lock all threads
+ except the one that needs to move past the breakpoint.
+ If a non-event thread has this set, the "incomplete
+ step-over" check above should have caught it earlier. */
+ gdb_assert (!tp->control.trap_expected);
+
+ /* Did we find the stepping thread? */
+ if (tp->control.step_range_end)
+ {
+ /* Yep. There should only one though. */
+ gdb_assert (stepping_thread == NULL);
+
+ /* The event thread is handled at the top, before we
+ enter this loop. */
+ gdb_assert (tp != ecs->event_thread);
+
+ /* If some thread other than the event thread is
+ stepping, then scheduler locking can't be in effect,
+ otherwise we wouldn't have resumed the current event
+ thread in the first place. */
+ gdb_assert (!schedlock_applies (tp));
+
+ stepping_thread = tp;
+ }
+ else if (thread_still_needs_step_over (tp))
+ {
+ step_over = tp;
+
+ /* At the top we've returned early if the event thread
+ is stepping. If some other thread not the event
+ thread is stepping, then scheduler locking can't be
+ in effect, and we can resume this thread. No need to
+ keep looking for the stepping thread then. */
+ break;
+ }
+ }
- tp = iterate_over_threads (currently_stepping_or_nexting_callback,
- ecs->event_thread);
- if (tp)
+ if (step_over != NULL)
{
- /* However, if the current thread is blocked on some internal
- breakpoint, and we simply need to step over that breakpoint
- to get it going again, do that first. */
- if ((ecs->event_thread->control.trap_expected
- && ecs->event_thread->suspend.stop_signal != GDB_SIGNAL_TRAP)
- || ecs->event_thread->stepping_over_breakpoint)
+ tp = step_over;
+ if (debug_infrun)
{
- keep_going (ecs);
- return 1;
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: need to step-over [%s]\n",
+ target_pid_to_str (tp->ptid));
}
+ /* Only the stepping thread should have this set. */
+ gdb_assert (tp->control.step_range_end == 0);
+
+ ecs->ptid = tp->ptid;
+ ecs->event_thread = tp;
+ switch_to_thread (ecs->ptid);
+ keep_going (ecs);
+ return 1;
+ }
+
+ if (stepping_thread != NULL)
+ {
+ struct frame_info *frame;
+ struct gdbarch *gdbarch;
+
+ tp = stepping_thread;
+
/* If the stepping thread exited, then don't try to switch
back and resume it, which could fail in several different
ways depending on the target. Instead, just keep going.
@@ -5311,11 +5752,6 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs)
return 1;
}
- /* Otherwise, we no longer expect a trap in the current thread.
- Clear the trap_expected flag before switching back -- this is
- what keep_going would do as well, if we called it. */
- ecs->event_thread->control.trap_expected = 0;
-
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog,
"infrun: switching back to stepped thread\n");
@@ -5323,7 +5759,59 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs)
ecs->event_thread = tp;
ecs->ptid = tp->ptid;
context_switch (ecs->ptid);
- keep_going (ecs);
+
+ stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid));
+ frame = get_current_frame ();
+ gdbarch = get_frame_arch (frame);
+
+ /* If the PC of the thread we were trying to single-step has
+ changed, then that thread has trapped or been signaled,
+ but the event has not been reported to GDB yet. Re-poll
+ the target looking for this particular thread's event
+ (i.e. temporarily enable schedlock) by:
+
+ - setting a break at the current PC
+ - resuming that particular thread, only (by setting
+ trap expected)
+
+ This prevents us continuously moving the single-step
+ breakpoint forward, one instruction at a time,
+ overstepping. */
+
+ if (stop_pc != tp->prev_pc)
+ {
+ ptid_t resume_ptid;
+
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: expected thread advanced also\n");
+
+ /* Clear the info of the previous step-over, as it's no
+ longer valid. It's what keep_going would do too, if
+ we called it. Must do this before trying to insert
+ the sss breakpoint, otherwise if we were previously
+ trying to step over this exact address in another
+ thread, the breakpoint ends up not installed. */
+ clear_step_over_info ();
+
+ insert_single_step_breakpoint (get_frame_arch (frame),
+ get_frame_address_space (frame),
+ stop_pc);
+
+ resume_ptid = user_visible_resume_ptid (tp->control.stepping_command);
+ do_target_resume (resume_ptid,
+ currently_stepping (tp), GDB_SIGNAL_0);
+ prepare_to_wait (ecs);
+ }
+ else
+ {
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: expected thread still "
+ "hasn't advanced\n");
+ keep_going (ecs);
+ }
+
return 1;
}
}
@@ -5338,22 +5826,10 @@ currently_stepping (struct thread_info *tp)
return ((tp->control.step_range_end
&& tp->control.step_resume_breakpoint == NULL)
|| tp->control.trap_expected
+ || tp->stepped_breakpoint
|| bpstat_should_step ());
}
-/* Returns true if any thread *but* the one passed in "data" is in the
- middle of stepping or of handling a "next". */
-
-static int
-currently_stepping_or_nexting_callback (struct thread_info *tp, void *data)
-{
- if (tp == data)
- return 0;
-
- return (tp->control.step_range_end
- || tp->control.trap_expected);
-}
-
/* Inferior has stepped into a subroutine call with source code that
we should not step over. Do step to the first line of code in
it. */
@@ -5362,13 +5838,13 @@ static void
handle_step_into_function (struct gdbarch *gdbarch,
struct execution_control_state *ecs)
{
- struct symtab *s;
+ struct compunit_symtab *cust;
struct symtab_and_line stop_func_sal, sr_sal;
fill_in_stop_func (gdbarch, ecs);
- s = find_pc_symtab (stop_pc);
- if (s && s->language != language_asm)
+ cust = find_pc_compunit_symtab (stop_pc);
+ if (cust != NULL && compunit_language (cust) != language_asm)
ecs->stop_func_start = gdbarch_skip_prologue (gdbarch,
ecs->stop_func_start);
@@ -5410,9 +5886,7 @@ handle_step_into_function (struct gdbarch *gdbarch,
if (ecs->stop_func_start == stop_pc)
{
/* We are already there: stop now. */
- ecs->event_thread->control.stop_step = 1;
- print_end_stepping_range_reason ();
- stop_stepping (ecs);
+ end_stepping_range (ecs);
return;
}
else
@@ -5443,13 +5917,13 @@ static void
handle_step_into_function_backward (struct gdbarch *gdbarch,
struct execution_control_state *ecs)
{
- struct symtab *s;
+ struct compunit_symtab *cust;
struct symtab_and_line stop_func_sal;
fill_in_stop_func (gdbarch, ecs);
- s = find_pc_symtab (stop_pc);
- if (s && s->language != language_asm)
+ cust = find_pc_compunit_symtab (stop_pc);
+ if (cust != NULL && compunit_language (cust) != language_asm)
ecs->stop_func_start = gdbarch_skip_prologue (gdbarch,
ecs->stop_func_start);
@@ -5459,9 +5933,7 @@ handle_step_into_function_backward (struct gdbarch *gdbarch,
if (stop_func_sal.pc == stop_pc)
{
/* We're there already. Just stop stepping now. */
- ecs->event_thread->control.stop_step = 1;
- print_end_stepping_range_reason ();
- stop_stepping (ecs);
+ end_stepping_range (ecs);
}
else
{
@@ -5601,14 +6073,11 @@ insert_longjmp_resume_breakpoint (struct gdbarch *gdbarch, CORE_ADDR pc)
static void
insert_exception_resume_breakpoint (struct thread_info *tp,
- struct block *b,
+ const struct block *b,
struct frame_info *frame,
struct symbol *sym)
{
- volatile struct gdb_exception e;
-
- /* We want to ignore errors here. */
- TRY_CATCH (e, RETURN_MASK_ERROR)
+ TRY
{
struct symbol *vsym;
struct value *value;
@@ -5637,6 +6106,11 @@ insert_exception_resume_breakpoint (struct thread_info *tp,
inferior_thread ()->control.exception_resume_breakpoint = bp;
}
}
+ CATCH (e, RETURN_MASK_ERROR)
+ {
+ /* We want to ignore errors here. */
+ }
+ END_CATCH
}
/* A helper for check_exception_resume that sets an
@@ -5644,7 +6118,7 @@ insert_exception_resume_breakpoint (struct thread_info *tp,
static void
insert_exception_resume_from_probe (struct thread_info *tp,
- const struct probe *probe,
+ const struct bound_probe *probe,
struct frame_info *frame)
{
struct value *arg_value;
@@ -5677,8 +6151,7 @@ static void
check_exception_resume (struct execution_control_state *ecs,
struct frame_info *frame)
{
- volatile struct gdb_exception e;
- const struct probe *probe;
+ struct bound_probe probe;
struct symbol *func;
/* First see if this exception unwinding breakpoint was set via a
@@ -5686,9 +6159,9 @@ check_exception_resume (struct execution_control_state *ecs,
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)
+ if (probe.probe)
{
- insert_exception_resume_from_probe (ecs->event_thread, probe, frame);
+ insert_exception_resume_from_probe (ecs->event_thread, &probe, frame);
return;
}
@@ -5696,9 +6169,9 @@ check_exception_resume (struct execution_control_state *ecs,
if (!func)
return;
- TRY_CATCH (e, RETURN_MASK_ERROR)
+ TRY
{
- struct block *b;
+ const struct block *b;
struct block_iterator iter;
struct symbol *sym;
int argno = 0;
@@ -5733,13 +6206,19 @@ check_exception_resume (struct execution_control_state *ecs,
}
}
}
+ CATCH (e, RETURN_MASK_ERROR)
+ {
+ }
+ END_CATCH
}
static void
-stop_stepping (struct execution_control_state *ecs)
+stop_waiting (struct execution_control_state *ecs)
{
if (debug_infrun)
- fprintf_unfiltered (gdb_stdlog, "infrun: stop_stepping\n");
+ 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;
@@ -5768,11 +6247,14 @@ keep_going (struct execution_control_state *ecs)
are supposed to pass through to the inferior. Simply
continue. */
discard_cleanups (old_cleanups);
- resume (currently_stepping (ecs->event_thread),
- ecs->event_thread->suspend.stop_signal);
+ resume (ecs->event_thread->suspend.stop_signal);
}
else
{
+ struct regcache *regcache = get_current_regcache ();
+ int remove_bp;
+ int remove_wps;
+
/* Either the trap was not expected, but we are continuing
anyway (if we got a signal, the user asked it be passed to
the child)
@@ -5786,37 +6268,47 @@ keep_going (struct execution_control_state *ecs)
already inserted breakpoints. Therefore, we don't
care if breakpoints were already inserted, or not. */
- if (ecs->event_thread->stepping_over_breakpoint)
+ /* If we need to step over a breakpoint, and we're not using
+ displaced stepping to do so, insert all breakpoints
+ (watchpoints, etc.) but the one we're stepping over, step one
+ instruction, and then re-insert the breakpoint when that step
+ is finished. */
+
+ remove_bp = (ecs->hit_singlestep_breakpoint
+ || thread_still_needs_step_over (ecs->event_thread));
+ remove_wps = (ecs->event_thread->stepping_over_watchpoint
+ && !target_have_steppable_watchpoint);
+
+ /* We can't use displaced stepping if we need to step past a
+ watchpoint. The instruction copied to the scratch pad would
+ still trigger the watchpoint. */
+ if (remove_bp
+ && (remove_wps
+ || !use_displaced_stepping (get_regcache_arch (regcache))))
{
- struct regcache *thread_regcache = get_thread_regcache (ecs->ptid);
-
- if (!use_displaced_stepping (get_regcache_arch (thread_regcache)))
- {
- /* Since we can't do a displaced step, we have to remove
- the breakpoint while we step it. To keep things
- simple, we remove them all. */
- remove_breakpoints ();
- }
+ set_step_over_info (get_regcache_aspace (regcache),
+ regcache_read_pc (regcache), remove_wps);
}
+ else if (remove_wps)
+ set_step_over_info (NULL, 0, remove_wps);
else
- {
- volatile struct gdb_exception e;
+ clear_step_over_info ();
- /* Stop stepping if inserting breakpoints fails. */
- TRY_CATCH (e, RETURN_MASK_ERROR)
- {
- insert_breakpoints ();
- }
- if (e.reason < 0)
- {
- exception_print (gdb_stderr, e);
- stop_stepping (ecs);
- return;
- }
+ /* Stop stepping if inserting breakpoints fails. */
+ TRY
+ {
+ insert_breakpoints ();
+ }
+ CATCH (e, RETURN_MASK_ERROR)
+ {
+ exception_print (gdb_stderr, e);
+ stop_waiting (ecs);
+ discard_cleanups (old_cleanups);
+ return;
}
+ END_CATCH
- ecs->event_thread->control.trap_expected
- = ecs->event_thread->stepping_over_breakpoint;
+ ecs->event_thread->control.trap_expected = (remove_bp || remove_wps);
/* Do not deliver GDB_SIGNAL_TRAP (except when the user
explicitly specifies that such a signal should be delivered
@@ -5833,8 +6325,7 @@ keep_going (struct execution_control_state *ecs)
ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_0;
discard_cleanups (old_cleanups);
- resume (currently_stepping (ecs->event_thread),
- ecs->event_thread->suspend.stop_signal);
+ resume (ecs->event_thread->suspend.stop_signal);
}
prepare_to_wait (ecs);
@@ -5856,35 +6347,42 @@ prepare_to_wait (struct execution_control_state *ecs)
ecs->wait_some_more = 1;
}
+/* We are done with the step range of a step/next/si/ni command.
+ Called once for each n of a "step n" operation. */
+
+static void
+end_stepping_range (struct execution_control_state *ecs)
+{
+ ecs->event_thread->control.stop_step = 1;
+ stop_waiting (ecs);
+}
+
/* Several print_*_reason functions to print why the inferior has stopped.
We always print something when the inferior exits, or receives a signal.
The rest of the cases are dealt with later on in normal_stop and
print_it_typical. Ideally there should be a call to one of these
print_*_reason functions functions from handle_inferior_event each time
- stop_stepping is called. */
+ stop_waiting is called.
-/* Print why the inferior has stopped.
- We are done with a step/next/si/ni command, print why the inferior has
- stopped. For now print nothing. Print a message only if not in the middle
- of doing a "step n" operation for n > 1. */
+ Note that we don't call these directly, instead we delegate that to
+ the interpreters, through observers. Interpreters then call these
+ with whatever uiout is right. */
-static void
-print_end_stepping_range_reason (void)
+void
+print_end_stepping_range_reason (struct ui_out *uiout)
{
- if ((!inferior_thread ()->step_multi
- || !inferior_thread ()->control.stop_step)
- && ui_out_is_mi_like_p (current_uiout))
- ui_out_field_string (current_uiout, "reason",
- async_reason_lookup (EXEC_ASYNC_END_STEPPING_RANGE));
-}
+ /* For CLI-like interpreters, print nothing. */
-/* The inferior was terminated by a signal, print why it stopped. */
+ if (ui_out_is_mi_like_p (uiout))
+ {
+ ui_out_field_string (uiout, "reason",
+ async_reason_lookup (EXEC_ASYNC_END_STEPPING_RANGE));
+ }
+}
-static void
-print_signal_exited_reason (enum gdb_signal siggnal)
+void
+print_signal_exited_reason (struct ui_out *uiout, enum gdb_signal siggnal)
{
- struct ui_out *uiout = current_uiout;
-
annotate_signalled ();
if (ui_out_is_mi_like_p (uiout))
ui_out_field_string
@@ -5903,14 +6401,11 @@ print_signal_exited_reason (enum gdb_signal siggnal)
ui_out_text (uiout, "The program no longer exists.\n");
}
-/* The inferior program is finished, print why it stopped. */
-
-static void
-print_exited_reason (int exitstatus)
+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));
- struct ui_out *uiout = current_uiout;
annotate_exited (exitstatus);
if (exitstatus)
@@ -5937,18 +6432,11 @@ print_exited_reason (int exitstatus)
ui_out_text (uiout, pidstr);
ui_out_text (uiout, ") exited normally]\n");
}
- /* Support the --return-child-result option. */
- return_child_result_value = exitstatus;
}
-/* Signal received, print why the inferior has stopped. The signal table
- tells us to print about it. */
-
-static void
-print_signal_received_reason (enum gdb_signal siggnal)
+void
+print_signal_received_reason (struct ui_out *uiout, enum gdb_signal siggnal)
{
- struct ui_out *uiout = current_uiout;
-
annotate_signal ();
if (siggnal == GDB_SIGNAL_0 && !ui_out_is_mi_like_p (uiout))
@@ -5980,13 +6468,72 @@ print_signal_received_reason (enum gdb_signal siggnal)
ui_out_text (uiout, ".\n");
}
-/* Reverse execution: target ran out of history info, print why the inferior
- has stopped. */
+void
+print_no_history_reason (struct ui_out *uiout)
+{
+ ui_out_text (uiout, "\nNo more reverse-execution history.\n");
+}
+
+/* Print current location without a level number, if we have changed
+ functions or hit a breakpoint. Print source line if we have one.
+ bpstat_print contains the logic deciding in detail what to print,
+ based on the event(s) that just occurred. */
-static void
-print_no_history_reason (void)
+void
+print_stop_event (struct target_waitstatus *ws)
{
- ui_out_text (current_uiout, "\nNo more reverse-execution history.\n");
+ int bpstat_ret;
+ int source_flag;
+ int do_frame_printing = 1;
+ struct thread_info *tp = inferior_thread ();
+
+ bpstat_ret = bpstat_print (tp->control.stop_bpstat, ws->kind);
+ switch (bpstat_ret)
+ {
+ case PRINT_UNKNOWN:
+ /* FIXME: cagney/2002-12-01: Given that a frame ID does (or
+ should) carry around the function and does (or should) use
+ that when doing a frame comparison. */
+ 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))
+ {
+ /* Finished step, just print source line. */
+ source_flag = SRC_LINE;
+ }
+ else
+ {
+ /* Print location and source line. */
+ source_flag = SRC_AND_LOC;
+ }
+ break;
+ case PRINT_SRC_AND_LOC:
+ /* Print location and source line. */
+ source_flag = SRC_AND_LOC;
+ break;
+ case PRINT_SRC_ONLY:
+ source_flag = SRC_LINE;
+ break;
+ case PRINT_NOTHING:
+ /* Something bogus. */
+ source_flag = SRC_LINE;
+ do_frame_printing = 0;
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, _("Unknown value."));
+ }
+
+ /* The behavior of this routine with respect to the source
+ flag is:
+ SRC_LINE: Print only source line
+ LOCATION: Print only location
+ SRC_AND_LOC: Print location and source line. */
+ if (do_frame_printing)
+ print_stack_frame (get_selected_frame (NULL), 0, source_flag, 1);
+
+ /* Display the auto-display expressions. */
+ do_displays ();
}
/* Here to return control to GDB when the inferior stops for real.
@@ -6017,10 +6564,18 @@ normal_stop (void)
&& last.kind != TARGET_WAITKIND_NO_RESUMED)
make_cleanup (finish_thread_state_cleanup, &inferior_ptid);
- /* In non-stop mode, we don't want GDB to switch threads behind the
- user's back, to avoid races where the user is typing a command to
- apply to thread x, but GDB switches to thread y before the user
- finishes entering the command. */
+ /* As we're presenting a stop, and potentially removing breakpoints,
+ update the thread list so we can tell whether there are threads
+ running on the target. With target remote, for example, we can
+ only learn about new threads when we explicitly update the thread
+ list. Do this before notifying the interpreters about signal
+ stops, end of stepping ranges, etc., so that the "new thread"
+ output is emitted before e.g., "Program received signal FOO",
+ instead of after. */
+ update_thread_list ();
+
+ if (last.kind == TARGET_WAITKIND_STOPPED && stopped_by_random_signal)
+ observer_notify_signal_received (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
@@ -6028,7 +6583,16 @@ normal_stop (void)
There's no point in saying anything if the inferior has exited.
Note that SIGNALLED here means "exited with a signal", not
- "received a signal". */
+ "received a signal".
+
+ Also skip saying anything in non-stop mode. In that mode, as we
+ don't want GDB to switch threads behind the user's back, to avoid
+ races where the user is typing a command to apply to thread x,
+ but GDB switches to thread y before the user finishes entering
+ the command, fetch_inferior_event installs a cleanup to restore
+ the current thread back to the thread the user had selected right
+ 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)
&& target_has_execution
@@ -6051,7 +6615,8 @@ normal_stop (void)
printf_filtered (_("No unwaited-for children left.\n"));
}
- if (!breakpoints_always_inserted_mode () && target_has_execution)
+ /* Note: this depends on the update_thread_list call above. */
+ if (!breakpoints_should_be_inserted_now () && target_has_execution)
{
if (remove_breakpoints ())
{
@@ -6068,14 +6633,19 @@ normal_stop (void)
if (stopped_by_random_signal)
disable_current_display ();
- /* Don't print a message if in the middle of doing a "step n"
- operation for n > 1 */
+ /* Notify observers if we finished a "step"-like command, etc. */
if (target_has_execution
&& last.kind != TARGET_WAITKIND_SIGNALLED
&& last.kind != TARGET_WAITKIND_EXITED
- && inferior_thread ()->step_multi
&& inferior_thread ()->control.stop_step)
- goto done;
+ {
+ /* But not if in the middle of doing a "step n" operation for
+ n > 1 */
+ if (inferior_thread ()->step_multi)
+ goto done;
+
+ observer_notify_end_stepping_range ();
+ }
target_terminal_ours ();
async_enable_stdin ();
@@ -6084,10 +6654,20 @@ normal_stop (void)
display the frame below, but the current SAL will be incorrect
during a user hook-stop function. */
if (has_stack_frames () && !stop_stack_dummy)
- set_current_sal_from_frame (get_current_frame (), 1);
-
- /* Let the user/frontend see the threads as stopped. */
- do_cleanups (old_chain);
+ set_current_sal_from_frame (get_current_frame ());
+
+ /* Let the user/frontend see the threads as stopped, but do nothing
+ if the thread was running an infcall. We may be e.g., evaluating
+ a breakpoint condition. In that case, the thread had state
+ THREAD_RUNNING before the infcall, and shall remain set to
+ running, all without informing the user/frontend about state
+ transition changes. If this is actually a call command, then the
+ thread was originally already stopped, so there's no state to
+ finish either. */
+ if (target_has_execution && inferior_thread ()->control.in_infcall)
+ discard_cleanups (old_chain);
+ else
+ do_cleanups (old_chain);
/* Look up the hook_stop and run it (CLI internally handles problem
of stop_command's pre-hook not existing). */
@@ -6111,65 +6691,11 @@ normal_stop (void)
{
select_frame (get_current_frame ());
- /* Print current location without a level number, if
- we have changed functions or hit a breakpoint.
- Print source line if we have one.
- bpstat_print() contains the logic deciding in detail
- what to print, based on the event(s) that just occurred. */
-
/* If --batch-silent is enabled then there's no need to print the current
source location, and to try risks causing an error message about
missing source files. */
if (stop_print_frame && !batch_silent)
- {
- int bpstat_ret;
- int source_flag;
- int do_frame_printing = 1;
- struct thread_info *tp = inferior_thread ();
-
- bpstat_ret = bpstat_print (tp->control.stop_bpstat, last.kind);
- switch (bpstat_ret)
- {
- case PRINT_UNKNOWN:
- /* FIXME: cagney/2002-12-01: Given that a frame ID does
- (or should) carry around the function and does (or
- should) use that when doing a frame comparison. */
- if (tp->control.stop_step
- && frame_id_eq (tp->control.step_frame_id,
- get_frame_id (get_current_frame ()))
- && step_start_function == find_pc_function (stop_pc))
- source_flag = SRC_LINE; /* Finished step, just
- print source line. */
- else
- source_flag = SRC_AND_LOC; /* Print location and
- source line. */
- break;
- case PRINT_SRC_AND_LOC:
- source_flag = SRC_AND_LOC; /* Print location and
- source line. */
- break;
- case PRINT_SRC_ONLY:
- source_flag = SRC_LINE;
- break;
- case PRINT_NOTHING:
- source_flag = SRC_LINE; /* something bogus */
- do_frame_printing = 0;
- break;
- default:
- internal_error (__FILE__, __LINE__, _("Unknown value."));
- }
-
- /* The behavior of this routine with respect to the source
- flag is:
- SRC_LINE: Print only source line
- LOCATION: Print only location
- SRC_AND_LOC: Print location and source line. */
- if (do_frame_printing)
- print_stack_frame (get_selected_frame (NULL), 0, source_flag, 1);
-
- /* Display the auto-display expressions. */
- do_displays ();
- }
+ print_stop_event (&last);
}
/* Save the function value return registers, if we care.
@@ -6577,72 +7103,6 @@ handle_completer (struct cmd_list_element *ignore,
return return_val;
}
-static void
-xdb_handle_command (char *args, int from_tty)
-{
- char **argv;
- struct cleanup *old_chain;
-
- if (args == NULL)
- error_no_arg (_("xdb command"));
-
- /* Break the command line up into args. */
-
- argv = gdb_buildargv (args);
- old_chain = make_cleanup_freeargv (argv);
- if (argv[1] != (char *) NULL)
- {
- char *argBuf;
- int bufLen;
-
- bufLen = strlen (argv[0]) + 20;
- argBuf = (char *) xmalloc (bufLen);
- if (argBuf)
- {
- int validFlag = 1;
- enum gdb_signal oursig;
-
- oursig = gdb_signal_from_name (argv[0]);
- memset (argBuf, 0, bufLen);
- if (strcmp (argv[1], "Q") == 0)
- sprintf (argBuf, "%s %s", argv[0], "noprint");
- else
- {
- if (strcmp (argv[1], "s") == 0)
- {
- if (!signal_stop[oursig])
- sprintf (argBuf, "%s %s", argv[0], "stop");
- else
- sprintf (argBuf, "%s %s", argv[0], "nostop");
- }
- else if (strcmp (argv[1], "i") == 0)
- {
- if (!signal_program[oursig])
- sprintf (argBuf, "%s %s", argv[0], "pass");
- else
- sprintf (argBuf, "%s %s", argv[0], "nopass");
- }
- else if (strcmp (argv[1], "r") == 0)
- {
- if (!signal_print[oursig])
- sprintf (argBuf, "%s %s", argv[0], "print");
- else
- sprintf (argBuf, "%s %s", argv[0], "noprint");
- }
- else
- validFlag = 0;
- }
- if (validFlag)
- handle_command (argBuf, from_tty);
- else
- printf_filtered (_("Invalid signal handling flag.\n"));
- if (argBuf)
- xfree (argBuf);
- }
- }
- do_cleanups (old_chain);
-}
-
enum gdb_signal
gdb_signal_from_command (int num)
{
@@ -6851,7 +7311,7 @@ save_infcall_suspend_state (void)
}
}
- inf_state = XZALLOC (struct infcall_suspend_state);
+ inf_state = XCNEW (struct infcall_suspend_state);
if (siginfo_data)
{
@@ -7083,20 +7543,6 @@ discard_infcall_control_state (struct infcall_control_state *inf_status)
xfree (inf_status);
}
-int
-ptid_match (ptid_t ptid, ptid_t filter)
-{
- if (ptid_equal (filter, minus_one_ptid))
- return 1;
- if (ptid_is_pid (filter)
- && ptid_get_pid (ptid) == ptid_get_pid (filter))
- return 1;
- else if (ptid_equal (ptid, filter))
- return 1;
-
- return 0;
-}
-
/* restore_inferior_ptid() will be used by the cleanup machinery
to restore the inferior_ptid value saved in a call to
save_inferior_ptid(). */
@@ -7124,7 +7570,7 @@ save_inferior_ptid (void)
return make_cleanup (restore_inferior_ptid, saved_ptid_ptr);
}
-/* See inferior.h. */
+/* See infrun.h. */
void
clear_exit_convenience_vars (void)
@@ -7239,29 +7685,6 @@ may be interspersed with actions, with the actions being performed for\n\
all signals cumulatively specified."));
set_cmd_completer (c, handle_completer);
- if (xdb_commands)
- {
- add_com ("lz", class_info, signals_info, _("\
-What debugger does when program gets various signals.\n\
-Specify a signal as argument to print info on that signal only."));
- add_com ("z", class_run, xdb_handle_command, _("\
-Specify how to handle a signal.\n\
-Args are signals and actions to apply to those signals.\n\
-Symbolic signals (e.g. SIGSEGV) are recommended but numeric signals\n\
-from 1-15 are allowed for compatibility with old versions of GDB.\n\
-Numeric ranges may be specified with the form LOW-HIGH (e.g. 1-5).\n\
-The special arg \"all\" is recognized to mean all signals except those\n\
-used by the debugger, typically SIGTRAP and SIGINT.\n\
-Recognized actions include \"s\" (toggles between stop and nostop),\n\
-\"r\" (toggles between print and noprint), \"i\" (toggles between pass and \
-nopass), \"Q\" (noprint)\n\
-Stop means reenter debugger if this signal happens (implies print).\n\
-Print means print a message if this signal happens.\n\
-Pass means let program see this signal; otherwise program doesn't know.\n\
-Ignore is a synonym for nopass and noignore is a synonym for pass.\n\
-Pass and Stop may be combined."));
- }
-
if (!dbx_commands)
stop_command = add_cmd ("stop", class_obscure,
not_just_help_class_command, _("\
@@ -7315,7 +7738,7 @@ leave it stopped or free to run as needed."),
signal_catch = (unsigned char *)
xmalloc (sizeof (signal_catch[0]) * numsigs);
signal_pass = (unsigned char *)
- xmalloc (sizeof (signal_program[0]) * numsigs);
+ xmalloc (sizeof (signal_pass[0]) * numsigs);
for (i = 0; i < numsigs; i++)
{
signal_stop[i] = 1;
@@ -7418,9 +7841,8 @@ Set mode for locking scheduler during execution."), _("\
Show mode for locking scheduler during execution."), _("\
off == no locking (threads may preempt at any time)\n\
on == full locking (no thread except the current thread may run)\n\
-step == scheduler locked during every single-step operation.\n\
- In this mode, no other thread may run during a step command.\n\
- Other threads may run while stepping over a function call ('next')."),
+step == scheduler locked during stepping commands (step, next, stepi, nexti).\n\
+ In this mode, other threads may run during other commands."),
set_schedlock_func, /* traps on target vector */
show_scheduler_mode,
&setlist, &showlist);