PR python/17372 - Python hangs when displaying help()
[deliverable/binutils-gdb.git] / gdb / infrun.c
index 8137eb38d3443be9c54dbb907527a8bcaac65e64..e25f392fd989dea768ea01e8801abc0dc4711f80 100644 (file)
@@ -24,7 +24,6 @@
 #include "symtab.h"
 #include "frame.h"
 #include "inferior.h"
-#include "exceptions.h"
 #include "breakpoint.h"
 #include "gdb_wait.h"
 #include "gdbcore.h"
@@ -378,8 +377,6 @@ static void context_switch (ptid_t ptid);
 
 void init_thread_stepping_state (struct thread_info *tss);
 
-static void init_infwait_state (void);
-
 static const char follow_fork_mode_child[] = "child";
 static const char follow_fork_mode_parent[] = "parent";
 
@@ -461,10 +458,11 @@ holding the child stopped.  Try \"set detach-on-fork\" or \
 
          if (info_verbose || debug_infrun)
            {
-             target_terminal_ours ();
+             target_terminal_ours_for_output ();
              fprintf_filtered (gdb_stdlog,
-                               "Detaching after fork from "
-                               "child process %d.\n",
+                               _("Detaching after %s from "
+                                 "child process %d.\n"),
+                               has_vforked ? "vfork" : "fork",
                                child_pid);
            }
        }
@@ -549,17 +547,13 @@ holding the child stopped.  Try \"set detach-on-fork\" or \
 
       if (info_verbose || debug_infrun)
        {
-         target_terminal_ours ();
-         if (has_vforked)
-           fprintf_filtered (gdb_stdlog,
-                             _("Attaching after process %d "
-                               "vfork to child process %d.\n"),
-                             parent_pid, child_pid);
-         else
-           fprintf_filtered (gdb_stdlog,
-                             _("Attaching after process %d "
-                               "fork to child process %d.\n"),
-                             parent_pid, child_pid);
+         target_terminal_ours_for_output ();
+         fprintf_filtered (gdb_stdlog,
+                           _("Attaching after process %d "
+                             "%s to child process %d.\n"),
+                           parent_pid,
+                           has_vforked ? "vfork" : "fork",
+                           child_pid);
        }
 
       /* Add the new inferior first, so that the target_detach below
@@ -596,7 +590,18 @@ holding the child stopped.  Try \"set detach-on-fork\" or \
          parent_inf->waiting_for_vfork_done = 0;
        }
       else if (detach_fork)
-       target_detach (NULL, 0);
+       {
+         if (info_verbose || debug_infrun)
+           {
+             target_terminal_ours_for_output ();
+             fprintf_filtered (gdb_stdlog,
+                               _("Detaching after fork from "
+                                 "child process %d.\n"),
+                               child_pid);
+           }
+
+         target_detach (NULL, 0);
+       }
 
       /* Note that the detach above makes PARENT_INF dangling.  */
 
@@ -930,18 +935,22 @@ handle_vfork_child_exec_or_exit (int exec)
 
          if (debug_infrun || info_verbose)
            {
-             target_terminal_ours ();
+             target_terminal_ours_for_output ();
 
              if (exec)
-               fprintf_filtered (gdb_stdlog,
-                                 "Detaching vfork parent process "
-                                 "%d after child exec.\n",
-                                 inf->vfork_parent->pid);
+               {
+                 fprintf_filtered (gdb_stdlog,
+                                   _("Detaching vfork parent process "
+                                     "%d after child exec.\n"),
+                                   inf->vfork_parent->pid);
+               }
              else
-               fprintf_filtered (gdb_stdlog,
-                                 "Detaching vfork parent process "
-                                 "%d after child exit.\n",
-                                 inf->vfork_parent->pid);
+               {
+                 fprintf_filtered (gdb_stdlog,
+                                   _("Detaching vfork parent process "
+                                     "%d after child exit.\n"),
+                                   inf->vfork_parent->pid);
+               }
            }
 
          target_detach (NULL, 0);
@@ -1085,6 +1094,7 @@ follow_exec (ptid_t pid, char *execd_pathname)
      statement through an exec().  */
   th->control.step_resume_breakpoint = NULL;
   th->control.exception_resume_breakpoint = NULL;
+  th->control.single_step_breakpoints = NULL;
   th->control.step_range_start = 0;
   th->control.step_range_end = 0;
 
@@ -1198,27 +1208,20 @@ follow_exec (ptid_t pid, char *execd_pathname)
      matically get reset there in the new process.).  */
 }
 
