resume_ptid = RESUME_ALL; /* Default */
- if ((step || singlestep_breakpoints_inserted_p)
- && (stepping_past_singlestep_breakpoint
- || (!breakpoints_inserted && breakpoint_here_p (read_pc ()))))
+ /* 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));
+
+ if (singlestep_breakpoints_inserted_p
+ && stepping_past_singlestep_breakpoint)
{
- /* Stepping past a breakpoint without inserting breakpoints.
- Make sure only the current thread gets to step, so that
- other threads don't sneak past breakpoints while they are
- not inserted. */
+ /* 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;
+ }
+ if (step && breakpoint_here_p (read_pc ())
+ && !breakpoint_inserted_here_p (read_pc ()))
+ {
+ /* We're stepping, have breakpoint at PC, and it's
+ not inserted. Most likely, proceed has noticed that
+ we have breakpoint and tries to single-step over it,
+ so that it's not hit. 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 either has all breakpoints inserted,
+ or all removed, so if we let other threads run,
+ we can actually miss any breakpoint, not the one at PC. */
resume_ptid = inferior_ptid;
}
{
infwait_normal_state,
infwait_thread_hop_state,
+ infwait_step_watch_state,
infwait_nonstep_watch_state
};
by an event from the inferior, figure out what it means and take
appropriate action. */
-int stepped_after_stopped_by_watchpoint;
-
void
handle_inferior_event (struct execution_control_state *ecs)
{
- /* NOTE: bje/2005-05-02: If you're looking at this code and thinking
- that the variable stepped_after_stopped_by_watchpoint isn't used,
- then you're wrong! See remote.c:remote_stopped_data_address. */
-
int sw_single_step_trap_p = 0;
- int stopped_by_watchpoint = -1; /* Mark as unknown. */
+ int stopped_by_watchpoint;
+ int stepped_after_stopped_by_watchpoint = 0;
/* Cache the last pid/waitstatus. */
target_last_wait_ptid = ecs->ptid;
case infwait_normal_state:
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: infwait_normal_state\n");
- stepped_after_stopped_by_watchpoint = 0;
+ break;
+
+ case infwait_step_watch_state:
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: infwait_step_watch_state\n");
+
+ stepped_after_stopped_by_watchpoint = 1;
break;
case infwait_nonstep_watch_state:
#endif
target_terminal_inferior ();
- /* Try to reenable shared library breakpoints, additional
- code segments in shared libraries might be mapped in now. */
- re_enable_breakpoints_in_shlibs ();
-
/* If requested, stop when the dynamic linker notifies
gdb of events. This allows the user to get control
and place breakpoints in initializer routines for
stop_pc = read_pc ();
- stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid, 0);
+ stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
ecs->random_signal = !bpstat_explains_signal (stop_bpstat);
ecs->saved_inferior_ptid = inferior_ptid;
inferior_ptid = ecs->ptid;
- stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid, 0);
+ stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
ecs->random_signal = !bpstat_explains_signal (stop_bpstat);
inferior_ptid = ecs->saved_inferior_ptid;
singlestep_breakpoints_inserted_p = 0;
}
- /* It may not be necessary to disable the watchpoint to stop over
- it. For example, the PA can (with some kernel cooperation)
- single step over a watchpoint without disabling the watchpoint. */
- if (HAVE_STEPPABLE_WATCHPOINT && STOPPED_BY_WATCHPOINT (ecs->ws))
+ if (stepped_after_stopped_by_watchpoint)
+ stopped_by_watchpoint = 0;
+ else
+ stopped_by_watchpoint = watchpoints_triggered (&ecs->ws);
+
+ /* If necessary, step over this watchpoint. We'll be back to display
+ it in a moment. */
+ if (stopped_by_watchpoint
+ && (HAVE_STEPPABLE_WATCHPOINT
+ || gdbarch_have_nonsteppable_watchpoint (current_gdbarch)))
{
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: STOPPED_BY_WATCHPOINT\n");
- resume (1, 0);
- prepare_to_wait (ecs);
- return;
- }
- /* It is far more common to need to disable a watchpoint to step
- the inferior over it. FIXME. What else might a debug
- register or page protection watchpoint scheme need here? */
- if (gdbarch_have_nonsteppable_watchpoint (current_gdbarch)
- && STOPPED_BY_WATCHPOINT (ecs->ws))
- {
/* At this point, we are stopped at an instruction which has
attempted to write to a piece of memory under control of
a watchpoint. The instruction hasn't actually executed
In order to make watchpoints work `right', we really need
to complete the memory write, and then evaluate the
- watchpoint expression. The following code does that by
- removing the watchpoint (actually, all watchpoints and
- breakpoints), single-stepping the target, re-inserting
- watchpoints, and then falling through to let normal
- single-step processing handle proceed. Since this
- includes evaluating watchpoints, things will come to a
- stop in the correct manner. */
-
- if (debug_infrun)
- fprintf_unfiltered (gdb_stdlog, "infrun: STOPPED_BY_WATCHPOINT\n");
- remove_breakpoints ();
+ watchpoint expression. We do this by single-stepping the
+ target.
+
+ It may not be necessary to disable the watchpoint to stop 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. */
+
+ if (!HAVE_STEPPABLE_WATCHPOINT)
+ remove_breakpoints ();
registers_changed ();
target_resume (ecs->ptid, 1, TARGET_SIGNAL_0); /* Single step */
-
ecs->waiton_ptid = ecs->ptid;
- ecs->wp = &(ecs->ws);
- ecs->infwait_state = infwait_nonstep_watch_state;
+ if (HAVE_STEPPABLE_WATCHPOINT)
+ ecs->infwait_state = infwait_step_watch_state;
+ else
+ ecs->infwait_state = infwait_nonstep_watch_state;
prepare_to_wait (ecs);
return;
}
- /* It may be possible to simply continue after a watchpoint. */
- if (HAVE_CONTINUABLE_WATCHPOINT)
- stopped_by_watchpoint = STOPPED_BY_WATCHPOINT (ecs->ws);
-
ecs->stop_func_start = 0;
ecs->stop_func_end = 0;
ecs->stop_func_name = 0;
else
{
/* See if there is a breakpoint at the current PC. */
- stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid,
- stopped_by_watchpoint);
+ stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
/* Following in case break condition called a
function. */
#endif
target_terminal_inferior ();
- /* Try to reenable shared library breakpoints, additional
- code segments in shared libraries might be mapped in now. */
- re_enable_breakpoints_in_shlibs ();
-
/* If requested, stop when the dynamic linker notifies
gdb of events. This allows the user to get control
and place breakpoints in initializer routines for
function. Fortunately, those days are nearly upon us. */
#endif
{
- struct frame_id current_frame = get_frame_id (get_current_frame ());
- if (!(frame_id_inner (current_frame, step_frame_id)))
+ struct frame_info *frame = get_current_frame ();
+ struct frame_id current_frame = get_frame_id (frame);
+ if (!(frame_id_inner (get_frame_arch (frame), current_frame,
+ step_frame_id)))
step_frame_id = current_frame;
}