[gdbserver] linux-low.c: better starvation avoidance, handle non-stop mode too
authorPedro Alves <palves@redhat.com>
Mon, 29 Dec 2014 19:41:07 +0000 (19:41 +0000)
committerPedro Alves <palves@redhat.com>
Fri, 9 Jan 2015 14:42:32 +0000 (14:42 +0000)
This patch applies the same starvation avoidance improvements of the
previous patch to the Linux gdbserver side.

Without this, the test added by the following commit
(gdb.threads/non-stop-fair-events.exp) always fails with time outs.

gdb/gdbserver/
2015-01-09  Pedro Alves  <palves@redhat.com>

* linux-low.c (step_over_bkpt): Move higher up in the file.
(handle_extended_wait): Don't store the stop_pc here.
(get_stop_pc): Adjust comments and rename to ...
(check_stopped_by_breakpoint): ... this.  Record whether the LWP
stopped for a software breakpoint or hardware breakpoint.
(thread_still_has_status_pending_p): New function.
(status_pending_p_callback): Use
thread_still_has_status_pending_p.  If the event is no longer
interesting, resume the LWP.
(handle_tracepoints): Add assert.
(maybe_move_out_of_jump_pad): Remove cancel_breakpoints call.
(wstatus_maybe_breakpoint): New function.
(cancel_breakpoint): Delete function.
(check_stopped_by_watchpoint): New function, factored out from
linux_low_filter_event.
(lp_status_maybe_breakpoint): Delete function.
(linux_low_filter_event): Remove filter_ptid argument.
Leave thread group exits pending here. Store the LWP's stop PC.
Always leave events pending.
(linux_wait_for_event_filtered): Pull all events out of the
kernel, and leave them all pending.
(count_events_callback, select_event_lwp_callback): Consider all
events.
(cancel_breakpoints_callback, linux_cancel_breakpoints): Delete.
(select_event_lwp): Only give preference to the stepping LWP in
all-stop mode. Adjust comments.
(ignore_event): New function.
(linux_wait_1): Delete 'retry' label.  Use ignore_event.  Remove
references to cancel_breakpoints.  Adjust to renames.  Also give
equal priority to all LWPs that have had events in non-stop mode.
If reporting a software breakpoint event, unadjust the LWP's PC.
(linux_wait): If linux_wait_1 returned an ignored event, retry.
(stuck_in_jump_pad_callback, move_out_of_jump_pad_callback):
Adjust.
(linux_resume_one_lwp): Store the LWP's PC.  Adjust.
(resume_status_pending_p): Use thread_still_has_status_pending_p.
(linux_stopped_by_watchpoint): Adjust.
(linux_target_ops): Remove reference to linux_cancel_breakpoints.
* linux-low.h (enum lwp_stop_reason): New.
(struct lwp_info) <stop_pc>: Adjust comment.
<stopped_by_watchpoint>: Delete field.
<stop_reason>: New field.
* linux-x86-low.c (x86_linux_prepare_to_resume): Adjust.
* mem-break.c (software_breakpoint_inserted_here)
(hardware_breakpoint_inserted_here): New function.
* mem-break.h (software_breakpoint_inserted_here)
(hardware_breakpoint_inserted_here): Declare.
* target.h (struct target_ops) <cancel_breakpoints>: Remove field.
(cancel_breakpoints): Delete.
* tracepoint.c (clear_installed_tracepoints, stop_tracing)
(upload_fast_traceframes): Remove references to
cancel_breakpoints.

gdb/gdbserver/ChangeLog
gdb/gdbserver/linux-low.c
gdb/gdbserver/linux-low.h
gdb/gdbserver/linux-x86-low.c
gdb/gdbserver/mem-break.c
gdb/gdbserver/mem-break.h
gdb/gdbserver/target.h
gdb/gdbserver/tracepoint.c

index d6bafae9b8db8487aaa13a5afdd92dee3939b083..180e341c9e264bbe8cd7d168ffbe82b0aec7f807 100644 (file)
@@ -1,3 +1,58 @@
+2015-01-09  Pedro Alves  <palves@redhat.com>
+
+       * linux-low.c (step_over_bkpt): Move higher up in the file.
+       (handle_extended_wait): Don't store the stop_pc here.
+       (get_stop_pc): Adjust comments and rename to ...
+       (check_stopped_by_breakpoint): ... this.  Record whether the LWP
+       stopped for a software breakpoint or hardware breakpoint.
+       (thread_still_has_status_pending_p): New function.
+       (status_pending_p_callback): Use
+       thread_still_has_status_pending_p.  If the event is no longer
+       interesting, resume the LWP.
+       (handle_tracepoints): Add assert.
+       (maybe_move_out_of_jump_pad): Remove cancel_breakpoints call.
+       (wstatus_maybe_breakpoint): New function.
+       (cancel_breakpoint): Delete function.
+       (check_stopped_by_watchpoint): New function, factored out from
+       linux_low_filter_event.
+       (lp_status_maybe_breakpoint): Delete function.
+       (linux_low_filter_event): Remove filter_ptid argument.
+       Leave thread group exits pending here.  Store the LWP's stop PC.
+       Always leave events pending.
+       (linux_wait_for_event_filtered): Pull all events out of the
+       kernel, and leave them all pending.
+       (count_events_callback, select_event_lwp_callback): Consider all
+       events.
+       (cancel_breakpoints_callback, linux_cancel_breakpoints): Delete.
+       (select_event_lwp): Only give preference to the stepping LWP in
+       all-stop mode.  Adjust comments.
+       (ignore_event): New function.
+       (linux_wait_1): Delete 'retry' label.  Use ignore_event.  Remove
+       references to cancel_breakpoints.  Adjust to renames.  Also give
+       equal priority to all LWPs that have had events in non-stop mode.
+       If reporting a software breakpoint event, unadjust the LWP's PC.
+       (linux_wait): If linux_wait_1 returned an ignored event, retry.
+       (stuck_in_jump_pad_callback, move_out_of_jump_pad_callback):
+       Adjust.
+       (linux_resume_one_lwp): Store the LWP's PC.  Adjust.
+       (resume_status_pending_p): Use thread_still_has_status_pending_p.
+       (linux_stopped_by_watchpoint): Adjust.
+       (linux_target_ops): Remove reference to linux_cancel_breakpoints.
+       * linux-low.h (enum lwp_stop_reason): New.
+       (struct lwp_info) <stop_pc>: Adjust comment.
+       <stopped_by_watchpoint>: Delete field.
+       <stop_reason>: New field.
+       * linux-x86-low.c (x86_linux_prepare_to_resume): Adjust.
+       * mem-break.c (software_breakpoint_inserted_here)
+       (hardware_breakpoint_inserted_here): New function.
+       * mem-break.h (software_breakpoint_inserted_here)
+       (hardware_breakpoint_inserted_here): Declare.
+       * target.h (struct target_ops) <cancel_breakpoints>: Remove field.
+       (cancel_breakpoints): Delete.
+       * tracepoint.c (clear_installed_tracepoints, stop_tracing)
+       (upload_fast_traceframes): Remove references to
+       cancel_breakpoints.
+
 2015-01-09  Pedro Alves  <palves@redhat.com>
 
        * thread-db.c (find_new_threads_callback): Ignore thread if the
