#include "arch-utils.h"
#include "gdbsupport/scope-exit.h"
#include "gdbsupport/forward-scope-exit.h"
-#include "gdb_select.h"
+#include "gdbsupport/gdb_select.h"
#include <unordered_map>
/* Prototypes for local functions */
static void sig_print_header (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 int currently_stepping (struct thread_info *tp);
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)
+static bool
+follow_fork_inferior (bool follow_child, bool detach_fork)
{
int has_vforked;
ptid_t parent_ptid, child_ptid;
if the inferior should be resumed; false, if the target for some
reason decided it's best not to resume. */
-static int
-follow_fork (void)
+static bool
+follow_fork ()
{
- int follow_child = (follow_fork_mode_string == follow_fork_mode_child);
- int should_resume = 1;
+ bool follow_child = (follow_fork_mode_string == follow_fork_mode_child);
+ bool should_resume = true;
struct thread_info *tp;
/* Copy user stepping state to the new inferior thread. FIXME: the
happened. */
thread_info *wait_thread = find_thread_ptid (wait_target, wait_ptid);
switch_to_thread (wait_thread);
- should_resume = 0;
+ should_resume = false;
}
}
int pass;
int iterations = 0;
- gdb_assert (target_is_non_stop_p ());
+ gdb_assert (exists_non_stop_target ());
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: stop_all_threads\n");
to tell the target to stop. */
for (thread_info *t : all_non_exited_threads ())
{
+ /* For a single-target setting with an all-stop target,
+ we would not even arrive here. For a multi-target
+ setting, until GDB is able to handle a mixture of
+ all-stop and non-stop targets, simply skip all-stop
+ targets' threads. This should be fine due to the
+ protection of 'check_multi_target_resumption'. */
+
+ switch_to_thread_no_regs (t);
+ if (!target_is_non_stop_p ())
+ continue;
+
if (t->executing)
{
/* If already stopping, don't request a stop again.
"infrun: %s executing, "
"need stop\n",
target_pid_to_str (t->ptid).c_str ());
- switch_to_thread_no_regs (t);
target_stop (t->ptid);
t->stop_requested = 1;
}
watchpoints, for example, always appear in the bpstat. */
if (!bpstat_causes_stop (ecs->event_thread->control.stop_bpstat))
{
- int should_resume;
- int follow_child
+ bool follow_child
= (follow_fork_mode_string == follow_fork_mode_child);
ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_0;
process_stratum_target *targ
= ecs->event_thread->inf->process_target ();
- should_resume = follow_fork ();
+ bool should_resume = follow_fork ();
/* Note that one of these may be an invalid pointer,
depending on detach_fork. */
}
}
+ /* This always returns the sal for the inner-most frame when we are in a
+ stack of inlined frames, even if GDB actually believes that it is in a
+ more outer frame. This is checked for below by calls to
+ inline_skipped_frames. */
stop_pc_sal = find_pc_line (ecs->event_thread->suspend.stop_pc, 0);
/* NOTE: tausq/2004-05-24: This if block used to be done before all
return;
}
+ bool refresh_step_info = true;
if ((ecs->event_thread->suspend.stop_pc == stop_pc_sal.pc)
&& (ecs->event_thread->current_line != stop_pc_sal.line
|| ecs->event_thread->current_symtab != stop_pc_sal.symtab))
{
- /* We are at the start of a different line. So stop. Note that
- we don't stop if we step into the middle of a different line.
- That is said to make things like for (;;) statements work
- better. */
- if (debug_infrun)
- fprintf_unfiltered (gdb_stdlog,
- "infrun: stepped to a different line\n");
- end_stepping_range (ecs);
- return;
+ if (stop_pc_sal.is_stmt)
+ {
+ /* We are at the start of a different line. So stop. Note that
+ we don't stop if we step into the middle of a different line.
+ That is said to make things like for (;;) statements work
+ better. */
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: stepped to a different line\n");
+ end_stepping_range (ecs);
+ return;
+ }
+ else if (frame_id_eq (get_frame_id (get_current_frame ()),
+ ecs->event_thread->control.step_frame_id))
+ {
+ /* We are at the start of a different line, however, this line is
+ not marked as a statement, and we have not changed frame. We
+ ignore this line table entry, and continue stepping forward,
+ looking for a better place to stop. */
+ refresh_step_info = false;
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: stepped to a different line, but "
+ "it's not the start of a statement\n");
+ }
}
/* We aren't done stepping.
Optimize by setting the stepping range to the line.
(We might not be in the original line, but if we entered a
new line in mid-statement, we continue stepping. This makes
- things like for(;;) statements work better.) */
+ things like for(;;) statements work better.)
+
+ If we entered a SAL that indicates a non-statement line table entry,
+ then we update the stepping range, but we don't update the step info,
+ which includes things like the line number we are stepping away from.
+ This means we will stop when we find a line table entry that is marked
+ as is-statement, even if it matches the non-statement one we just
+ stepped into. */
ecs->event_thread->control.step_range_start = stop_pc_sal.pc;
ecs->event_thread->control.step_range_end = stop_pc_sal.end;
ecs->event_thread->control.may_range_step = 1;
- set_step_info (ecs->event_thread, frame, stop_pc_sal);
+ if (refresh_step_info)
+ set_step_info (ecs->event_thread, frame, stop_pc_sal);
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: keep going\n");
/* Let callers know we don't want to wait for the inferior anymore. */
ecs->wait_some_more = 0;
- /* If all-stop, but the target is always in non-stop mode, stop all
+ /* If all-stop, but there exists a non-stop target, stop all
threads now that we're presenting the stop to the user. */
- if (!non_stop && target_is_non_stop_p ())
+ if (!non_stop && exists_non_stop_target ())
stop_all_threads ();
}