-/* Non-zero if we just simulating a single-step.  This is needed
-   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;
-
-/* PC when we started this single-step.  */
-static CORE_ADDR singlestep_pc;
-
-/* Info about an instruction that is being stepped over.  Invalid if
-   ASPACE is NULL.  */
+/* Info about an instruction that is being stepped over.  */
 
 struct step_over_info
 {
-  /* The instruction's address space.  */
+  /* If we're stepping past a breakpoint, this is the address space
+     and address of the instruction the breakpoint is set at.  We'll
+     skip inserting all breakpoints here.  Valid iff ASPACE is
+     non-NULL.  */
   struct address_space *aspace;
-
-  /* The instruction's address.  */
   CORE_ADDR address;
+
+  /* The instruction being stepped over triggers a nonsteppable
+     watchpoint.  If true, we'll skip inserting watchpoints.  */
+  int nonsteppable_watchpoint_p;
 };
 
 /* The step-over info of the location that is being stepped over.
@@ -1251,10 +1254,12 @@ static struct step_over_info step_over_info;
    stepping over.  */
 
 static void
-set_step_over_info (struct address_space *aspace, CORE_ADDR address)
+set_step_over_info (struct address_space *aspace, CORE_ADDR address,
+                   int nonsteppable_watchpoint_p)
 {
   step_over_info.aspace = aspace;
   step_over_info.address = address;
+  step_over_info.nonsteppable_watchpoint_p = nonsteppable_watchpoint_p;
 }
 
 /* Called when we're not longer stepping over a breakpoint / an
@@ -1265,6 +1270,7 @@ clear_step_over_info (void)
 {
   step_over_info.aspace = NULL;
   step_over_info.address = 0;
+  step_over_info.nonsteppable_watchpoint_p = 0;
 }
 
 /* See infrun.h.  */
@@ -1279,6 +1285,23 @@ stepping_past_instruction_at (struct address_space *aspace,
                                       step_over_info.address));
 }
 
+/* See infrun.h.  */
+
+int
+stepping_past_nonsteppable_watchpoint (void)
+{
+  return step_over_info.nonsteppable_watchpoint_p;
+}
+
+/* Returns true if step-over info is valid.  */
+
+static int
+step_over_info_valid_p (void)
+{
+  return (step_over_info.aspace != NULL
+         || stepping_past_nonsteppable_watchpoint ());
+}
+
 \f
 /* Displaced stepping.  */
 
@@ -1874,9 +1897,6 @@ infrun_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid)
   if (ptid_equal (inferior_ptid, old_ptid))
     inferior_ptid = new_ptid;
 
-  if (ptid_equal (singlestep_ptid, old_ptid))
-    singlestep_ptid = new_ptid;
-
   for (displaced = displaced_step_inferior_states;
        displaced;
        displaced = displaced->next)
@@ -1897,6 +1917,9 @@ infrun_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid)
 static void
 resume_cleanups (void *ignore)
 {
+  if (!ptid_equal (inferior_ptid, null_ptid))
+    delete_single_step_breakpoints (inferior_thread ());
+
   normal_stop ();
 }
 
@@ -1951,11 +1974,6 @@ maybe_software_singlestep (struct gdbarch *gdbarch, CORE_ADDR pc)
       && gdbarch_software_single_step (gdbarch, get_current_frame ()))
     {
       hw_step = 0;
-      /* Do not pull these breakpoints until after a `wait' in
-        `wait_for_inferior'.  */
-      singlestep_breakpoints_inserted_p = 1;
-      singlestep_ptid = inferior_ptid;
-      singlestep_pc = pc;
     }
   return hw_step;
 }