index 268ee5ceab9b25312f025103a33c1aac885379b7..4d19c870da2f447d019b3e899f8a53f283dbcb98 100644 (file)
@@ -218,9 +218,12 @@ static int linux_stopped_by_watchpoint (void);
 static void mark_lwp_dead (struct lwp_info *lwp, int wstat);
 static void proceed_all_lwps (void);
 static int finish_step_over (struct lwp_info *lwp);
-static CORE_ADDR get_stop_pc (struct lwp_info *lwp);
 static int kill_lwp (unsigned long lwpid, int signo);
 
+/* When the event-loop is doing a step-over, this points at the thread
+   being stepped.  */
+ptid_t step_over_bkpt;
+
 /* True if the low target can hardware single-step.  Such targets
    don't need a BREAKPOINT_REINSERT_ADDR callback.  */
 
@@ -363,6 +366,8 @@ linux_add_process (int pid, int attached)
   return proc;
 }
 
+static CORE_ADDR get_pc (struct lwp_info *lwp);
+
 /* Handle a GNU/Linux extended wait response.  If we see a clone
    event, we need to add the new LWP to our list (and not report the
    trap to higher layers).  */
@@ -423,9 +428,7 @@ handle_extended_wait (struct lwp_info *event_child, int wstat)
         If we do get another signal, be sure not to lose it.  */
       if (WSTOPSIG (status) == SIGSTOP)
        {
-         if (stopping_threads != NOT_STOPPING_THREADS)
-           new_lwp->stop_pc = get_stop_pc (new_lwp);
-         else
+         if (stopping_threads == NOT_STOPPING_THREADS)
            linux_resume_one_lwp (new_lwp, 0, 0, NULL);
        }
       else
@@ -434,7 +437,6 @@ handle_extended_wait (struct lwp_info *event_child, int wstat)
 
          if (stopping_threads != NOT_STOPPING_THREADS)
            {
-             new_lwp->stop_pc = get_stop_pc (new_lwp);
              new_lwp->status_pending_p = 1;
              new_lwp->status_pending = status;
            }
@@ -481,44 +483,96 @@ get_pc (struct lwp_info *lwp)
    The SIGTRAP could mean several things.
 
    On i386, where decr_pc_after_break is non-zero:
-   If we were single-stepping this process using PTRACE_SINGLESTEP,
-   we will get only the one SIGTRAP (even if the instruction we
-   stepped over was a breakpoint).  The value of $eip will be the
-   next instruction.
+
+   If we were single-stepping this process using PTRACE_SINGLESTEP, we
+   will get only the one SIGTRAP.  The value of $eip will be the next
+   instruction.  If the instruction we stepped over was a breakpoint,
+   we need to decrement the PC.
+
    If we continue the process using PTRACE_CONT, we will get a
    SIGTRAP when we hit a breakpoint.  The value of $eip will be
    the instruction after the breakpoint (i.e. needs to be
    decremented).  If we report the SIGTRAP to GDB, we must also
-   report the undecremented PC.  If we cancel the SIGTRAP, we
+   report the undecremented PC.  If the breakpoint is removed, we
    must resume at the decremented PC.
 
-   (Presumably, not yet tested) On a non-decr_pc_after_break machine
-   with hardware or kernel single-step:
-   If we single-step over a breakpoint instruction, our PC will
-   point at the following instruction.  If we continue and hit a
-   breakpoint instruction, our PC will point at the breakpoint
+   On a non-decr_pc_after_break machine with hardware or kernel
+   single-step:
+
+   If we either single-step a breakpoint instruction, or continue and
+   hit a breakpoint instruction, our PC will point at the breakpoint
    instruction.  */
 
-static CORE_ADDR
-get_stop_pc (struct lwp_info *lwp)
+static int
+check_stopped_by_breakpoint (struct lwp_info *lwp)
 {
-  CORE_ADDR stop_pc;
+  CORE_ADDR pc;
+  CORE_ADDR sw_breakpoint_pc;
+  struct thread_info *saved_thread;
 
   if (the_low_target.get_pc == NULL)
     return 0;
 
-  stop_pc = get_pc (lwp);
+  pc = get_pc (lwp);
+  sw_breakpoint_pc = pc - the_low_target.decr_pc_after_break;
 
-  if (WSTOPSIG (lwp->last_status) == SIGTRAP
-      && !lwp->stepping
-      && !lwp->stopped_by_watchpoint
-      && !linux_is_extended_waitstatus (lwp->last_status))
-    stop_pc -= the_low_target.decr_pc_after_break;
+  /* breakpoint_at reads from the current thread.  */
+  saved_thread = current_thread;
+  current_thread = get_lwp_thread (lwp);
 
-  if (debug_threads)
-    debug_printf ("stop pc is 0x%lx\n", (long) stop_pc);
+  /* We may have just stepped a breakpoint instruction.  E.g., in
+     non-stop mode, GDB first tells the thread A to step a range, and
+     then the user inserts a breakpoint inside the range.  In that
+     case, we need to report the breakpoint PC.  But, when we're
+     trying to step past one of our own breakpoints, that happens to
+     have been placed on top of a permanent breakpoint instruction, we
+     shouldn't adjust the PC, otherwise the program would keep
+     trapping the permanent breakpoint forever.  */
+  if ((!lwp->stepping
+       || (!ptid_equal (ptid_of (current_thread), step_over_bkpt)
+          && lwp->stop_pc == sw_breakpoint_pc))
+      && (*the_low_target.breakpoint_at) (sw_breakpoint_pc))
+    {
+      if (debug_threads)
+       {
+         struct thread_info *thr = get_lwp_thread (lwp);
+
+         debug_printf ("CSBB: %s stopped by software breakpoint\n",
+                       target_pid_to_str (ptid_of (thr)));
+       }
+
+      /* Back up the PC if necessary.  */
+      if (pc != sw_breakpoint_pc)
+        {
+         struct regcache *regcache
+           = get_thread_regcache (current_thread, 1);
+         (*the_low_target.set_pc) (regcache, sw_breakpoint_pc);
+       }
+
+      lwp->stop_pc = sw_breakpoint_pc;
+      lwp->stop_reason = LWP_STOPPED_BY_SW_BREAKPOINT;
+      current_thread = saved_thread;
+      return 1;
+    }
+
+  if (hardware_breakpoint_inserted_here (pc))
+    {
+      if (debug_threads)
+       {
+         struct thread_info *thr = get_lwp_thread (lwp);
+
+         debug_printf ("CSBB: %s stopped by hardware breakpoint\n",
+                       target_pid_to_str (ptid_of (thr)));
+       }
 
-  return stop_pc;
+      lwp->stop_pc = pc;
+      lwp->stop_reason = LWP_STOPPED_BY_HW_BREAKPOINT;
+      current_thread = saved_thread;
+      return 1;
+    }
+
+  current_thread = saved_thread;
+  return 0;
 }
 
 static struct lwp_info *
