gdb/
[deliverable/binutils-gdb.git] / gdb / infrun.c
index 1a8556775ac7afff589c4f78765bd18fb147549c..85d889a5a29f043a2ca653faa8614745a46abeea 100644 (file)
@@ -583,15 +583,41 @@ a command like `return' or `jump' to continue execution."));
 
       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;
        }
 
@@ -881,6 +907,7 @@ enum infwait_states
 {
   infwait_normal_state,
   infwait_thread_hop_state,
+  infwait_step_watch_state,
   infwait_nonstep_watch_state
 };
 
@@ -1220,17 +1247,12 @@ adjust_pc_after_break (struct execution_control_state *ecs)
    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;
@@ -1250,7 +1272,14 @@ handle_inferior_event (struct execution_control_state *ecs)
     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:
@@ -1337,10 +1366,6 @@ handle_inferior_event (struct execution_control_state *ecs)
 #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
@@ -1439,7 +1464,7 @@ handle_inferior_event (struct execution_control_state *ecs)
 
       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);
 
@@ -1487,7 +1512,7 @@ handle_inferior_event (struct execution_control_state *ecs)
       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;
@@ -1800,24 +1825,20 @@ handle_inferior_event (struct execution_control_state *ecs)
       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
@@ -1827,31 +1848,31 @@ handle_inferior_event (struct execution_control_state *ecs)
 
          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;
@@ -1973,8 +1994,7 @@ handle_inferior_event (struct execution_control_state *ecs)
       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.  */
@@ -2276,10 +2296,6 @@ process_event_stop_test:
 #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
@@ -2736,8 +2752,10 @@ process_event_stop_test:
      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;
   }
 
This page took 0.028984 seconds and 4 git commands to generate.