@@ -2083,8 +2101,7 @@ a command like `return' or `jump' to continue execution."));
      event, displaced stepping breaks the vfork child similarly as single
      step software breakpoint.  */
   if (use_displaced_stepping (gdbarch)
-      && (tp->control.trap_expected
-         || (step && gdbarch_software_single_step_p (gdbarch)))
+      && tp->control.trap_expected
       && sig == GDB_SIGNAL_0
       && !current_inferior ()->waiting_for_vfork_done)
     {
@@ -2143,8 +2160,9 @@ a command like `return' or `jump' to continue execution."));
      at the current address, deliver the signal without stepping, and
      once we arrive back at the step-resume breakpoint, actually step
      over the breakpoint we originally wanted to step over.  */
-  if (singlestep_breakpoints_inserted_p
-      && tp->control.trap_expected && sig != GDB_SIGNAL_0)
+  if (thread_has_single_step_breakpoints_set (tp)
+      && sig != GDB_SIGNAL_0
+      && step_over_info_valid_p ())
     {
       /* If we have nested signals or a pending signal is delivered
         immediately after a handler returns, might might already have
@@ -2157,8 +2175,7 @@ a command like `return' or `jump' to continue execution."));
          tp->step_after_step_resume_breakpoint = 1;
        }
 
-      remove_single_step_breakpoints ();
-      singlestep_breakpoints_inserted_p = 0;
+      delete_single_step_breakpoints (tp);
 
       clear_step_over_info ();
       tp->control.trap_expected = 0;
@@ -2169,7 +2186,7 @@ a command like `return' or `jump' to continue execution."));
   /* 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));
+  gdb_assert (!(thread_has_single_step_breakpoints_set (tp) && step));
 
   /* Decide the set of threads to ask the target to resume.  Start
      by assuming everything will be resumed, than narrow the set
@@ -2185,7 +2202,7 @@ a command like `return' or `jump' to continue execution."));
     set_running (resume_ptid, 1);
 
   /* Maybe resume a single thread after all.  */
-  if ((step || singlestep_breakpoints_inserted_p)
+  if ((step || thread_has_single_step_breakpoints_set (tp))
       && tp->control.trap_expected)
     {
       /* We're allowing a thread to run past a breakpoint it has
@@ -2196,12 +2213,35 @@ a command like `return' or `jump' to continue execution."));
       resume_ptid = inferior_ptid;
     }
 
-  if (gdbarch_cannot_step_breakpoint (gdbarch))
-    {
+  if (execution_direction != EXEC_REVERSE
+      && step && breakpoint_inserted_here_p (aspace, pc))
+    {
+      /* The only case we currently need to step a breakpoint
+        instruction is when we have a signal to deliver.  See
+        handle_signal_stop where we handle random signals that could
+        take out us out of the stepping range.  Normally, in that
+        case we end up continuing (instead of stepping) over the
+        signal handler with a breakpoint at PC, but there are cases
+        where we should _always_ single-step, even if we have a
+        step-resume breakpoint, like when a software watchpoint is
+        set.  Assuming single-stepping and delivering a signal at the
+        same time would takes us to the signal handler, then we could
+        have removed the breakpoint at PC to step over it.  However,
+        some hardware step targets (like e.g., Mac OS) can't step
+        into signal handlers, and for those, we need to leave the
+        breakpoint at PC inserted, as otherwise if the handler
+        recurses and executes PC again, it'll miss the breakpoint.
+        So we leave the breakpoint inserted anyway, but we need to
+        record that we tried to step a breakpoint instruction, so
+        that adjust_pc_after_break doesn't end up confused.  */
+      gdb_assert (sig != GDB_SIGNAL_0);
+
+      tp->stepped_breakpoint = 1;
+
       /* Most targets can step a breakpoint instruction, thus
         executing it normally.  But if this one cannot, just
         continue and we will hit it anyway.  */
-      if (step && breakpoint_inserted_here_p (aspace, pc))
+      if (gdbarch_cannot_step_breakpoint (gdbarch))
        step = 0;
     }
 
@@ -2238,13 +2278,10 @@ a command like `return' or `jump' to continue execution."));
   tp->suspend.stop_signal = GDB_SIGNAL_0;
 
   /* Advise target which signals may be handled silently.  If we have
-     removed breakpoints because we are stepping over one (which can
-     happen only if we are not using displaced stepping), we need to
-     receive all signals to avoid accidentally skipping a breakpoint
-     during execution of a signal handler.  */
-  if ((step || singlestep_breakpoints_inserted_p)
-      && tp->control.trap_expected
-      && !use_displaced_stepping (gdbarch))
+     removed breakpoints because we are stepping over one (in any
+     thread), we need to receive all signals to avoid accidentally
+     skipping a breakpoint during execution of a signal handler.  */
+  if (step_over_info_valid_p ())
     target_pass_signals (0, NULL);
   else
     target_pass_signals ((int) GDB_SIGNAL_LAST, signal_pass);
@@ -2550,7 +2587,7 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal, int step)
       struct regcache *regcache = get_current_regcache ();
 
       set_step_over_info (get_regcache_aspace (regcache),
-                         regcache_read_pc (regcache));
+                         regcache_read_pc (regcache), 0);
     }
   else
     clear_step_over_info ();
@@ -2590,9 +2627,6 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal, int step)
      correctly when the inferior is stopped.  */
   tp->prev_pc = regcache_read_pc (get_current_regcache ());
 
-  /* Reset to normal state.  */
-  init_infwait_state ();
-
   /* Resume inferior.  */
   resume (tp->control.trap_expected || step || bpstat_should_step (),
          tp->suspend.stop_signal);