@@ -1197,12 +1251,83 @@ linux_thread_alive (ptid_t ptid)
     return 0;
 }
 
+/* Return 1 if this lwp still has an interesting status pending.  If
+   not (e.g., it had stopped for a breakpoint that is gone), return
+   false.  */
+
+static int
+thread_still_has_status_pending_p (struct thread_info *thread)
+{
+  struct lwp_info *lp = get_thread_lwp (thread);
+
+  if (!lp->status_pending_p)
+    return 0;
+
+  /* If we got a `vCont;t', but we haven't reported a stop yet, do
+     report any status pending the LWP may have.  */
+  if (thread->last_resume_kind == resume_stop
+      && thread->last_status.kind != TARGET_WAITKIND_IGNORE)
+    return 0;
+
+  if (thread->last_resume_kind != resume_stop
+      && (lp->stop_reason == LWP_STOPPED_BY_SW_BREAKPOINT
+         || lp->stop_reason == LWP_STOPPED_BY_HW_BREAKPOINT))
+    {
+      struct thread_info *saved_thread;
+      CORE_ADDR pc;
+      int discard = 0;
+
+      gdb_assert (lp->last_status != 0);
+
+      pc = get_pc (lp);
+
+      saved_thread = current_thread;
+      current_thread = thread;
+
+      if (pc != lp->stop_pc)
+       {
+         if (debug_threads)
+           debug_printf ("PC of %ld changed\n",
+                         lwpid_of (thread));
+         discard = 1;
+       }
+      else if (lp->stop_reason == LWP_STOPPED_BY_SW_BREAKPOINT
+              && !(*the_low_target.breakpoint_at) (pc))
+       {
+         if (debug_threads)
+           debug_printf ("previous SW breakpoint of %ld gone\n",
+                         lwpid_of (thread));
+         discard = 1;
+       }
+      else if (lp->stop_reason == LWP_STOPPED_BY_HW_BREAKPOINT
+              && !hardware_breakpoint_inserted_here (pc))
+       {
+         if (debug_threads)
+           debug_printf ("previous HW breakpoint of %ld gone\n",
+                         lwpid_of (thread));
+         discard = 1;
+       }
+
+      current_thread = saved_thread;
+
+      if (discard)
+       {
+         if (debug_threads)
+           debug_printf ("discarding pending breakpoint status\n");
+         lp->status_pending_p = 0;
+         return 0;
+       }
+    }
+
+  return 1;
+}
+
 /* Return 1 if this lwp has an interesting status pending.  */
 static int
 status_pending_p_callback (struct inferior_list_entry *entry, void *arg)
 {
   struct thread_info *thread = (struct thread_info *) entry;
-  struct lwp_info *lwp = get_thread_lwp (thread);
+  struct lwp_info *lp = get_thread_lwp (thread);
   ptid_t ptid = * (ptid_t *) arg;
 
   /* Check if we're only interested in events from a specific process
@@ -1211,13 +1336,14 @@ status_pending_p_callback (struct inferior_list_entry *entry, void *arg)
       && ptid_get_pid (ptid) != ptid_get_pid (thread->entry.id))
     return 0;
 
-  /* If we got a `vCont;t', but we haven't reported a stop yet, do
-     report any status pending the LWP may have.  */
-  if (thread->last_resume_kind == resume_stop
-      && thread->last_status.kind != TARGET_WAITKIND_IGNORE)
-    return 0;
+  if (lp->status_pending_p
+      && !thread_still_has_status_pending_p (thread))
+    {
+      linux_resume_one_lwp (lp, lp->stepping, GDB_SIGNAL_0, NULL);
+      return 0;
+    }
 
-  return lwp->status_pending_p;
+  return lp->status_pending_p;
 }
 
 static int
@@ -1363,6 +1489,8 @@ handle_tracepoints (struct lwp_info *lwp)
   struct thread_info *tinfo = get_lwp_thread (lwp);
   int tpoint_related_event = 0;
 
+  gdb_assert (lwp->suspended == 0);
+
   /* If this tracepoint hit causes a tracing stop, we'll immediately
      uninsert tracepoints.  To do this, we temporarily pause all
      threads, unpatch away, and then unpause threads.  We need to make
@@ -1528,7 +1656,6 @@ maybe_move_out_of_jump_pad (struct lwp_info *lwp, int *wstat)
                              "stopping all threads momentarily.\n");
 
              stop_all_lwps (1, lwp);
-             cancel_breakpoints ();
 
              delete_breakpoint (lwp->exit_jump_pad_bkpt);
              lwp->exit_jump_pad_bkpt = NULL;
@@ -1654,65 +1781,59 @@ dequeue_one_deferred_signal (struct lwp_info *lwp, int *wstat)
   return 0;
 }
 
-/* Arrange for a breakpoint to be hit again later.  We don't keep the
-   SIGTRAP status and don't forward the SIGTRAP signal to the LWP.  We
-   will handle the current event, eventually we will resume this LWP,
-   and this breakpoint will trap again.  */
+/* Return true if the event in LP may be caused by breakpoint.  */
 
 static int
-cancel_breakpoint (struct lwp_info *lwp)
+wstatus_maybe_breakpoint (int wstatus)
 {
-  struct thread_info *saved_thread;
+  return (WIFSTOPPED (wstatus)
+         && (WSTOPSIG (wstatus) == SIGTRAP
+             /* SIGILL and SIGSEGV are also treated as traps in case a
+                breakpoint is inserted at the current PC.  */
+             || WSTOPSIG (wstatus) == SIGILL
+             || WSTOPSIG (wstatus) == SIGSEGV));
+}
 
-  /* There's nothing to do if we don't support breakpoints.  */
-  if (!supports_breakpoints ())
-    return 0;
+/* Fetch the possibly triggered data watchpoint info and store it in
+   CHILD.
 
-  /* breakpoint_at reads from current inferior.  */
-  saved_thread = current_thread;
-  current_thread = get_lwp_thread (lwp);
+   On some archs, like x86, that use debug registers to set
+   watchpoints, it's possible that the way to know which watched
+   address trapped, is to check the register that is used to select
+   which address to watch.  Problem is, between setting the watchpoint
+   and reading back which data address trapped, the user may change
+   the set of watchpoints, and, as a consequence, GDB changes the
+   debug registers in the inferior.  To avoid reading back a stale
+   stopped-data-address when that happens, we cache in LP the fact
+   that a watchpoint trapped, and the corresponding data address, as
+   soon as we see CHILD stop with a SIGTRAP.  If GDB changes the debug
+   registers meanwhile, we have the cached data we can rely on.  */
 
