This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
#include "gdb_string.h"
static void xdb_handle_command (char *args, int from_tty);
-static int prepare_to_proceed (void);
+static int prepare_to_proceed (int);
void _initialize_infrun (void);
-int inferior_ignoring_startup_exec_events = 0;
int inferior_ignoring_leading_exec_events = 0;
/* When set, stop the 'step' command if we enter a function which has
thread here so that we can resume single-stepping it later. */
static ptid_t saved_singlestep_ptid;
static int stepping_past_singlestep_breakpoint;
+
+/* Similarly, if we are stepping another thread past a breakpoint,
+ save the original thread here so that we can resume stepping it later. */
+static ptid_t stepping_past_breakpoint_ptid;
+static int stepping_past_breakpoint;
\f
/* Things to clean up if we QUIT out of resume (). */
/* This should be suitable for any targets that support threads. */
static int
-prepare_to_proceed (void)
+prepare_to_proceed (int step)
{
ptid_t wait_ptid;
struct target_waitstatus wait_status;
/* Get the last target status returned by target_wait(). */
get_last_target_status (&wait_ptid, &wait_status);
- /* Make sure we were stopped either at a breakpoint, or because
- of a Ctrl-C. */
+ /* Make sure we were stopped at a breakpoint. */
if (wait_status.kind != TARGET_WAITKIND_STOPPED
- || (wait_status.value.sig != TARGET_SIGNAL_TRAP
- && wait_status.value.sig != TARGET_SIGNAL_INT))
+ || wait_status.value.sig != TARGET_SIGNAL_TRAP)
{
return 0;
}
+ /* Switched over from WAIT_PID. */
if (!ptid_equal (wait_ptid, minus_one_ptid)
- && !ptid_equal (inferior_ptid, wait_ptid))
+ && !ptid_equal (inferior_ptid, wait_ptid)
+ && breakpoint_here_p (read_pc_pid (wait_ptid)))
{
- /* Switched over from WAIT_PID. */
- CORE_ADDR wait_pc = read_pc_pid (wait_ptid);
-
- if (wait_pc != read_pc ())
+ /* If stepping, remember current thread to switch back to. */
+ if (step)
{
- /* Switch back to WAIT_PID thread. */
- inferior_ptid = wait_ptid;
-
- /* FIXME: This stuff came from switch_to_thread() in
- thread.c (which should probably be a public function). */
- reinit_frame_cache ();
- registers_changed ();
- stop_pc = wait_pc;
+ stepping_past_breakpoint = 1;
+ stepping_past_breakpoint_ptid = inferior_ptid;
}
+ /* Switch back to WAIT_PID thread. */
+ switch_to_thread (wait_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. */
- if (breakpoint_here_p (wait_pc))
- return 1;
+ so we need to step over it before continuing to avoid
+ hitting it straight away. */
+ return 1;
}
return 0;
-
}
/* Record the pc of the program the last time it stopped. This is
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 () && breakpoint_here_p (read_pc ()))
+ if (prepare_to_proceed (step))
oneproc = 1;
if (oneproc)
{
init_thread_list ();
init_wait_for_inferior ();
- stop_soon = STOP_QUIETLY;
+ stop_soon = STOP_QUIETLY_REMOTE;
trap_expected = 0;
/* Always go on waiting for the target, regardless of the mode. */
clear_proceed_status ();
stepping_past_singlestep_breakpoint = 0;
+ stepping_past_breakpoint = 0;
}
\f
/* This enum encodes possible reasons for doing a target_wait, so that
{
infwait_normal_state,
infwait_thread_hop_state,
+ infwait_step_watch_state,
infwait_nonstep_watch_state
};
&ecs->stepping_through_solib_catchpoints,
&ecs->current_line, &ecs->current_symtab);
}
- inferior_ptid = ecs->ptid;
- reinit_frame_cache ();
+
+ switch_to_thread (ecs->ptid);
}
static void
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:
case TARGET_WAITKIND_LOADED:
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_LOADED\n");
- /* Ignore gracefully during startup of the inferior, as it
- might be the shell which has just loaded some objects,
- otherwise add the symbols for the newly loaded objects. */
-#ifdef SOLIB_ADD
+ /* Ignore gracefully during startup of the inferior, as it might
+ be the shell which has just loaded some objects, otherwise
+ add the symbols for the newly loaded objects. Also ignore at
+ the beginning of an attach or remote session; we will query
+ the full list of libraries once the connection is
+ established. */
if (stop_soon == NO_STOP_QUIETLY)
{
+ int breakpoints_were_inserted;
+
/* Remove breakpoints, SOLIB_ADD might adjust
breakpoint addresses via breakpoint_re_set. */
+ breakpoints_were_inserted = breakpoints_inserted;
if (breakpoints_inserted)
remove_breakpoints ();
+ breakpoints_inserted = 0;
/* Check for any newly added shared libraries if we're
supposed to be adding them automatically. Switch
exec/process stratum, instead relying on the target stack
to propagate relevant changes (stop, section table
changed, ...) up to other layers. */
+#ifdef SOLIB_ADD
SOLIB_ADD (NULL, 0, ¤t_target, auto_solib_add);
+#else
+ solib_add (NULL, 0, ¤t_target, auto_solib_add);
+#endif
target_terminal_inferior ();
+ /* 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
+ dynamically loaded objects (among other things). */
+ if (stop_on_solib_events)
+ {
+ stop_stepping (ecs);
+ return;
+ }
+
+ /* NOTE drow/2007-05-11: This might be a good place to check
+ for "catch load". */
+
/* Reinsert breakpoints and continue. */
- if (breakpoints_inserted)
- insert_breakpoints ();
+ if (breakpoints_were_inserted)
+ {
+ insert_breakpoints ();
+ breakpoints_inserted = 1;
+ }
+ }
+
+ /* If we are skipping through a shell, or through shared library
+ loading that we aren't interested in, resume the program. If
+ we're running the program normally, also resume. But stop if
+ we're attaching or setting up a remote connection. */
+ if (stop_soon == STOP_QUIETLY || stop_soon == NO_STOP_QUIETLY)
+ {
+ resume (0, TARGET_SIGNAL_0);
+ prepare_to_wait (ecs);
+ return;
}
-#endif
- resume (0, TARGET_SIGNAL_0);
- prepare_to_wait (ecs);
- return;
+
+ break;
case TARGET_WAITKIND_SPURIOUS:
if (debug_infrun)
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;
stepping_past_singlestep_breakpoint = 0;
+ if (stepping_past_breakpoint)
+ {
+ stepping_past_breakpoint = 0;
+
+ /* If we stopped for some other reason than single-stepping, ignore
+ the fact that we were supposed to switch back. */
+ if (stop_signal == TARGET_SIGNAL_TRAP)
+ {
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: stepping_past_breakpoint\n");
+
+ /* Pull the single step breakpoints out of the target. */
+ if (singlestep_breakpoints_inserted_p)
+ {
+ remove_single_step_breakpoints ();
+ singlestep_breakpoints_inserted_p = 0;
+ }
+
+ /* Note: We do not call context_switch at this point, as the
+ context is already set up for stepping the original thread. */
+ switch_to_thread (stepping_past_breakpoint_ptid);
+ /* Suppress spurious "Switching to ..." message. */
+ previous_inferior_ptid = inferior_ptid;
+
+ resume (1, TARGET_SIGNAL_0);
+ prepare_to_wait (ecs);
+ return;
+ }
+ }
+
/* 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. */
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;
&& (stop_signal == TARGET_SIGNAL_ILL
|| stop_signal == TARGET_SIGNAL_SEGV
|| stop_signal == TARGET_SIGNAL_EMT))
- || stop_soon == STOP_QUIETLY || stop_soon == STOP_QUIETLY_NO_SIGSTOP)
+ || stop_soon == STOP_QUIETLY || stop_soon == STOP_QUIETLY_NO_SIGSTOP
+ || stop_soon == STOP_QUIETLY_REMOTE)
{
if (stop_signal == TARGET_SIGNAL_TRAP && stop_after_trap)
{
/* This is originated from start_remote(), start_inferior() and
shared libraries hook functions. */
- if (stop_soon == STOP_QUIETLY)
+ if (stop_soon == STOP_QUIETLY || stop_soon == STOP_QUIETLY_REMOTE)
{
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: quietly stopped\n");
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;
}
{
struct symtab_and_line sr_sal;
+ gdb_assert (return_frame != NULL);
init_sal (&sr_sal); /* initialize to zeros */
sr_sal.pc = gdbarch_addr_bits_remove
switch (bpstat_ret)
{
case PRINT_UNKNOWN:
+ /* If we had hit a shared library event breakpoint,
+ bpstat_print would print out this message. If we hit
+ an OS-level shared library event, do the same
+ thing. */
+ if (last.kind == TARGET_WAITKIND_LOADED)
+ {
+ printf_filtered (_("Stopped due to shared library event\n"));
+ source_flag = SRC_LINE; /* something bogus */
+ do_frame_printing = 0;
+ break;
+ }
+
/* 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. */