@@ -2657,13 +2691,9 @@ init_wait_for_inferior (void)
   target_last_wait_ptid = minus_one_ptid;
 
   previous_inferior_ptid = inferior_ptid;
-  init_infwait_state ();
 
   /* Discard any skipped inlined frames.  */
   clear_inline_frame_state (minus_one_ptid);
-
-  singlestep_ptid = null_ptid;
-  singlestep_pc = 0;
 }
 
 \f
@@ -2678,9 +2708,6 @@ enum infwait_states
   infwait_nonstep_watch_state
 };
 
-/* The PTID we'll do a target_wait on.*/
-ptid_t waiton_ptid;
-
 /* Current inferior wait state.  */
 static enum infwait_states infwait_state;
 
@@ -2700,11 +2727,6 @@ struct execution_control_state
   const char *stop_func_name;
   int wait_some_more;
 
-  /* We were in infwait_step_watch_state or
-     infwait_nonstep_watch_state state, and the thread reported an
-     event.  */
-  int stepped_after_stopped_by_watchpoint;
-
   /* True if the event thread hit the single-step breakpoint of
      another thread.  Thus the event doesn't cause a stop, the thread
      needs to be single-stepped past the single-step breakpoint before
@@ -2839,54 +2861,71 @@ infrun_thread_thread_exit (struct thread_info *tp, int silent)
     nullify_last_target_wait_ptid ();
 }
 
-/* Callback for iterate_over_threads.  */
+/* Delete the step resume, single-step and longjmp/exception resume
+   breakpoints of TP.  */
 
-static int
-delete_step_resume_breakpoint_callback (struct thread_info *info, void *data)
+static void
+delete_thread_infrun_breakpoints (struct thread_info *tp)
 {
-  if (is_exited (info->ptid))
-    return 0;
-
-  delete_step_resume_breakpoint (info);
-  delete_exception_resume_breakpoint (info);
-  return 0;
+  delete_step_resume_breakpoint (tp);
+  delete_exception_resume_breakpoint (tp);
+  delete_single_step_breakpoints (tp);
 }
 
-/* In all-stop, delete the step resume breakpoint of any thread that
-   had one.  In non-stop, delete the step resume breakpoint of the
-   thread that just stopped.  */
+/* If the target still has execution, call FUNC for each thread that
+   just stopped.  In all-stop, that's all the non-exited threads; in
+   non-stop, that's the current thread, only.  */
+
+typedef void (*for_each_just_stopped_thread_callback_func)
+  (struct thread_info *tp);
 
 static void
-delete_step_thread_step_resume_breakpoint (void)
+for_each_just_stopped_thread (for_each_just_stopped_thread_callback_func func)
 {
-  if (!target_has_execution
-      || ptid_equal (inferior_ptid, null_ptid))
-    /* If the inferior has exited, we have already deleted the step
-       resume breakpoints out of GDB's lists.  */
+  if (!target_has_execution || ptid_equal (inferior_ptid, null_ptid))
     return;
 
   if (non_stop)
     {
-      /* If in non-stop mode, only delete the step-resume or
-        longjmp-resume breakpoint of the thread that just stopped
-        stepping.  */
-      struct thread_info *tp = inferior_thread ();
-
-      delete_step_resume_breakpoint (tp);
-      delete_exception_resume_breakpoint (tp);
+      /* If in non-stop mode, only the current thread stopped.  */
+      func (inferior_thread ());
     }
   else
-    /* In all-stop mode, delete all step-resume and longjmp-resume
-       breakpoints of any thread that had them.  */
-    iterate_over_threads (delete_step_resume_breakpoint_callback, NULL);
+    {
+      struct thread_info *tp;
+
+      /* In all-stop mode, all threads have stopped.  */
+      ALL_NON_EXITED_THREADS (tp)
+        {
+         func (tp);
+       }
+    }
+}
+
+/* Delete the step resume and longjmp/exception resume breakpoints of
+   the threads that just stopped.  */
+
+static void
+delete_just_stopped_threads_infrun_breakpoints (void)
+{
+  for_each_just_stopped_thread (delete_thread_infrun_breakpoints);
+}
+
+/* Delete the single-step breakpoints of the threads that just
+   stopped.  */
+
+static void
+delete_just_stopped_threads_single_step_breakpoints (void)
+{
+  for_each_just_stopped_thread (delete_single_step_breakpoints);
 }
 
 /* A cleanup wrapper.  */
 
 static void
