aboutsummaryrefslogtreecommitdiff
path: root/gdb/infrun.c
diff options
context:
space:
mode:
authorDaniel Jacobowitz <drow@false.org>2004-02-16 20:49:51 +0000
committerDaniel Jacobowitz <drow@false.org>2004-02-16 20:49:51 +0000
commit9f976b41d7cc6d186b6ceda2658feee5016d3348 (patch)
tree4dd25a1f707e0c0a1cd5070630b538a3771d172c /gdb/infrun.c
parentf090b9b105484e447876f776f78153adab214f70 (diff)
downloadfsf-binutils-gdb-9f976b41d7cc6d186b6ceda2658feee5016d3348.zip
fsf-binutils-gdb-9f976b41d7cc6d186b6ceda2658feee5016d3348.tar.gz
fsf-binutils-gdb-9f976b41d7cc6d186b6ceda2658feee5016d3348.tar.bz2
* Makefile.in (infrun.o): Add $(gdb_assert_h).
* infrun.c: Include "gdb_assert.h". (singlestep_ptid, saved_singlestep_ptid) (stepping_past_singlestep_breakpoint): New variables. (resume): Set singlestep_ptid. Check for singlestep thread hop. (init_wait_for_inferior): Clear stepping_past_singlestep_breakpoint. (handle_inferior_event): Handle singlestep thread hop.
Diffstat (limited to 'gdb/infrun.c')
-rw-r--r--gdb/infrun.c76
1 files changed, 74 insertions, 2 deletions
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 3d41f42..6bbee5e 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -44,6 +44,7 @@
#include "value.h"
#include "observer.h"
#include "language.h"
+#include "gdb_assert.h"
/* Prototypes for local functions */
@@ -474,6 +475,14 @@ follow_exec (int pid, char *execd_pathname)
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;
+
+/* The thread we inserted single-step breakpoints for. */
+static ptid_t singlestep_ptid;
+
+/* 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;
/* Things to clean up if we QUIT out of resume (). */
@@ -560,6 +569,7 @@ resume (int step, enum target_signal sig)
/* and do not pull these breakpoints until after a `wait' in
`wait_for_inferior' */
singlestep_breakpoints_inserted_p = 1;
+ singlestep_ptid = inferior_ptid;
}
/* Handle any optimized stores to the inferior NOW... */
@@ -597,7 +607,8 @@ resume (int step, enum target_signal sig)
resume_ptid = RESUME_ALL; /* Default */
if ((step || singlestep_breakpoints_inserted_p) &&
- !breakpoints_inserted && breakpoint_here_p (read_pc ()))
+ (stepping_past_singlestep_breakpoint
+ || (!breakpoints_inserted && breakpoint_here_p (read_pc ()))))
{
/* Stepping past a breakpoint without inserting breakpoints.
Make sure only the current thread gets to step, so that
@@ -896,6 +907,8 @@ init_wait_for_inferior (void)
number_of_threads_in_syscalls = 0;
clear_proceed_status ();
+
+ stepping_past_singlestep_breakpoint = 0;
}
static void
@@ -1739,12 +1752,46 @@ handle_inferior_event (struct execution_control_state *ecs)
stop_pc = read_pc_pid (ecs->ptid);
+ if (stepping_past_singlestep_breakpoint)
+ {
+ gdb_assert (SOFTWARE_SINGLE_STEP_P () && 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 (stop_signal == TARGET_SIGNAL_TRAP)
+ {
+ /* Pull the single step breakpoints out of the target. */
+ SOFTWARE_SINGLE_STEP (0, 0);
+ singlestep_breakpoints_inserted_p = 0;
+
+ ecs->random_signal = 0;
+
+ ecs->ptid = saved_singlestep_ptid;
+ context_switch (ecs);
+ if (context_hook)
+ context_hook (pid_to_thread_id (ecs->ptid));
+
+ resume (1, TARGET_SIGNAL_0);
+ prepare_to_wait (ecs);
+ return;
+ }
+ }
+
+ stepping_past_singlestep_breakpoint = 0;
+
/* 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 (stop_signal == TARGET_SIGNAL_TRAP)
{
+ int thread_hop_needed = 0;
+
/* 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. */
@@ -1752,12 +1799,38 @@ handle_inferior_event (struct execution_control_state *ecs)
{
ecs->random_signal = 0;
if (!breakpoint_thread_match (stop_pc, ecs->ptid))
+ thread_hop_needed = 1;
+ }
+ else if (SOFTWARE_SINGLE_STEP_P () && singlestep_breakpoints_inserted_p)
+ {
+ ecs->random_signal = 0;
+ /* 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))
+ {
+ thread_hop_needed = 1;
+ stepping_past_singlestep_breakpoint = 1;
+ saved_singlestep_ptid = singlestep_ptid;
+ }
+ }
+
+ if (thread_hop_needed)
{
int remove_status;
/* Saw a breakpoint, but it was hit by the wrong thread.
Just continue. */
+ if (SOFTWARE_SINGLE_STEP_P () && singlestep_breakpoints_inserted_p)
+ {
+ /* Pull the single step breakpoints out of the target. */
+ SOFTWARE_SINGLE_STEP (0, 0);
+ singlestep_breakpoints_inserted_p = 0;
+ }
+
remove_status = remove_breakpoints ();
/* Did we fail to remove breakpoints? If so, try
to set the PC past the bp. (There's at least
@@ -1799,7 +1872,6 @@ handle_inferior_event (struct execution_control_state *ecs)
registers_changed ();
return;
}
- }
}
else if (SOFTWARE_SINGLE_STEP_P () && singlestep_breakpoints_inserted_p)
{