-  if ((*the_low_target.breakpoint_at) (lwp->stop_pc))
+static int
+check_stopped_by_watchpoint (struct lwp_info *child)
+{
+  if (the_low_target.stopped_by_watchpoint != NULL)
     {
-      if (debug_threads)
-       debug_printf ("CB: Push back breakpoint for %s\n",
-                     target_pid_to_str (ptid_of (current_thread)));
+      struct thread_info *saved_thread;
 
-      /* Back up the PC if necessary.  */
-      if (the_low_target.decr_pc_after_break)
+      saved_thread = current_thread;
+      current_thread = get_lwp_thread (child);
+
+      if (the_low_target.stopped_by_watchpoint ())
        {
-         struct regcache *regcache
-           = get_thread_regcache (current_thread, 1);
-         (*the_low_target.set_pc) (regcache, lwp->stop_pc);
+         child->stop_reason = LWP_STOPPED_BY_WATCHPOINT;
+
+         if (the_low_target.stopped_data_address != NULL)
+           child->stopped_data_address
+             = the_low_target.stopped_data_address ();
+         else
+           child->stopped_data_address = 0;
        }
 
       current_thread = saved_thread;
-      return 1;
-    }
-  else
-    {
-      if (debug_threads)
-       debug_printf ("CB: No breakpoint found at %s for [%s]\n",
-                     paddress (lwp->stop_pc),
-                     target_pid_to_str (ptid_of (current_thread)));
     }
 
-  current_thread = saved_thread;
-  return 0;
-}
-
-/* Return true if the event in LP may be caused by breakpoint.  */
-
-static int
-lp_status_maybe_breakpoint (struct lwp_info *lp)
-{
-  return (lp->status_pending_p
-         && WIFSTOPPED (lp->status_pending)
-         && (WSTOPSIG (lp->status_pending) == SIGTRAP
-             /* SIGILL and SIGSEGV are also treated as traps in case a
-                breakpoint is inserted at the current PC.  */
-             || WSTOPSIG (lp->status_pending) == SIGILL
-             || WSTOPSIG (lp->status_pending) == SIGSEGV));
+  return child->stop_reason == LWP_STOPPED_BY_WATCHPOINT;
 }
 
 /* Do low-level handling of the event, and check if we should go on
@@ -1720,10 +1841,11 @@ lp_status_maybe_breakpoint (struct lwp_info *lp)
    NULL otherwise.  */
 
 static struct lwp_info *
-linux_low_filter_event (ptid_t filter_ptid, int lwpid, int wstat)
+linux_low_filter_event (int lwpid, int wstat)
 {
   struct lwp_info *child;
   struct thread_info *thread;
+  int have_stop_pc = 0;
 
   child = find_lwp_pid (pid_to_ptid (lwpid));
 
@@ -1745,6 +1867,35 @@ linux_low_filter_event (ptid_t filter_ptid, int lwpid, int wstat)
 
   child->last_status = wstat;
 
+  /* Check if the thread has exited.  */
+  if ((WIFEXITED (wstat) || WIFSIGNALED (wstat)))
+    {
+      if (debug_threads)
+       debug_printf ("LLFE: %d exited.\n", lwpid);
+      if (num_lwps (pid_of (thread)) > 1)
+       {
+
+         /* If there is at least one more LWP, then the exit signal was
+            not the end of the debugged application and should be
+            ignored.  */
+         delete_lwp (child);
+         return NULL;
+       }
+      else
+       {
+         /* This was the last lwp in the process.  Since events are
+            serialized to GDB core, and we can't report this one
+            right now, but GDB core and the other target layers will
+            want to be notified about the exit code/signal, leave the
+            status pending for the next time we're able to report
+            it.  */
+         mark_lwp_dead (child, wstat);
+         return child;
+       }
+    }
+
+  gdb_assert (WIFSTOPPED (wstat));
+
   if (WIFSTOPPED (wstat))
     {
       struct process_info *proc;
@@ -1769,75 +1920,6 @@ linux_low_filter_event (ptid_t filter_ptid, int lwpid, int wstat)
        }
     }
 
-  /* Store the STOP_PC, with adjustment applied.  This depends on the
-     architecture being defined already (so that CHILD has a valid
-     regcache), and on LAST_STATUS being set (to check for SIGTRAP or
-     not).  */
-  if (WIFSTOPPED (wstat))
-    {
-      if (debug_threads
-         && the_low_target.get_pc != NULL)
-       {
-         struct thread_info *saved_thread;
-         struct regcache *regcache;
-         CORE_ADDR pc;
-
-         saved_thread = current_thread;
-         current_thread = thread;
-         regcache = get_thread_regcache (current_thread, 1);
-         pc = (*the_low_target.get_pc) (regcache);
-         debug_printf ("linux_low_filter_event: pc is 0x%lx\n", (long) pc);
-         current_thread = saved_thread;
-       }
-
-      child->stop_pc = get_stop_pc (child);
-    }
-
-  /* Fetch the possibly triggered data watchpoint info and store it in
-     CHILD.
-
-     On some archs, like x86, that use debug registers to set
-     watchpoints, it's possible that the way to know which watched
-     address trapped, is to check the register that is used to select
-     which address to watch.  Problem is, between setting the
-     watchpoint and reading back which data address trapped, the user
-     may change the set of watchpoints, and, as a consequence, GDB
-     changes the debug registers in the inferior.  To avoid reading
-     back a stale stopped-data-address when that happens, we cache in
-     LP the fact that a watchpoint trapped, and the corresponding data
-     address, as soon as we see CHILD stop with a SIGTRAP.  If GDB
-     changes the debug registers meanwhile, we have the cached data we
-     can rely on.  */
-
-  if (WIFSTOPPED (wstat) && WSTOPSIG (wstat) == SIGTRAP)
-    {
-      if (the_low_target.stopped_by_watchpoint == NULL)
-       {
-         child->stopped_by_watchpoint = 0;
-       }
-      else
-       {
-         struct thread_info *saved_thread;
-
-         saved_thread = current_thread;
-         current_thread = thread;
-
-         child->stopped_by_watchpoint
-           = the_low_target.stopped_by_watchpoint ();
-
-         if (child->stopped_by_watchpoint)
-           {
-             if (the_low_target.stopped_data_address != NULL)
-               child->stopped_data_address
-                 = the_low_target.stopped_data_address ();
-             else
-               child->stopped_data_address = 0;
-           }
-
-         current_thread = saved_thread;
-       }
-    }
-
   if (WIFSTOPPED (wstat) && child->must_set_ptrace_flags)
     {
       struct process_info *proc = find_process_pid (pid_of (thread));
@@ -1846,13 +1928,28 @@ linux_low_filter_event (ptid_t filter_ptid, int lwpid, int wstat)
       child->must_set_ptrace_flags = 0;
     }
 
+  /* Be careful to not overwrite stop_pc until
+     check_stopped_by_breakpoint is called.  */
   if (WIFSTOPPED (wstat) && WSTOPSIG (wstat) == SIGTRAP
       && linux_is_extended_waitstatus (wstat))
     {
+      child->stop_pc = get_pc (child);
       handle_extended_wait (child, wstat);
       return NULL;
     }
 