-delete_step_thread_step_resume_breakpoint_cleanup (void *arg)
+delete_just_stopped_threads_infrun_breakpoints_cleanup (void *arg)
 {
-  delete_step_thread_step_resume_breakpoint ();
+  delete_just_stopped_threads_infrun_breakpoints ();
 }
 
 /* Pretty print the results of target_wait, for debugging purposes.  */
@@ -3021,14 +3060,16 @@ wait_for_inferior (void)
     fprintf_unfiltered
       (gdb_stdlog, "infrun: wait_for_inferior ()\n");
 
-  old_cleanups =
-    make_cleanup (delete_step_thread_step_resume_breakpoint_cleanup, NULL);
+  old_cleanups
+    = make_cleanup (delete_just_stopped_threads_infrun_breakpoints_cleanup,
+                   NULL);
 
   while (1)
     {
       struct execution_control_state ecss;
       struct execution_control_state *ecs = &ecss;
       struct cleanup *old_chain;
+      ptid_t waiton_ptid = minus_one_ptid;
 
       memset (ecs, 0, sizeof (*ecs));
 
@@ -3066,6 +3107,23 @@ wait_for_inferior (void)
   do_cleanups (old_cleanups);
 }
 
+/* Cleanup that reinstalls the readline callback handler, if the
+   target is running in the background.  If while handling the target
+   event something triggered a secondary prompt, like e.g., a
+   pagination prompt, we'll have removed the callback handler (see
+   gdb_readline_wrapper_line).  Need to do this as we go back to the
+   event loop, ready to process further input.  Note this has no
+   effect if the handler hasn't actually been removed, because calling
+   rl_callback_handler_install resets the line buffer, thus losing
+   input.  */
+
+static void
+reinstall_readline_callback_handler_cleanup (void *arg)
+{
+  if (async_command_editing_p && !sync_execution)
+    gdb_rl_callback_handler_reinstall ();
+}
+
 /* Asynchronous version of wait_for_inferior.  It is called by the
    event loop whenever a change of state is detected on the file
    descriptor corresponding to the target.  It can be called more than
@@ -3084,9 +3142,13 @@ fetch_inferior_event (void *client_data)
   struct cleanup *ts_old_chain;
   int was_sync = sync_execution;
   int cmd_done = 0;
+  ptid_t waiton_ptid = minus_one_ptid;
 
   memset (ecs, 0, sizeof (*ecs));
 
+  /* End up with readline processing input, if necessary.  */
+  make_cleanup (reinstall_readline_callback_handler_cleanup, NULL);
+
   /* We're handling a live event, so make sure we're doing live
      debugging.  If we're looking at traceframes while the target is
      running, we're going to need to get back to that mode after
@@ -3135,6 +3197,8 @@ fetch_inferior_event (void *client_data)
      still for the thread which has thrown the exception.  */
   make_bpstat_clear_actions_cleanup ();
 
+  make_cleanup (delete_just_stopped_threads_infrun_breakpoints_cleanup, NULL);
+
   /* Now figure out what to do with the result of the result.  */
   handle_inferior_event (ecs);
 
@@ -3142,7 +3206,7 @@ fetch_inferior_event (void *client_data)
     {
       struct inferior *inf = find_inferior_pid (ptid_get_pid (ecs->ptid));
 
-      delete_step_thread_step_resume_breakpoint ();
+      delete_just_stopped_threads_infrun_breakpoints ();
 
       /* We may not find an inferior if this was a process exit.  */
       if (inf == NULL || inf->control.stop_soon == NO_STOP_QUIETLY)
@@ -3200,7 +3264,9 @@ set_step_info (struct frame_info *frame, struct symtab_and_line sal)
 void
 init_thread_stepping_state (struct thread_info *tss)
 {
+  tss->stepped_breakpoint = 0;
   tss->stepping_over_breakpoint = 0;
+  tss->stepping_over_watchpoint = 0;
   tss->step_after_step_resume_breakpoint = 0;
 }
 
@@ -3360,23 +3426,17 @@ adjust_pc_after_break (struct execution_control_state *ecs)
         software breakpoint.  In this case (prev_pc == breakpoint_pc),
         we also need to back up to the breakpoint address.  */
 
-      if (singlestep_breakpoints_inserted_p
+      if (thread_has_single_step_breakpoints_set (ecs->event_thread)
          || !ptid_equal (ecs->ptid, inferior_ptid)
          || !currently_stepping (ecs->event_thread)
-         || ecs->event_thread->prev_pc == breakpoint_pc)
+         || (ecs->event_thread->stepped_breakpoint
+             && ecs->event_thread->prev_pc == breakpoint_pc))
        regcache_write_pc (regcache, breakpoint_pc);
 
       do_cleanups (old_cleanups);
     }
 }
 
