Blame SOURCES/gdb-rhbz1261564-aarch64-hw-watchpoint-1of5.patch

2c2fa1
http://sourceware.org/ml/gdb-patches/2015-02/msg00730.html
2c2fa1
Subject: [PATCH 2/8] Teach GDB about targets that can tell whether a trap is a breakpoint event
2c2fa1
2c2fa1
The moribund locations heuristics are problematic.  This patch teaches
2c2fa1
GDB about targets that can reliably tell whether a trap was caused by
2c2fa1
a software or hardware breakpoint, and thus don't need moribund
2c2fa1
locations, thus bypassing all the problems that mechanism has.
2c2fa1
2c2fa1
The non-stop-fair-events.exp test is frequently failing currently.
2c2fa1
E.g., see https://sourceware.org/ml/gdb-testers/2015-q1/msg03148.html.
2c2fa1
2c2fa1
The root cause is a fundamental problem with moribund locations.  For
2c2fa1
example, the stepped_breakpoint logic added by af48d08f breaks in this
2c2fa1
case (which is what happens with that test):
2c2fa1
2c2fa1
 - Step thread A, no breakpoint is set at PC.
2c2fa1
2c2fa1
 - The kernel doesn't schedule thread A yet.
2c2fa1
2c2fa1
 - Insert breakpoint at A's PC, for some reason (e.g., a step-resume
2c2fa1
   breakpoint for thread B).
2c2fa1
2c2fa1
 - Kernel finally schedules thread A.
2c2fa1
2c2fa1
 - thread A's stepped_breakpoint flag is not set, even though it now
2c2fa1
   stepped a breakpoint instruction.
2c2fa1
2c2fa1
 - adjust_pc_after_break gets the PC wrong, because PC == PREV_PC, but
2c2fa1
   stepped_breakpoint is not set.
2c2fa1
2c2fa1
We needed the stepped_breakpoint logic to workaround moribund
2c2fa1
locations, because otherwise adjust_pc_after_break could apply an
2c2fa1
adjustment when it shouldn't just because there _used_ to be a
2c2fa1
breakpoint at PC (a moribund breakpoint location).  For example, on
2c2fa1
x86, that's wrong if the thread really hasn't executed an int3, but
2c2fa1
instead executed some other 1-byte long instruction.  Getting the PC
2c2fa1
adjustment wrong of course leads to the inferior executing the wrong
2c2fa1
instruction.
2c2fa1
2c2fa1
Other problems with moribund locations are:
2c2fa1
2c2fa1
 - if a true SIGTRAP happens to be raised when the program is
2c2fa1
   executing the PC that used to have a breakpoint, GDB will assume
2c2fa1
   that is a trap for a breakpoint that has recently been removed, and
2c2fa1
   thus we miss reporting the random signal to the user.
2c2fa1
2c2fa1
 - to minimize that, we get rid of moribund location after a while.
2c2fa1
   That while is defined as just a certain number of events being
2c2fa1
   processed.  That number of events sometimes passes by before a
2c2fa1
   delayed breakpoint is processed, and GDB confuses the trap for a
2c2fa1
   random signal, thus reporting the random trap.  Once the user
2c2fa1
   resumes the thread, the program crashes because the PC was not
2c2fa1
   adjusted...
2c2fa1
2c2fa1
The fix for all this is to bite the bullet and get rid of heuristics
2c2fa1
and instead rely on the target knowing accurately what caused the
2c2fa1
SIGTRAP.  The target/kernel/stub is in the best position to know what
2c2fa1
that, because it can e.g. consult priviledged CPU flags GDB has no
2c2fa1
access to, or by knowing which exception vector entry was called when
2c2fa1
the instruction trapped, etc.  Most debug APIs I've seen to date
2c2fa1
report breakpoint hits as a distinct event in some fashion.  For
2c2fa1
example, on the Linux kernel, whether a breakpoint was executed is
2c2fa1
exposed to userspace in the si_code field of the SIGTRAP's siginfo.
2c2fa1
On Windows, the debug API reports a EXCEPTION_BREAKPOINT exception
2c2fa1
code.
2c2fa1
2c2fa1
We needed to keep around deleted breakpoints in an on-the-side list
2c2fa1
(the moribund locations) for two main reasons:
2c2fa1
2c2fa1
  - Know that a SIGTRAP actually is a delayed event for a hit of a
2c2fa1
    breakpoint that was removed before the event was processed, and
2c2fa1
    thus should not be reported as a random signal.
2c2fa1
2c2fa1
  - So we still do the decr_pc_after_break adjustment in that case, so
2c2fa1
    that the thread is resumed at the correct address.