+  if (WIFSTOPPED (wstat) && WSTOPSIG (wstat) == SIGTRAP
+      && check_stopped_by_watchpoint (child))
+    ;
+  else if (WIFSTOPPED (wstat) && wstatus_maybe_breakpoint (wstat))
+    {
+      if (check_stopped_by_breakpoint (child))
+       have_stop_pc = 1;
+    }
+
+  if (!have_stop_pc)
+    child->stop_pc = get_pc (child);
+
   if (WIFSTOPPED (wstat) && WSTOPSIG (wstat) == SIGSTOP
       && child->stop_expected)
     {
@@ -1868,7 +1965,7 @@ linux_low_filter_event (ptid_t filter_ptid, int lwpid, int wstat)
       else if (stopping_threads != NOT_STOPPING_THREADS)
        {
          /* Stopping threads.  We don't want this SIGSTOP to end up
-            pending in the FILTER_PTID handling below.  */
+            pending.  */
          return NULL;
        }
       else
@@ -1879,79 +1976,11 @@ linux_low_filter_event (ptid_t filter_ptid, int lwpid, int wstat)
        }
     }
 
-    /* Check if the thread has exited.  */
-  if ((WIFEXITED (wstat) || WIFSIGNALED (wstat))
-      && num_lwps (pid_of (thread)) > 1)
-    {
-      if (debug_threads)
-       debug_printf ("LLW: %d exited.\n", lwpid);
-
-        /* If there is at least one more LWP, then the exit signal
-           was not the end of the debugged application and should be
-           ignored.  */
-      delete_lwp (child);
-      return NULL;
-    }
-
-  if (!ptid_match (ptid_of (thread), filter_ptid))
-    {
-      if (debug_threads)
-       debug_printf ("LWP %d got an event %06x, leaving pending.\n",
-                     lwpid, wstat);
-
-      if (WIFSTOPPED (wstat))
-       {
-         child->status_pending_p = 1;
-         child->status_pending = wstat;
-
-         if (WSTOPSIG (wstat) != SIGSTOP)
-           {
-             /* Cancel breakpoint hits.  The breakpoint may be
-                removed before we fetch events from this process to
-                report to the core.  It is best not to assume the
-                moribund breakpoints heuristic always handles these
-                cases --- it could be too many events go through to
-                the core before this one is handled.  All-stop always
-                cancels breakpoint hits in all threads.  */
-             if (non_stop
-                 && lp_status_maybe_breakpoint (child)
-                 && cancel_breakpoint (child))
-               {
-                 /* Throw away the SIGTRAP.  */
-                 child->status_pending_p = 0;
-
-                 if (debug_threads)
-                   debug_printf ("LLW: LWP %d hit a breakpoint while"
-                                 " waiting for another process;"
-                                 " cancelled it\n", lwpid);
-               }
-           }
-       }
-      else if (WIFEXITED (wstat) || WIFSIGNALED (wstat))
-       {
-         if (debug_threads)
-           debug_printf ("LLWE: process %d exited while fetching "
-                         "event from another LWP\n", lwpid);
-
-         /* This was the last lwp in the process.  Since events are
-            serialized to GDB core, and we can't report this one
-            right now, but GDB core and the other target layers will
-            want to be notified about the exit code/signal, leave the
-            status pending for the next time we're able to report
-            it.  */
-         mark_lwp_dead (child, wstat);
-       }
-
-      return NULL;
-    }
-
+  child->status_pending_p = 1;
+  child->status_pending = wstat;
   return child;
 }
 
-/* When the event-loop is doing a step-over, this points at the thread
-   being stepped.  */
-ptid_t step_over_bkpt;
-
 /* Wait for an event from child(ren) WAIT_PTID, and return any that
    match FILTER_PTID (leaving others pending).  The PTIDs can be:
    minus_one_ptid, to specify any child; a pid PTID, specifying all
@@ -2041,6 +2070,9 @@ linux_wait_for_event_filtered (ptid_t wait_ptid, ptid_t filter_ptid,
   sigfillset (&block_mask);
   sigprocmask (SIG_BLOCK, &block_mask, &prev_mask);
 
+  /* Always pull all events out of the kernel.  We'll randomly select
+     an event LWP out of all that have events, to prevent
+     starvation.  */
   while (event_child == NULL)
     {
       pid_t ret = 0;
@@ -2073,20 +2105,28 @@ linux_wait_for_event_filtered (ptid_t wait_ptid, ptid_t filter_ptid,
                            (long) ret, status_to_str (*wstatp));
            }
 
-         event_child = linux_low_filter_event (filter_ptid,
-                                               ret, *wstatp);
-         if (event_child != NULL)
-           {
-             /* We got an event to report to the core.  */
-             event_thread = get_lwp_thread (event_child);
-             break;
-           }
-
+         /* Filter all events.  IOW, leave all events pending.  We'll
+            randomly select an event LWP out of all that have events
+            below.  */
+         linux_low_filter_event (ret, *wstatp);
          /* Retry until nothing comes out of waitpid.  A single
             SIGCHLD can indicate more than one child stopped.  */
          continue;
        }
 
+      /* Now that we've pulled all events out of the kernel, check if
+        there's any LWP with a status to report to the core.  */
+      event_thread = (struct thread_info *)
+       find_inferior (&all_threads, status_pending_p_callback, &filter_ptid);
+      if (event_thread != NULL)
+       {
+         event_child = get_thread_lwp (event_thread);
+         *wstatp = event_child->status_pending;
+         event_child->status_pending_p = 0;
+         event_child->status_pending = 0;
+         break;
+       }
+
       /* Check for zombie thread group leaders.  Those can't be reaped
         until all other threads in the thread group are.  */
       check_zombie_leaders ();
@@ -2166,17 +2206,14 @@ static int
 count_events_callback (struct inferior_list_entry *entry, void *data)
 {
   struct thread_info *thread = (struct thread_info *) entry;
-  struct lwp_info *lp = get_thread_lwp (thread);
   int *count = data;
 
   gdb_assert (count != NULL);
 
-  /* Count only resumed LWPs that have a SIGTRAP event pending that
-     should be reported to GDB.  */
+  /* Count only resumed LWPs that have an event pending. */
   if (thread->last_status.kind == TARGET_WAITKIND_IGNORE
       && thread->last_resume_kind != resume_stop
-      && lp_status_maybe_breakpoint (lp)
-      && !breakpoint_inserted_here (lp->stop_pc))
+      && thread->status_pending_p)
     (*count)++;
 
   return 0;
@@ -2205,62 +2242,20 @@ static int
 select_event_lwp_callback (struct inferior_list_entry *entry, void *data)
 {
   struct thread_info *thread = (struct thread_info *) entry;
-  struct lwp_info *lp = get_thread_lwp (thread);
   int *selector = data;
 
   gdb_assert (selector != NULL);
 
-  /* Select only resumed LWPs that have a SIGTRAP event pending. */
+  /* Select only resumed LWPs that have an event pending. */
   if (thread->last_resume_kind != resume_stop
       && thread->last_status.kind == TARGET_WAITKIND_IGNORE
-      && lp_status_maybe_breakpoint (lp)
-      && !breakpoint_inserted_here (lp->stop_pc))
+      && thread->status_pending_p)
     if ((*selector)-- == 0)
       return 1;
 
   return 0;
 }
 