-static void
-init_infwait_state (void)
-{
-  waiton_ptid = pid_to_ptid (-1);
-  infwait_state = infwait_normal_state;
-}
-
 static int
 stepped_in_from (struct frame_info *frame, struct frame_id step_frame_id)
 {
@@ -3597,40 +3657,6 @@ handle_inferior_event (struct execution_control_state *ecs)
           && ecs->ws.kind != TARGET_WAITKIND_EXITED)
     set_executing (ecs->ptid, 0);
 
-  switch (infwait_state)
-    {
-    case infwait_normal_state:
-      if (debug_infrun)
-        fprintf_unfiltered (gdb_stdlog, "infrun: infwait_normal_state\n");
-      break;
-
-    case infwait_step_watch_state:
-      if (debug_infrun)
-        fprintf_unfiltered (gdb_stdlog,
-                           "infrun: infwait_step_watch_state\n");
-
-      ecs->stepped_after_stopped_by_watchpoint = 1;
-      break;
-
-    case infwait_nonstep_watch_state:
-      if (debug_infrun)
-        fprintf_unfiltered (gdb_stdlog,
-                           "infrun: infwait_nonstep_watch_state\n");
-      insert_breakpoints ();
-
-      /* FIXME-maybe: is this cleaner than setting a flag?  Does it
-         handle things like signals arriving and other things happening
-         in combination correctly?  */
-      ecs->stepped_after_stopped_by_watchpoint = 1;
-      break;
-
-    default:
-      internal_error (__FILE__, __LINE__, _("bad switch"));
-    }
-
-  infwait_state = infwait_normal_state;
-  waiton_ptid = pid_to_ptid (-1);
-
   switch (ecs->ws.kind)
     {
     case TARGET_WAITKIND_LOADED:
@@ -3787,8 +3813,6 @@ Cannot fill $_exitsignal with the correct signal number.\n"));
 
       gdb_flush (gdb_stdout);
       target_mourn_inferior ();
-      singlestep_breakpoints_inserted_p = 0;
-      cancel_single_step_breakpoints ();
       stop_print_frame = 0;
       stop_waiting (ecs);
       return;
@@ -3881,12 +3905,7 @@ Cannot fill $_exitsignal with the correct signal number.\n"));
          detach_breakpoints (ecs->ws.value.related_pid);
        }
 
-      if (singlestep_breakpoints_inserted_p)
-       {
-         /* Pull the single step breakpoints out of the target.  */
-         remove_single_step_breakpoints ();
-         singlestep_breakpoints_inserted_p = 0;
-       }
+      delete_just_stopped_threads_single_step_breakpoints ();
 
       /* In case the event is caught by a catchpoint, remember that
         the event is to be followed at the next resume of the thread,
@@ -3973,9 +3992,6 @@ Cannot fill $_exitsignal with the correct signal number.\n"));
       if (!ptid_equal (ecs->ptid, inferior_ptid))
        context_switch (ecs->ptid);
 
-      singlestep_breakpoints_inserted_p = 0;
-      cancel_single_step_breakpoints ();
-
       stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid));
 
       /* Do whatever is necessary to the parent branch of the vfork.  */
@@ -4041,14 +4057,7 @@ Cannot fill $_exitsignal with the correct signal number.\n"));
         fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_NO_HISTORY\n");
       /* Reverse execution: target ran out of history info.  */
 
-      /* Pull the single step breakpoints out of the target.  */
-      if (singlestep_breakpoints_inserted_p)
-       {
-         if (!ptid_equal (ecs->ptid, inferior_ptid))
-           context_switch (ecs->ptid);
-         remove_single_step_breakpoints ();
-         singlestep_breakpoints_inserted_p = 0;
-       }
+      delete_just_stopped_threads_single_step_breakpoints ();
       stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid));
       observer_notify_no_history ();
       stop_waiting (ecs);
@@ -4187,13 +4196,9 @@ handle_signal_stop (struct execution_control_state *ecs)
   gdbarch = get_frame_arch (frame);
 
   /* Pull the single step breakpoints out of the target.  */