2c2fa1
2c2fa1
In the new model, if GDB processes an event the target tells is a
2c2fa1
breakpoint trap, and GDB doesn't find the corresponding breakpoint in
2c2fa1
its breakpoint tables, it means that event is a delayed event for a
2c2fa1
breakpoint that has since been removed, and thus the event should be
2c2fa1
ignored.
2c2fa1
2c2fa1
For the decr_pc_after_after issue, it ends up being much simpler that
2c2fa1
on targets that can reliably tell whether a breakpoint trapped, for
2c2fa1
the breakpoint trap to present the PC already adjusted.  Proper
2c2fa1
multi-threading support already implies that targets needs to be doing
2c2fa1
decr_pc_after_break adjustment themselves, otherwise for example, in
2c2fa1
all-stop if two threads hit a breakpoint simultaneously, and the user
2c2fa1
does "info threads", he'll see the non-event thread that hit the
2c2fa1
breakpoint stopped at the wrong PC.
2c2fa1
2c2fa1
This way (target adjusts) also ends up eliminating the need for some
2c2fa1
awkward re-incrementing of the PC in the record-full and Linux targets
2c2fa1
that we do today, and the need for the target_decr_pc_after_break
2c2fa1
hook.
2c2fa1
2c2fa1
If the target always adjusts, then there's a case where GDB needs to
2c2fa1
re-increment the PC.  Say, on x86, an "int3" instruction that was
2c2fa1
explicitly written in the program traps.  In this case, GDB should
2c2fa1
report a random SIGTRAP signal to the user, with the PC pointing at
2c2fa1
the instruction past the int3, just like if GDB was not debugging the
2c2fa1
program.  The user may well decide to pass the SIGTRAP to the program
2c2fa1
because the program being debugged has a SIGTRAP handler that handles
2c2fa1
its own breakpoints, and expects the PC to be unadjusted.
2c2fa1
2c2fa1
Tested on x86-64 Fedora 20.
2c2fa1
2c2fa1
gdb/ChangeLog:
2c2fa1
2015-02-25  Pedro Alves  <palves@redhat.com>
2c2fa1
2c2fa1
	* breakpoint.c (need_moribund_for_location_type): New function.
2c2fa1
	(bpstat_stop_status): Don't skipping checking moribund locations
2c2fa1
	of breakpoint types which the target tell caused a stop.
2c2fa1
	(program_breakpoint_here_p): New function, factored out from ...
2c2fa1
	(bp_loc_is_permanent): ... this.
2c2fa1
	(update_global_location_list): Don't create a moribund location if
2c2fa1
	the target supports reporting stops of the type of the removed
2c2fa1
	breakpoint.
2c2fa1
	* breakpoint.h (program_breakpoint_here_p): New declaration.
2c2fa1
	* infrun.c (adjust_pc_after_break): Return early if the target has
2c2fa1
	already adjusted the PC.  Add comments.
2c2fa1
	(handle_signal_stop): If nothing explains a signal, and the target
2c2fa1
	tells us the stop was caused by a software breakpoint, check if
2c2fa1
	there's a breakpoint instruction in the memory.  If so, adjust the
2c2fa1
	PC before presenting the stop to the user.  Otherwise, ignore the
2c2fa1
	trap.  If nothing explains a signal, and the target tells us the
2c2fa1
	stop was caused by a hardware breakpoint, ignore the trap.
2c2fa1
	* target.h (struct target_ops) 
2c2fa1
	to_supports_stopped_by_sw_breakpoint, to_stopped_by_hw_breakpoint,
2c2fa1
	to_supports_stopped_by_hw_breakpoint>: New fields.
2c2fa1
	(target_stopped_by_sw_breakpoint)
2c2fa1
	(target_supports_stopped_by_sw_breakpoint)
2c2fa1
	(target_stopped_by_hw_breakpoint)
2c2fa1
	(target_supports_stopped_by_hw_breakpoint): Define.
2c2fa1
	* target-delegates.c: Regenerate.
2c2fa1
---
2c2fa1
 gdb/breakpoint.c       |  91 ++++++++++++++++++++++++------------
2c2fa1
 gdb/breakpoint.h       |   5 ++
2c2fa1
 gdb/infrun.c           |  70 +++++++++++++++++++++++++++-
2c2fa1
 gdb/target-delegates.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++++
2c2fa1
 gdb/target.h           |  44 ++++++++++++++++++
2c2fa1
 5 files changed, 303 insertions(+), 31 deletions(-)
