* Makefile.in (infrun.o): Add $(gdb_assert_h).
authorDaniel Jacobowitz <drow@false.org>
Mon, 16 Feb 2004 20:49:51 +0000 (20:49 +0000)
committerDaniel Jacobowitz <drow@false.org>
Mon, 16 Feb 2004 20:49:51 +0000 (20:49 +0000)
* 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.

gdb/ChangeLog
gdb/Makefile.in
gdb/infrun.c

index c7d69d9..e3479dc 100644 (file)
@@ -1,3 +1,14 @@
+2004-02-16  Daniel Jacobowitz  <drow@mvista.com>
+
+       * 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.
+
 2004-02-16  Andrew Cagney  <cagney@redhat.com>
 
        * dwarf2-frame.c (dwarf2_frame_ops): New function.
index c658895..f6d33ca 100644 (file)
@@ -1851,7 +1851,7 @@ infrun.o: infrun.c $(defs_h) $(gdb_string_h) $(symtab_h) $(frame_h) \
        $(inferior_h) $(breakpoint_h) $(gdb_wait_h) $(gdbcore_h) $(gdbcmd_h) \
        $(cli_script_h) $(target_h) $(gdbthread_h) $(annotate_h) \
        $(symfile_h) $(top_h) $(inf_loop_h) $(regcache_h) $(value_h) \
-       $(observer_h) $(language_h)
+       $(observer_h) $(language_h) $(gdb_assert_h)
 inftarg.o: inftarg.c $(defs_h) $(frame_h) $(inferior_h) $(target_h) \
        $(gdbcore_h) $(command_h) $(gdb_stat_h) $(gdb_wait_h) $(inflow_h)
 infttrace.o: infttrace.c $(defs_h) $(frame_h) $(inferior_h) $(target_h) \
index 3d41f42..6bbee5e 100644 (file)
@@ -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;
 \f
 
 /* 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)
         {