aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPedro Alves <palves@redhat.com>2014-12-29 19:41:07 +0000
committerPedro Alves <palves@redhat.com>2015-01-09 14:42:32 +0000
commit582511be69deb0e9d52efd6d51f860b6bee02a64 (patch)
tree3a79e3d349e693ba3b1d1247f532d9d101de20d5
parent9c02b52532ac7864e7e19c7df1fb2e63625f3131 (diff)
downloadgdb-582511be69deb0e9d52efd6d51f860b6bee02a64.zip
gdb-582511be69deb0e9d52efd6d51f860b6bee02a64.tar.gz
gdb-582511be69deb0e9d52efd6d51f860b6bee02a64.tar.bz2
[gdbserver] linux-low.c: better starvation avoidance, handle non-stop mode too
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.
-rw-r--r--gdb/gdbserver/ChangeLog55
-rw-r--r--gdb/gdbserver/linux-low.c707
-rw-r--r--gdb/gdbserver/linux-low.h29
-rw-r--r--gdb/gdbserver/linux-x86-low.c2
-rw-r--r--gdb/gdbserver/mem-break.c34
-rw-r--r--gdb/gdbserver/mem-break.h10
-rw-r--r--gdb/gdbserver/target.h10
-rw-r--r--gdb/gdbserver/tracepoint.c5
8 files changed, 506 insertions, 346 deletions
diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog
index d6bafae..180e341 100644
--- a/gdb/gdbserver/ChangeLog
+++ b/gdb/gdbserver/ChangeLog
@@ -1,5 +1,60 @@
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
kernel thread ID is -1.
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 268ee5c..4d19c87 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -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,
diff --git a/gdb/gdbserver/linux-low.h b/gdb/gdbserver/linux-low.h
index 97b163f..bea4a37 100644
--- a/gdb/gdbserver/linux-low.h
+++ b/gdb/gdbserver/linux-low.h
@@ -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
diff --git a/gdb/gdbserver/linux-x86-low.c b/gdb/gdbserver/linux-x86-low.c
index f0939ce..2c3fccc 100644
--- a/gdb/gdbserver/linux-x86-low.c
+++ b/gdb/gdbserver/linux-x86-low.c
@@ -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);
}
diff --git a/gdb/gdbserver/mem-break.c b/gdb/gdbserver/mem-break.c
index c3114b9..70fab2e 100644
--- a/gdb/gdbserver/mem-break.c
+++ b/gdb/gdbserver/mem-break.c
@@ -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)
{
diff --git a/gdb/gdbserver/mem-break.h b/gdb/gdbserver/mem-break.h
index 056a256..8b010c1 100644
--- a/gdb/gdbserver/mem-break.h
+++ b/gdb/gdbserver/mem-break.h
@@ -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. */
diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h
index 9bcf246..bbb0567 100644
--- a/gdb/gdbserver/target.h
+++ b/gdb/gdbserver/target.h
@@ -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 \
{ \
diff --git a/gdb/gdbserver/tracepoint.c b/gdb/gdbserver/tracepoint.c
index b5ea56b..82d6ce5 100644
--- a/gdb/gdbserver/tracepoint.c
+++ b/gdb/gdbserver/tracepoint.c
@@ -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;