2c2fa1
2c2fa1
Index: gdb-7.6.1/gdb/target.h
2c2fa1
===================================================================
2c2fa1
--- gdb-7.6.1.orig/gdb/target.h	2016-03-13 22:01:58.833963789 +0100
2c2fa1
+++ gdb-7.6.1/gdb/target.h	2016-03-13 22:01:59.950971809 +0100
2c2fa1
@@ -462,6 +462,16 @@
2c2fa1
     void (*to_files_info) (struct target_ops *);
2c2fa1
     int (*to_insert_breakpoint) (struct gdbarch *, struct bp_target_info *);
2c2fa1
     int (*to_remove_breakpoint) (struct gdbarch *, struct bp_target_info *);
2c2fa1
+
2c2fa1
+    /* Returns true if the target stopped for a hardware breakpoint.
2c2fa1
+       Likewise, if the target supports hardware breakpoints, this
2c2fa1
+       method is necessary for correct background execution / non-stop
2c2fa1
+       mode operation.  Even though hardware breakpoints do not
2c2fa1
+       require PC adjustment, GDB needs to be able to tell whether the
2c2fa1
+       hardware breakpoint event is a delayed event for a breakpoint
2c2fa1
+       that is already gone and should thus be ignored.  */
2c2fa1
+    int (*to_stopped_by_hw_breakpoint) (struct target_ops *);
2c2fa1
+
2c2fa1
     int (*to_can_use_hw_breakpoint) (int, int, int);
2c2fa1
     int (*to_ranged_break_num_registers) (struct target_ops *);
2c2fa1
     int (*to_insert_hw_breakpoint) (struct gdbarch *, struct bp_target_info *);
2c2fa1
@@ -1548,6 +1558,9 @@
2c2fa1
 #define target_stopped_by_watchpoint \
2c2fa1
    (*current_target.to_stopped_by_watchpoint)
2c2fa1
 
2c2fa1
+#define target_stopped_by_hw_breakpoint()				\
2c2fa1
+  ((*current_target.to_stopped_by_hw_breakpoint) (&current_target))
2c2fa1
+
2c2fa1
 /* Non-zero if we have steppable watchpoints  */
2c2fa1
 
2c2fa1
 #define target_have_steppable_watchpoint \
2c2fa1
Index: gdb-7.6.1/gdb/infrun.c
2c2fa1
===================================================================
2c2fa1
--- gdb-7.6.1.orig/gdb/infrun.c	2016-03-13 22:01:58.704962863 +0100
2c2fa1
+++ gdb-7.6.1/gdb/infrun.c	2016-03-13 22:17:33.735674697 +0100
2c2fa1
@@ -4295,6 +4295,18 @@
2c2fa1
 	ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_TRAP;
2c2fa1
     }
2c2fa1
 
2c2fa1
+  /* Maybe this was a trap for a hardware breakpoint/watchpoint that
2c2fa1
+     has since been removed.  */
2c2fa1
+  if (ecs->random_signal && target_stopped_by_hw_breakpoint())
2c2fa1
+    {
2c2fa1
+      /* A delayed hardware breakpoint event.  Ignore the trap.  */
2c2fa1
+      if (debug_infrun)
2c2fa1
+	fprintf_unfiltered (gdb_stdlog,
2c2fa1
+			    "infrun: delayed hardware breakpoint/watchpoint "
2c2fa1
+			    "trap, ignoring\n");
2c2fa1
+      ecs->random_signal = 0;
2c2fa1
+    }
2c2fa1
+
2c2fa1
 process_event_stop_test:
2c2fa1
 
2c2fa1
   /* Re-fetch current thread's frame in case we did a
2c2fa1
Index: gdb-7.6.1/gdb/target.c
2c2fa1
===================================================================
2c2fa1
--- gdb-7.6.1.orig/gdb/target.c	2016-03-13 22:01:58.832963782 +0100
2c2fa1
+++ gdb-7.6.1/gdb/target.c	2016-03-13 22:17:20.367578754 +0100
2c2fa1
@@ -726,6 +726,7 @@
2c2fa1
       /* Do not inherit to_memory_map.  */
2c2fa1
       /* Do not inherit to_flash_erase.  */
2c2fa1
       /* Do not inherit to_flash_done.  */
2c2fa1
+      INHERIT (to_stopped_by_hw_breakpoint, t);
2c2fa1
     }
2c2fa1
 #undef INHERIT
2c2fa1
 
2c2fa1
@@ -968,6 +969,9 @@
2c2fa1
 	    (int (*) (void))
2c2fa1
 	    return_zero);
2c2fa1
   de_fault (to_execution_direction, default_execution_direction);
2c2fa1
+  de_fault (to_stopped_by_hw_breakpoint,
2c2fa1
+	    (int (*) (struct target_ops *))
2c2fa1
+	    return_zero);
2c2fa1
 
2c2fa1
 #undef de_fault
2c2fa1