summaryrefslogtreecommitdiff
path: root/gdb/breakpoint.c
diff options
context:
space:
mode:
authorPedro Alves <pedro@codesourcery.com>2009-11-20 13:08:15 +0000
committerPedro Alves <pedro@codesourcery.com>2009-11-20 13:08:15 +0000
commit5f00af2b7ef80b99e6d42c3bd8ba662149798a84 (patch)
tree63629176c9304f65cd617f9ed39b8c5854b96cf5 /gdb/breakpoint.c
parent79677e50c88ffe5bb2f423fc8eac52710ef4ceac (diff)
downloadgdb-5f00af2b7ef80b99e6d42c3bd8ba662149798a84.tar.gz
* infrun.c (handle_inferior_event): Hardware hatchpoint traps are
never random signals. * breakpoint.c (update_global_location_list): Always delete immediately delete hardware watchpoint locations and other locations whose target address isn't meaningful. Update comment explaining the hazard of moribund locations.
Diffstat (limited to 'gdb/breakpoint.c')
-rw-r--r--gdb/breakpoint.c61
1 files changed, 48 insertions, 13 deletions
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 7968068a4af..493b1f4843f 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -8300,20 +8300,55 @@ update_global_location_list (int should_insert)
if (!found_object)
{
- if (removed && non_stop)
+ if (removed && non_stop
+ && breakpoint_address_is_meaningful (old_loc->owner)
+ && !is_hardware_watchpoint (old_loc->owner))
{
- /* This location was removed from the targets. In non-stop mode,
- a race condition is possible where we've removed a breakpoint,
- but stop events for that breakpoint are already queued and will
- arrive later. To suppress spurious SIGTRAPs reported to user,
- we keep this breakpoint location for a bit, and will retire it
- after we see 3 * thread_count events.
- The theory here is that reporting of events should,
- "on the average", be fair, so after that many event we'll see
- events from all threads that have anything of interest, and no
- longer need to keep this breakpoint. This is just a
- heuristic, but if it's wrong, we'll report unexpected SIGTRAP,
- which is usability issue, but not a correctness problem. */
+ /* This location was removed from the target. In
+ non-stop mode, a race condition is possible where
+ we've removed a breakpoint, but stop events for that
+ breakpoint are already queued and will arrive later.
+ We apply an heuristic to be able to distinguish such
+ SIGTRAPs from other random SIGTRAPs: we keep this
+ breakpoint location for a bit, and will retire it
+ after we see some number of events. The theory here
+ is that reporting of events should, "on the average",
+ be fair, so after a while we'll see events from all
+ threads that have anything of interest, and no longer
+ need to keep this breakpoint location around. We
+ don't hold locations forever so to reduce chances of
+ mistaking a non-breakpoint SIGTRAP for a breakpoint
+ SIGTRAP.
+
+ The heuristic failing can be disastrous on
+ decr_pc_after_break targets.
+
+ On decr_pc_after_break targets, like e.g., x86-linux,
+ if we fail to recognize a late breakpoint SIGTRAP,
+ because events_till_retirement has reached 0 too
+ soon, we'll fail to do the PC adjustment, and report
+ a random SIGTRAP to the user. When the user resumes
+ the inferior, it will most likely immediately crash
+ with SIGILL/SIGBUS/SEGSEGV, or worse, get silently
+ corrupted, because of being resumed e.g., in the
+ middle of a multi-byte instruction, or skipped a
+ one-byte instruction. This was actually seen happen
+ on native x86-linux, and should be less rare on
+ targets that do not support new thread events, like
+ remote, due to the heuristic depending on
+ thread_count.
+
+ Mistaking a random SIGTRAP for a breakpoint trap
+ causes similar symptoms (PC adjustment applied when
+ it shouldn't), but then again, playing with SIGTRAPs
+ behind the debugger's back is asking for trouble.
+
+ Since hardware watchpoint traps are always
+ distinguishable from other traps, so we don't need to
+ apply keep hardware watchpoint moribund locations
+ around. We simply always ignore hardware watchpoint
+ traps we can no longer explain. */
+
old_loc->events_till_retirement = 3 * (thread_count () + 1);
old_loc->owner = NULL;