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

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