-static int
-cancel_breakpoints_callback (struct inferior_list_entry *entry, void *data)
-{
-  struct thread_info *thread = (struct thread_info *) entry;
-  struct lwp_info *lp = get_thread_lwp (thread);
-  struct lwp_info *event_lp = data;
-
-  /* Leave the LWP that has been elected to receive a SIGTRAP alone.  */
-  if (lp == event_lp)
-    return 0;
-
-  /* If a LWP other than the LWP that we're reporting an event for has
-     hit a GDB breakpoint (as opposed to some random trap signal),
-     then just arrange for it to hit it again later.  We don't keep
-     the SIGTRAP status and don't forward the SIGTRAP signal to the
-     LWP.  We will handle the current event, eventually we will resume
-     all LWPs, and this one will get its breakpoint trap again.
-
-     If we do not do this, then we run the risk that the user will
-     delete or disable the breakpoint, but the LWP will have already
-     tripped on it.  */
-
-  if (thread->last_resume_kind != resume_stop
-      && thread->last_status.kind == TARGET_WAITKIND_IGNORE
-      && lp_status_maybe_breakpoint (lp)
-      && !lp->stepping
-      && !lp->stopped_by_watchpoint
-      && cancel_breakpoint (lp))
-    /* Throw away the SIGTRAP.  */
-    lp->status_pending_p = 0;
-
-  return 0;
-}
-
-static void
-linux_cancel_breakpoints (void)
-{
-  find_inferior (&all_threads, cancel_breakpoints_callback, NULL);
-}
-
 /* Select one LWP out of those that have events pending.  */
 
 static void
@@ -2268,20 +2263,30 @@ select_event_lwp (struct lwp_info **orig_lp)
 {
   int num_events = 0;
   int random_selector;
-  struct thread_info *event_thread;
-
-  /* Give preference to any LWP that is being single-stepped.  */
-  event_thread
-    = (struct thread_info *) find_inferior (&all_threads,
-                                           select_singlestep_lwp_callback,
-                                           NULL);
-  if (event_thread != NULL)
+  struct thread_info *event_thread = NULL;
+
+  /* In all-stop, give preference to the LWP that is being
+     single-stepped.  There will be at most one, and it's the LWP that
+     the core is most interested in.  If we didn't do this, then we'd
+     have to handle pending step SIGTRAPs somehow in case the core
+     later continues the previously-stepped thread, otherwise we'd
+     report the pending SIGTRAP, and the core, not having stepped the
+     thread, wouldn't understand what the trap was for, and therefore
+     would report it to the user as a random signal.  */
+  if (!non_stop)
     {
-      if (debug_threads)
-       debug_printf ("SEL: Select single-step %s\n",
-                     target_pid_to_str (ptid_of (event_thread)));
+      event_thread
+       = (struct thread_info *) find_inferior (&all_threads,
+                                               select_singlestep_lwp_callback,
+                                               NULL);
+      if (event_thread != NULL)
+       {
+         if (debug_threads)
+           debug_printf ("SEL: Select single-step %s\n",
+                         target_pid_to_str (ptid_of (event_thread)));
+       }
     }
-  else
+  if (event_thread == NULL)
     {
       /* No single-stepping LWP.  Select one at random, out of those
          which have had SIGTRAP events.  */
@@ -2448,6 +2453,23 @@ linux_stabilize_threads (void)
     }
 }
 
+static void async_file_mark (void);
+
+/* Convenience function that is called when the kernel reports an
+   event that is not passed out to GDB.  */
+
+static ptid_t
+ignore_event (struct target_waitstatus *ourstatus)
+{
+  /* If we got an event, there may still be others, as a single
+     SIGCHLD can indicate more than one child stopped.  This forces
+     another target_wait call.  */
+  async_file_mark ();
+
+  ourstatus->kind = TARGET_WAITKIND_IGNORE;
+  return null_ptid;
+}
+
 /* Wait for process, returns status.  */
 
 static ptid_t
@@ -2476,7 +2498,6 @@ linux_wait_1 (ptid_t ptid,
   if (target_options & TARGET_WNOHANG)
     options |= WNOHANG;
 
-retry:
   bp_explains_trap = 0;
   trace_event = 0;
   in_step_range = 0;
@@ -2641,7 +2662,8 @@ retry:
                          WSTOPSIG (w), lwpid_of (current_thread));
 
          linux_resume_one_lwp (event_child, 0, 0, NULL);
-         goto retry;
+
+         return ignore_event (ourstatus);
        }
     }
 
@@ -2675,7 +2697,6 @@ retry:
                 care of while the breakpoint is still
                 inserted.  */
              stop_all_lwps (1, event_child);
-             cancel_breakpoints ();
 
              delete_breakpoint (event_child->exit_jump_pad_bkpt);
              event_child->exit_jump_pad_bkpt = NULL;
@@ -2759,7 +2780,7 @@ retry:
        info_p = NULL;
       linux_resume_one_lwp (event_child, event_child->stepping,
                            WSTOPSIG (w), info_p);
-      goto retry;
+      return ignore_event (ourstatus);
     }
 
   /* Note that all addresses are always "out of the step range" when
@@ -2778,7 +2799,7 @@ retry:
   report_to_gdb = (!maybe_internal_trap
                   || (current_thread->last_resume_kind == resume_step
                       && !in_step_range)
-                  || event_child->stopped_by_watchpoint
+                  || event_child->stop_reason == LWP_STOPPED_BY_WATCHPOINT
                   || (!step_over_finished && !in_step_range
                       && !bp_explains_trap && !trace_event)
                   || (gdb_breakpoint_here (event_child->stop_pc)
@@ -2830,7 +2851,7 @@ retry:
        unsuspend_all_lwps (event_child);
 
       proceed_all_lwps ();
-      goto retry;
+      return ignore_event (ourstatus);
     }
 
   if (debug_threads)
@@ -2842,9 +2863,9 @@ retry:
          else if (!lwp_in_step_range (event_child))
            debug_printf ("Out of step range, reporting event.\n");
        }
-      if (event_child->stopped_by_watchpoint)
+      if (event_child->stop_reason == LWP_STOPPED_BY_WATCHPOINT)
        debug_printf ("Stopped by watchpoint.\n");
-      if (gdb_breakpoint_here (event_child->stop_pc))
+      else if (gdb_breakpoint_here (event_child->stop_pc))
        debug_printf ("Stopped by GDB breakpoint.\n");
       if (debug_threads)
        debug_printf ("Hit a non-gdbserver trap event.\n");
@@ -2852,10 +2873,11 @@ retry:
 
   /* Alright, we're going to report a stop.  */
 