-  if (singlestep_breakpoints_inserted_p)
+  if (gdbarch_software_single_step_p (gdbarch))
     {
-      /* However, before doing so, if this single-step breakpoint was
-        actually for another thread, set this thread up for moving
-        past it.  */
-      if (!ptid_equal (ecs->ptid, singlestep_ptid)
-         && ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP)
+      if (ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP)
        {
          struct regcache *regcache;
          struct address_space *aspace;
@@ -4202,25 +4207,43 @@ handle_signal_stop (struct execution_control_state *ecs)
          regcache = get_thread_regcache (ecs->ptid);
          aspace = get_regcache_aspace (regcache);
          pc = regcache_read_pc (regcache);
-         if (single_step_breakpoint_inserted_here_p (aspace, pc))
+
+         /* However, before doing so, if this single-step breakpoint was
+            actually for another thread, set this thread up for moving
+            past it.  */
+         if (!thread_has_single_step_breakpoint_here (ecs->event_thread,
+                                                      aspace, pc))
+           {
+             if (single_step_breakpoint_inserted_here_p (aspace, pc))
+               {
+                 if (debug_infrun)
+                   {
+                     fprintf_unfiltered (gdb_stdlog,
+                                         "infrun: [%s] hit another thread's "
+                                         "single-step breakpoint\n",
+                                         target_pid_to_str (ecs->ptid));
+                   }
+                 ecs->hit_singlestep_breakpoint = 1;
+               }
+           }
+         else
            {
              if (debug_infrun)
                {
                  fprintf_unfiltered (gdb_stdlog,
-                                     "infrun: [%s] hit step over single-step"
-                                     " breakpoint of [%s]\n",
-                                     target_pid_to_str (ecs->ptid),
-                                     target_pid_to_str (singlestep_ptid));
+                                     "infrun: [%s] hit its "
+                                     "single-step breakpoint\n",
+                                     target_pid_to_str (ecs->ptid));
                }
-             ecs->hit_singlestep_breakpoint = 1;
            }
        }
 
-      remove_single_step_breakpoints ();
-      singlestep_breakpoints_inserted_p = 0;
+      delete_just_stopped_threads_single_step_breakpoints ();
     }
 
-  if (ecs->stepped_after_stopped_by_watchpoint)
+  if (ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP
+      && ecs->event_thread->control.trap_expected
+      && ecs->event_thread->stepping_over_watchpoint)
     stopped_by_watchpoint = 0;
   else
     stopped_by_watchpoint = watchpoints_triggered (&ecs->ws);
@@ -4250,29 +4273,22 @@ handle_signal_stop (struct execution_control_state *ecs)
         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.  */
-      int hw_step = 1;
-
-      if (!target_have_steppable_watchpoint)
-       {
-         remove_breakpoints ();
-         /* See comment in resume why we need to stop bypassing signals
-            while breakpoints have been removed.  */
-         target_pass_signals (0, NULL);
-       }
-       /* Single step */
-      hw_step = maybe_software_singlestep (gdbarch, stop_pc);
-      target_resume (ecs->ptid, hw_step, GDB_SIGNAL_0);
-      waiton_ptid = ecs->ptid;
-      if (target_have_steppable_watchpoint)
-       infwait_state = infwait_step_watch_state;
-      else
-       infwait_state = infwait_nonstep_watch_state;
-      prepare_to_wait (ecs);
+        disable all watchpoints.
+
+        Any breakpoint at PC must also be stepped over -- if there's
+        one, it will have already triggered before the watchpoint
+        triggered, and we either already reported it to the user, or
+        it didn't cause a stop and we called keep_going.  In either
+        case, if there was a breakpoint at PC, we must be trying to
+        step past it.  */
+      ecs->event_thread->stepping_over_watchpoint = 1;
+      keep_going (ecs);
       return;
     }
 
+  ecs->event_thread->stepped_breakpoint = 0;
   ecs->event_thread->stepping_over_breakpoint = 0;
+  ecs->event_thread->stepping_over_watchpoint = 0;
   bpstat_clear (&ecs->event_thread->control.stop_bpstat);
   ecs->event_thread->control.stop_step = 0;
   stop_print_frame = 1;
@@ -4426,7 +4442,6 @@ handle_signal_stop (struct execution_control_state *ecs)
   if (random_signal)
     {
       /* Signal not for debugging purposes.  */
-      int printed = 0;
       struct inferior *inf = find_inferior_pid (ptid_get_pid (ecs->ptid));
       enum gdb_signal stop_signal = ecs->event_thread->suspend.stop_signal;
 
@@ -4494,9 +4509,9 @@ handle_signal_stop (struct execution_control_state *ecs)
          return;
        }
 
-      if (ecs->event_thread->control.step_range_end != 0
-         && ecs->event_thread->suspend.stop_signal != GDB_SIGNAL_0
-         && pc_in_thread_step_range (stop_pc, ecs->event_thread)
+      if (ecs->event_thread->suspend.stop_signal != GDB_SIGNAL_0
+         && (pc_in_thread_step_range (stop_pc, ecs->event_thread)
+             || ecs->event_thread->control.step_range_end == 1)
          && frame_id_eq (get_stack_frame_id (frame),
                          ecs->event_thread->control.step_stack_frame_id)
          && ecs->event_thread->control.step_resume_breakpoint == NULL)
@@ -4516,6 +4531,7 @@ handle_signal_stop (struct execution_control_state *ecs)
                                 "single-step range\n");
 
          insert_hp_step_resume_breakpoint_at_frame (frame);
+         ecs->event_thread->step_after_step_resume_breakpoint = 1;
          /* Reset trap_expected to ensure breakpoints are re-inserted.  */
          ecs->event_thread->control.trap_expected = 0;
          keep_going (ecs);
@@ -4598,7 +4614,10 @@ process_event_stop_test (struct execution_control_state *ecs)
             is the third argument to the probe.  */
          arg_value = probe_safe_evaluate_at_pc (frame, 2);
          if (arg_value)
-           jmp_buf_pc = value_as_address (arg_value);
+           {
+             jmp_buf_pc = value_as_address (arg_value);
+             jmp_buf_pc = gdbarch_addr_bits_remove (gdbarch, jmp_buf_pc);
+           }
          else if (!gdbarch_get_longjmp_target_p (gdbarch)
                   || !gdbarch_get_longjmp_target (gdbarch,
                                                   frame, &jmp_buf_pc))
@@ -5552,13 +5571,18 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs)
                fprintf_unfiltered (gdb_stdlog,
                                    "infrun: expected thread advanced also\n");
 
+             /* Clear the info of the previous step-over, as it's no
+                longer valid.  It's what keep_going would do too, if
+                we called it.  Must do this before trying to insert
+                the sss breakpoint, otherwise if we were previously
+                trying to step over this exact address in another
+                thread, the breakpoint ends up not installed.  */
+             clear_step_over_info ();
+
              insert_single_step_breakpoint (get_frame_arch (frame),
                                             get_frame_address_space (frame),
                                             stop_pc);
-             singlestep_breakpoints_inserted_p = 1;
              ecs->event_thread->control.trap_expected = 1;
-             singlestep_ptid = inferior_ptid;
-             singlestep_pc = stop_pc;
 
              resume (0, GDB_SIGNAL_0);
              prepare_to_wait (ecs);
@@ -6008,6 +6032,8 @@ keep_going (struct execution_control_state *ecs)
     {
       volatile struct gdb_exception e;
       struct regcache *regcache = get_current_regcache ();
+      int remove_bp;
+      int remove_wps;
 
       /* Either the trap was not expected, but we are continuing
         anyway (if we got a signal, the user asked it be passed to
@@ -6027,13 +6053,19 @@ keep_going (struct execution_control_state *ecs)
         (watchpoints, etc.) but the one we're stepping over, step one
         instruction, and then re-insert the breakpoint when that step
         is finished.  */
-      if ((ecs->hit_singlestep_breakpoint
-          || thread_still_needs_step_over (ecs->event_thread))
-         && !use_displaced_stepping (get_regcache_arch (regcache)))
+
+      remove_bp = (ecs->hit_singlestep_breakpoint
+                  || thread_still_needs_step_over (ecs->event_thread));
+      remove_wps = (ecs->event_thread->stepping_over_watchpoint
+                   && !target_have_steppable_watchpoint);
+
+      if (remove_bp && !use_displaced_stepping (get_regcache_arch (regcache)))
        {
          set_step_over_info (get_regcache_aspace (regcache),
-                             regcache_read_pc (regcache));
+                             regcache_read_pc (regcache), remove_wps);
        }
+      else if (remove_wps)
+       set_step_over_info (NULL, 0, remove_wps);
       else
        clear_step_over_info ();
 
@@ -6049,9 +6081,7 @@ keep_going (struct execution_control_state *ecs)
          return;
        }
 
-      ecs->event_thread->control.trap_expected
-       = (ecs->event_thread->stepping_over_breakpoint
-          || ecs->hit_singlestep_breakpoint);
+      ecs->event_thread->control.trap_expected = (remove_bp || remove_wps);
 
       /* Do not deliver GDB_SIGNAL_TRAP (except when the user
         explicitly specifies that such a signal should be delivered
@@ -6383,7 +6413,7 @@ normal_stop (void)
       && last.kind != TARGET_WAITKIND_EXITED
       && inferior_thread ()->control.stop_step)
     {
-      /* But not if if in the middle of doing a "step n" operation for
+      /* But not if in the middle of doing a "step n" operation for
         n > 1 */
       if (inferior_thread ()->step_multi)
        goto done;
This page took 0.035997 seconds and 4 git commands to generate.