-  if (!non_stop && !stabilizing_threads)
+  if (!stabilizing_threads)
     {
       /* In all-stop, stop all threads.  */
-      stop_all_lwps (0, NULL);
+      if (!non_stop)
+       stop_all_lwps (0, NULL);
 
       /* If we're not waiting for a specific LWP, choose an event LWP
         from among those that have had events.  Giving equal priority
@@ -2875,23 +2897,33 @@ retry:
          w = event_child->status_pending;
        }
 
-      /* Now that we've selected our final event LWP, cancel any
-        breakpoints in other LWPs that have hit a GDB breakpoint.
-        See the comment in cancel_breakpoints_callback to find out
-        why.  */
-      find_inferior (&all_threads, cancel_breakpoints_callback, event_child);
-
-      /* If we were going a step-over, all other threads but the stepping one
-        had been paused in start_step_over, with their suspend counts
-        incremented.  We don't want to do a full unstop/unpause, because we're
-        in all-stop mode (so we want threads stopped), but we still need to
-        unsuspend the other threads, to decrement their `suspended' count
-        back.  */
       if (step_over_finished)
-       unsuspend_all_lwps (event_child);
+       {
+         if (!non_stop)
+           {
+             /* If we were doing a step-over, all other threads but
+                the stepping one had been paused in start_step_over,
+                with their suspend counts incremented.  We don't want
+                to do a full unstop/unpause, because we're in
+                all-stop mode (so we want threads stopped), but we
+                still need to unsuspend the other threads, to
+                decrement their `suspended' count back.  */
+             unsuspend_all_lwps (event_child);
+           }
+         else
+           {
+             /* If we just finished a step-over, then all threads had
+                been momentarily paused.  In all-stop, that's fine,
+                we want threads stopped by now anyway.  In non-stop,
+                we need to re-resume threads that GDB wanted to be
+                running.  */
+             unstop_all_lwps (1, event_child);
+           }
+       }
 
       /* Stabilize threads (move out of jump pads).  */
-      stabilize_threads ();
+      if (!non_stop)
+       stabilize_threads ();
     }
   else
     {
@@ -2905,6 +2937,20 @@ retry:
 
   ourstatus->kind = TARGET_WAITKIND_STOPPED;
 
+  /* Now that we've selected our final event LWP, un-adjust its PC if
+     it was a software breakpoint.  */
+  if (event_child->stop_reason == LWP_STOPPED_BY_SW_BREAKPOINT)
+    {
+      int decr_pc = the_low_target.decr_pc_after_break;
+
+      if (decr_pc != 0)
+       {
+         struct regcache *regcache
+           = get_thread_regcache (current_thread, 1);
+         (*the_low_target.set_pc) (regcache, event_child->stop_pc + decr_pc);
+       }
+    }
+
   if (current_thread->last_resume_kind == resume_stop
       && WSTOPSIG (w) == SIGSTOP)
     {
@@ -2976,7 +3022,13 @@ linux_wait (ptid_t ptid,
   if (target_is_async_p ())
     async_file_flush ();
 
-  event_ptid = linux_wait_1 (ptid, ourstatus, target_options);
+  do
+    {
+      event_ptid = linux_wait_1 (ptid, ourstatus, target_options);
+    }
+  while ((target_options & TARGET_WNOHANG) == 0
+        && ptid_equal (event_ptid, null_ptid)
+        && ourstatus->kind == TARGET_WAITKIND_IGNORE);
 
   /* If at least one stop was reported, there may be more.  A single
      SIGCHLD can signal more than one child stop.  */
@@ -3164,7 +3216,7 @@ stuck_in_jump_pad_callback (struct inferior_list_entry *entry, void *data)
   return (supports_fast_tracepoints ()
          && agent_loaded_p ()
          && (gdb_breakpoint_here (lwp->stop_pc)
-             || lwp->stopped_by_watchpoint
+             || lwp->stop_reason == LWP_STOPPED_BY_WATCHPOINT
              || thread->last_resume_kind == resume_step)
          && linux_fast_tracepoint_collecting (lwp, NULL));
 }
@@ -3183,7 +3235,7 @@ move_out_of_jump_pad_callback (struct inferior_list_entry *entry)
 
   /* Allow debugging the jump pad, gdb_collect, etc.  */
   if (!gdb_breakpoint_here (lwp->stop_pc)
-      && !lwp->stopped_by_watchpoint
+      && lwp->stop_reason != LWP_STOPPED_BY_WATCHPOINT
       && thread->last_resume_kind != resume_step
       && maybe_move_out_of_jump_pad (lwp, wstat))
     {
@@ -3407,11 +3459,17 @@ linux_resume_one_lwp (struct lwp_info *lwp,
       step = 1;
     }
 
-  if (debug_threads && the_low_target.get_pc != NULL)
+  if (the_low_target.get_pc != NULL)
     {
       struct regcache *regcache = get_thread_regcache (current_thread, 1);
-      CORE_ADDR pc = (*the_low_target.get_pc) (regcache);
-      debug_printf ("  resuming from pc 0x%lx\n", (long) pc);
+
+      lwp->stop_pc = (*the_low_target.get_pc) (regcache);
+
+      if (debug_threads)
+       {
+         debug_printf ("  %s from pc 0x%lx\n", step ? "step" : "continue",
+                       (long) lwp->stop_pc);
+       }
     }
 
   /* If we have pending signals, consume one unless we are trying to
@@ -3442,7 +3500,7 @@ linux_resume_one_lwp (struct lwp_info *lwp,
   regcache_invalidate_thread (thread);
   errno = 0;
   lwp->stopped = 0;
-  lwp->stopped_by_watchpoint = 0;
+  lwp->stop_reason = LWP_STOPPED_BY_NO_REASON;
   lwp->stepping = step;
   ptrace (step ? PTRACE_SINGLESTEP : PTRACE_CONT, lwpid_of (thread),
          (PTRACE_TYPE_ARG3) 0,
@@ -3563,7 +3621,7 @@ resume_status_pending_p (struct inferior_list_entry *entry, void *flag_p)
   if (lwp->resume == NULL)
     return 0;
 
-  if (lwp->status_pending_p)
+  if (thread_still_has_status_pending_p (thread))
     * (int *) flag_p = 1;
 
   return 0;
@@ -4848,7 +4906,7 @@ linux_stopped_by_watchpoint (void)
 {
   struct lwp_info *lwp = get_thread_lwp (current_thread);
 
-  return lwp->stopped_by_watchpoint;
+  return lwp->stop_reason == LWP_STOPPED_BY_WATCHPOINT;
 }
 
 static CORE_ADDR
@@ -6017,7 +6075,6 @@ static struct target_ops linux_target_ops = {
   NULL,
   linux_pause_all,
   linux_unpause_all,
-  linux_cancel_breakpoints,
   linux_stabilize_threads,
   linux_install_fast_tracepoint_jump_pad,
   linux_emit_ops,
index 97b163fbb5d5374a5a9751c7d180635d12ce3d55..bea4a377ed848b6e71dd767e6c1586a1ff654633 100644 (file)
@@ -230,6 +230,24 @@ extern struct linux_target_ops the_low_target;
 #define get_thread_lwp(thr) ((struct lwp_info *) (inferior_target_data (thr)))
 #define get_lwp_thread(lwp) ((lwp)->thread)
 
+/* Reasons an LWP last stopped.  */
+
+enum lwp_stop_reason
+{
+  /* Either not stopped, or stopped for a reason that doesn't require
+     special tracking.  */
+  LWP_STOPPED_BY_NO_REASON,
+
+  /* Stopped by a software breakpoint.  */
+  LWP_STOPPED_BY_SW_BREAKPOINT,
+
+  /* Stopped by a hardware breakpoint.  */
+  LWP_STOPPED_BY_HW_BREAKPOINT,
+
+  /* Stopped by a watchpoint.  */
+  LWP_STOPPED_BY_WATCHPOINT
+};
+
 /* This struct is recorded in the target_data field of struct thread_info.
 
    On linux ``all_threads'' is keyed by the LWP ID, which we use as the
@@ -269,8 +287,9 @@ struct lwp_info
   /* When stopped is set, the last wait status recorded for this lwp.  */
   int last_status;
 
-  /* When stopped is set, this is where the lwp stopped, with
-     decr_pc_after_break already accounted for.  */
+  /* When stopped is set, this is where the lwp last stopped, with
+     decr_pc_after_break already accounted for.  If the LWP is
+     running, this is the address at which the lwp was resumed.  */
   CORE_ADDR stop_pc;
 
   /* If this flag is set, STATUS_PENDING is a waitstatus that has not yet
@@ -278,9 +297,9 @@ struct lwp_info
   int status_pending_p;
   int status_pending;
 
-  /* STOPPED_BY_WATCHPOINT is non-zero if this LWP stopped with a data
-     watchpoint trap.  */
-  int stopped_by_watchpoint;
+  /* The reason the LWP last stopped, if we need to track it
+     (breakpoint, watchpoint, etc.)  */
+  enum lwp_stop_reason stop_reason;
 
   /* On architectures where it is possible to know the data address of
      a triggered watchpoint, STOPPED_DATA_ADDRESS is non-zero, and
index f0939ce306fab242fc32ac2ec424fb5e7f62c646..2c3fccca8118a98bce500faa9d82e8e40c18ea57 100644 (file)
@@ -805,7 +805,7 @@ x86_linux_prepare_to_resume (struct lwp_info *lwp)
       lwp->arch_private->debug_registers_changed = 0;
     }
 
-  if (clear_status || lwp->stopped_by_watchpoint)
+  if (clear_status || lwp->stop_reason == LWP_STOPPED_BY_WATCHPOINT)
     x86_linux_dr_set (ptid, DR_STATUS, 0);
 }
 \f
index c3114b9fa9b458da222cd509ff589dcaa9c4a1ec..70fab2e3a73a6bce2f6bc049bcf1d4107c3cb6b1 100644 (file)
@@ -1610,6 +1610,40 @@ breakpoint_inserted_here (CORE_ADDR addr)
   return 0;
 }
 
+/* See mem-break.h.  */
+
+int
+software_breakpoint_inserted_here (CORE_ADDR addr)
+{
+  struct process_info *proc = current_process ();
+  struct raw_breakpoint *bp;
+
+  for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next)
+    if (bp->raw_type == raw_bkpt_type_sw
+       && bp->pc == addr
+       && bp->inserted)
+      return 1;
+
+  return 0;
+}
+
+/* See mem-break.h.  */
+
+int
+hardware_breakpoint_inserted_here (CORE_ADDR addr)
+{
+  struct process_info *proc = current_process ();
+  struct raw_breakpoint *bp;
+
+  for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next)
+    if (bp->raw_type == raw_bkpt_type_hw
+       && bp->pc == addr
+       && bp->inserted)
+      return 1;
+
+  return 0;
+}
+
 static int
 validate_inserted_breakpoint (struct raw_breakpoint *bp)
 {
index 056a256d9b956f93585c74516428c62942d751cb..8b010c14dfabafcc604a96a3334c2011da6997fa 100644 (file)
@@ -90,6 +90,16 @@ int breakpoint_here (CORE_ADDR addr);
 
 int breakpoint_inserted_here (CORE_ADDR addr);
 
+/* Returns TRUE if there's any inserted software breakpoint at
+   ADDR.  */
+
+int software_breakpoint_inserted_here (CORE_ADDR addr);
+
+/* Returns TRUE if there's any inserted hardware (code) breakpoint at
+   ADDR.  */
+
+int hardware_breakpoint_inserted_here (CORE_ADDR addr);
+
 /* Clear all breakpoint conditions and commands associated with a
    breakpoint.  */
 
index 9bcf246bde3083476fb0ad75e1e104a9f5d37e52..bbb056733e29b20d6177ac8ea14ee19990e5e2d7 100644 (file)
@@ -304,9 +304,6 @@ struct target_ops
      the pause call.  */
   void (*unpause_all) (int unfreeze);
 
-  /* Cancel all pending breakpoints hits in all threads.  */
-  void (*cancel_breakpoints) (void);
-
   /* Stabilize all threads.  That is, force them out of jump pads.  */
   void (*stabilize_threads) (void);
 
@@ -453,13 +450,6 @@ int kill_inferior (int);
        (*the_target->unpause_all) (unfreeze);  \
     } while (0)
 
-#define cancel_breakpoints()                   \
-  do                                           \
-    {                                          \
-      if (the_target->cancel_breakpoints)      \
-       (*the_target->cancel_breakpoints) ();   \
-    } while (0)
-
 #define stabilize_threads()                    \
   do                                           \
     {                                          \
index b5ea56b35ab82ab387f90dff0685184c2b52f27e..82d6ce5d51e1841a18f60b196435e22a7b7ef150 100644 (file)
@@ -2443,7 +2443,6 @@ clear_installed_tracepoints (void)
   struct tracepoint *prev_stpoint;
 
   pause_all (1);
-  cancel_breakpoints ();
 
   prev_stpoint = NULL;
 
@@ -3433,9 +3432,6 @@ stop_tracing (void)
      We can't now, since we may be getting here due to the inferior
      agent calling us.  */
   pause_all (1);
-  /* Since we're removing breakpoints, cancel breakpoint hits,
-     possibly related to the breakpoints we're about to delete.  */
-  cancel_breakpoints ();
 
   /* Stop logging. Tracepoints can still be hit, but they will not be
      recorded.  */
@@ -6538,7 +6534,6 @@ upload_fast_traceframes (void)
   trace_debug ("Done uploading traceframes [%d]\n", curr_tbctrl_idx);
 
   pause_all (1);
-  cancel_breakpoints ();
 
   delete_breakpoint (about_to_request_buffer_space_bkpt);
   about_to_request_buffer_space_bkpt = NULL;