Blame SOURCES/gdb-rhbz1347993-aarch64-hw-watchpoint.patch

2c2fa1
commit a3b60e4588606354b93508a0008a5ca04b68fad8
2c2fa1
Author: Jan Kratochvil <jan.kratochvil@redhat.com>
2c2fa1
Date:   Fri May 4 22:22:04 2018 +0200
2c2fa1
2c2fa1
    aarch64: PR 19806: watchpoints: false negatives + PR 20207 contiguous ones
2c2fa1
    
2c2fa1
    Some unaligned watchpoints were currently missed.
2c2fa1
    
2c2fa1
    On old kernels as specified in
2c2fa1
            kernel RFE: aarch64: ptrace: BAS: Support any contiguous range (edit)
2c2fa1
            https://sourceware.org/bugzilla/show_bug.cgi?id=20207
2c2fa1
    after this patch some other unaligned watchpoints will get reported as false
2c2fa1
    positives.
2c2fa1
    
2c2fa1
    With new kernels all the watchpoints should work exactly.
2c2fa1
    
2c2fa1
    There may be a regresion that it now less merges watchpoints so that with
2c2fa1
    multiple overlapping watchpoints it may run out of the 4 hardware watchpoint
2c2fa1
    registers.  But as discussed in the original thread GDB needs some generic
2c2fa1
    watchpoints merging framework to be used by all the target specific code.
2c2fa1
    Even current FSF GDB code does not merge it perfectly.  Also with the more
2c2fa1
    precise watchpoints one can technically merge them less.  And I do not think
2c2fa1
    it matters too much to improve mergeability only for old kernels.
2c2fa1
    Still even on new kernels some better merging logic would make sense.
2c2fa1
    
2c2fa1
    There remains one issue:
2c2fa1
            kernel-4.15.14-300.fc27.armv7hl
2c2fa1
            FAIL: gdb.base/watchpoint-unaligned.exp: continue
2c2fa1
            FAIL: gdb.base/watchpoint-unaligned.exp: continue
2c2fa1
            (gdb) continue
2c2fa1
            Continuing.
2c2fa1
            Unexpected error setting watchpoint: Invalid argument.
2c2fa1
            (gdb) FAIL: gdb.base/watchpoint-unaligned.exp: continue
2c2fa1
    But that looks as a kernel bug to me.
2c2fa1
    (1) It is not a regression by this patch.
2c2fa1
    (2) It is unrelated to this patch.
2c2fa1
    
2c2fa1
    gdb/ChangeLog
2c2fa1
    2018-05-04  Jan Kratochvil  <jan.kratochvil@redhat.com>
2c2fa1
                Pedro Alves <palves@redhat.com>
2c2fa1
    
2c2fa1
            PR breakpoints/19806 and support for PR external/20207.
2c2fa1
            * NEWS: Mention Aarch64 watchpoint improvements.
2c2fa1
            * aarch64-linux-nat.c (aarch64_linux_stopped_data_address): Fix missed
2c2fa1
            watchpoints and PR external/20207 watchpoints.
2c2fa1
            * nat/aarch64-linux-hw-point.c
2c2fa1
            (kernel_supports_any_contiguous_range): New.
2c2fa1
            (aarch64_watchpoint_offset): New.
2c2fa1
            (aarch64_watchpoint_length): Support PR external/20207 watchpoints.
2c2fa1
            (aarch64_point_encode_ctrl_reg): New parameter offset, new asserts.
2c2fa1
            (aarch64_point_is_aligned): Support PR external/20207 watchpoints.
2c2fa1
            (aarch64_align_watchpoint): New parameters aligned_offset_p and
2c2fa1
            next_addr_orig_p.  Support PR external/20207 watchpoints.
2c2fa1
            (aarch64_downgrade_regs): New.
2c2fa1
            (aarch64_dr_state_insert_one_point): New parameters offset and
2c2fa1
            addr_orig.
2c2fa1
            (aarch64_dr_state_remove_one_point): Likewise.
2c2fa1
            (aarch64_handle_breakpoint): Update caller.
2c2fa1
            (aarch64_handle_aligned_watchpoint): Likewise.
2c2fa1
            (aarch64_handle_unaligned_watchpoint): Support addr_orig and
2c2fa1
            aligned_offset.
2c2fa1
            (aarch64_linux_set_debug_regs): Remove const from state.  Call
2c2fa1
            aarch64_downgrade_regs.
2c2fa1
            (aarch64_show_debug_reg_state): Print also dr_addr_orig_wp.
2c2fa1
            * nat/aarch64-linux-hw-point.h (DR_CONTROL_LENGTH): Rename to ...
2c2fa1
            (DR_CONTROL_MASK): ... this.
2c2fa1
            (struct aarch64_debug_reg_state): New field dr_addr_orig_wp.
2c2fa1
            (unsigned int aarch64_watchpoint_offset): New prototype.
2c2fa1
            (aarch64_linux_set_debug_regs): Remove const from state.
2c2fa1
            * utils.c (align_up, align_down): Move to ...
2c2fa1
            * common/common-utils.c (align_up, align_down): ... here.
2c2fa1
            * utils.h (align_up, align_down): Move to ...
2c2fa1
            * common/common-utils.h (align_up, align_down): ... here.
2c2fa1
    
2c2fa1
    gdb/gdbserver/ChangeLog
2c2fa1
    2018-05-04  Jan Kratochvil  <jan.kratochvil@redhat.com>
2c2fa1
                Pedro Alves <palves@redhat.com>
2c2fa1
    
2c2fa1
            * linux-aarch64-low.c (aarch64_stopped_data_address):
2c2fa1
            Likewise.
2c2fa1
    
2c2fa1
    gdb/testsuite/ChangeLog
2c2fa1
    2018-05-04  Jan Kratochvil  <jan.kratochvil@redhat.com>
2c2fa1
                Pedro Alves <palves@redhat.com>
2c2fa1
    
2c2fa1
            PR breakpoints/19806 and support for PR external/20207.
2c2fa1
            * gdb.base/watchpoint-unaligned.c: New file.
2c2fa1
            * gdb.base/watchpoint-unaligned.exp: New file.
2c2fa1
2c2fa1
### a/gdb/ChangeLog
2c2fa1
### b/gdb/ChangeLog
2c2fa1
## -1,3 +1,39 @@
2c2fa1
+2018-05-04  Jan Kratochvil  <jan.kratochvil@redhat.com>
2c2fa1
+	    Pedro Alves <palves@redhat.com>
2c2fa1
+
2c2fa1
+	PR breakpoints/19806 and support for PR external/20207.
2c2fa1
+	* NEWS: Mention Aarch64 watchpoint improvements.
2c2fa1
+	* aarch64-linux-nat.c (aarch64_linux_stopped_data_address): Fix missed
2c2fa1
+	watchpoints and PR external/20207 watchpoints.
2c2fa1
+	* nat/aarch64-linux-hw-point.c
2c2fa1
+	(kernel_supports_any_contiguous_range): New.
2c2fa1
+	(aarch64_watchpoint_offset): New.
2c2fa1
+	(aarch64_watchpoint_length): Support PR external/20207 watchpoints.
2c2fa1
+	(aarch64_point_encode_ctrl_reg): New parameter offset, new asserts.
2c2fa1
+	(aarch64_point_is_aligned): Support PR external/20207 watchpoints.
2c2fa1
+	(aarch64_align_watchpoint): New parameters aligned_offset_p and
2c2fa1
+	next_addr_orig_p.  Support PR external/20207 watchpoints.
2c2fa1
+	(aarch64_downgrade_regs): New.
2c2fa1
+	(aarch64_dr_state_insert_one_point): New parameters offset and
2c2fa1
+	addr_orig.
2c2fa1
+	(aarch64_dr_state_remove_one_point): Likewise.
2c2fa1
+	(aarch64_handle_breakpoint): Update caller.
2c2fa1
+	(aarch64_handle_aligned_watchpoint): Likewise.
2c2fa1
+	(aarch64_handle_unaligned_watchpoint): Support addr_orig and
2c2fa1
+	aligned_offset.
2c2fa1
+	(aarch64_linux_set_debug_regs): Remove const from state.  Call
2c2fa1
+	aarch64_downgrade_regs.
2c2fa1
+	(aarch64_show_debug_reg_state): Print also dr_addr_orig_wp.
2c2fa1
+	* nat/aarch64-linux-hw-point.h (DR_CONTROL_LENGTH): Rename to ...
2c2fa1
+	(DR_CONTROL_MASK): ... this.
2c2fa1
+	(struct aarch64_debug_reg_state): New field dr_addr_orig_wp.
2c2fa1
+	(unsigned int aarch64_watchpoint_offset): New prototype.
2c2fa1
+	(aarch64_linux_set_debug_regs): Remove const from state.
2c2fa1
+	* utils.c (align_up, align_down): Move to ...
2c2fa1
+	* common/common-utils.c (align_up, align_down): ... here.
2c2fa1
+	* utils.h (align_up, align_down): Move to ...
2c2fa1
+	* common/common-utils.h (align_up, align_down): ... here.
2c2fa1
+
2c2fa1
 2018-05-04  Joel Brobecker  <brobecker@adacore.com>
2c2fa1
 
2c2fa1
 	* sparc-tdep.c (sparc_structure_return_p): Re-implement to
2c2fa1
Index: gdb-7.6.1/gdb/NEWS
2c2fa1
===================================================================
2c2fa1
--- gdb-7.6.1.orig/gdb/NEWS	2018-05-05 17:12:48.170769374 +0200
2c2fa1
+++ gdb-7.6.1/gdb/NEWS	2018-05-05 17:12:49.569781872 +0200
2c2fa1
@@ -4,6 +4,16 @@
2c2fa1
 * Newly installed $prefix/bin/gcore acts as a shell interface for the
2c2fa1
   GDB command gcore.
2c2fa1
 
2c2fa1
+* Aarch64/Linux hardware watchpoints improvements
2c2fa1
+
2c2fa1
+  Hardware watchpoints on unaligned addresses are now properly
2c2fa1
+  supported when running Linux kernel 4.10 or higher: read and access
2c2fa1
+  watchpoints are no longer spuriously missed, and all watchpoints
2c2fa1
+  lengths between 1 and 8 bytes are supported.  On older kernels,
2c2fa1
+  watchpoints set on unaligned addresses are no longer missed, with
2c2fa1
+  the tradeoff that there is a possibility of false hits being
2c2fa1
+  reported.
2c2fa1
+
2c2fa1
 *** Changes in GDB 7.6
2c2fa1
 
2c2fa1
 * Target record has been renamed to record-full.
2c2fa1
Index: gdb-7.6.1/gdb/aarch64-linux-nat.c
2c2fa1
===================================================================
2c2fa1
--- gdb-7.6.1.orig/gdb/aarch64-linux-nat.c	2018-05-05 17:12:47.474763150 +0200
2c2fa1
+++ gdb-7.6.1/gdb/aarch64-linux-nat.c	2018-05-05 17:12:49.570781881 +0200
2c2fa1
@@ -45,6 +45,18 @@
2c2fa1
 #define TRAP_HWBKPT 0x0004
2c2fa1
 #endif
2c2fa1
 
2c2fa1
+/* ptrace expects control registers to be formatted as follows:
2c2fa1
+
2c2fa1
+   31                             13          5      3      1     0
2c2fa1
+   +--------------------------------+----------+------+------+----+
2c2fa1
+   |         RESERVED (SBZ)         |   MASK   | TYPE | PRIV | EN |
2c2fa1
+   +--------------------------------+----------+------+------+----+
2c2fa1
+
2c2fa1
+   The TYPE field is ignored for breakpoints.  */
2c2fa1
+
2c2fa1
+#define DR_CONTROL_ENABLED(ctrl)	(((ctrl) & 0x1) == 1)
2c2fa1
+#define DR_CONTROL_MASK(ctrl)		(((ctrl) >> 5) & 0xff)
2c2fa1
+
2c2fa1
 /* On GNU/Linux, threads are implemented as pseudo-processes, in which
2c2fa1
    case we may be tracing more than one process at a time.  In that
2c2fa1
    case, inferior_ptid will contain the main process ID and the
2c2fa1
@@ -118,6 +130,29 @@
2c2fa1
 static int aarch64_num_bp_regs;
2c2fa1
 static int aarch64_num_wp_regs;
2c2fa1
 
2c2fa1
+/* True if this kernel does not have the bug described by PR
2c2fa1
+   external/20207 (Linux >= 4.10).  A fixed kernel supports any
2c2fa1
+   contiguous range of bits in 8-bit byte DR_CONTROL_MASK.  A buggy
2c2fa1
+   kernel supports only 0x01, 0x03, 0x0f and 0xff.  We start by
2c2fa1
+   assuming the bug is fixed, and then detect the bug at
2c2fa1
+   PTRACE_SETREGSET time.  */
2c2fa1
+static int kernel_supports_any_contiguous_range = 1;
2c2fa1
+
2c2fa1
+/* Return starting byte 0..7 incl. of a watchpoint encoded by CTRL.  */
2c2fa1
+
2c2fa1
+static unsigned int
2c2fa1
+aarch64_watchpoint_offset (unsigned int ctrl)
2c2fa1
+{
2c2fa1
+  uint8_t mask = DR_CONTROL_MASK (ctrl);
2c2fa1
+  unsigned retval;
2c2fa1
+
2c2fa1
+  /* Shift out bottom zeros.  */
2c2fa1
+  for (retval = 0; mask && (mask & 1) == 0; ++retval)
2c2fa1
+    mask >>= 1;
2c2fa1
+
2c2fa1
+  return retval;
2c2fa1
+}
2c2fa1
+
2c2fa1
 /* Debugging of hardware breakpoint/watchpoint support.  */
2c2fa1
 
2c2fa1
 static int debug_hw_points;
2c2fa1
@@ -184,7 +219,10 @@
2c2fa1
   unsigned int dr_ref_count_bp[AARCH64_HBP_MAX_NUM];
2c2fa1
 
2c2fa1
   /* hardware watchpoint */
2c2fa1
+  /* Address aligned down to AARCH64_HWP_ALIGNMENT.  */
2c2fa1
   CORE_ADDR dr_addr_wp[AARCH64_HWP_MAX_NUM];
2c2fa1
+  /* Address as entered by user without any forced alignment.  */
2c2fa1
+  CORE_ADDR dr_addr_orig_wp[AARCH64_HWP_MAX_NUM];
2c2fa1
   unsigned int dr_ctrl_wp[AARCH64_HWP_MAX_NUM];
2c2fa1
   unsigned int dr_ref_count_wp[AARCH64_HWP_MAX_NUM];
2c2fa1
 };
2c2fa1
@@ -299,11 +337,76 @@
2c2fa1
   dr_changed_t dr_changed_wp;
2c2fa1
 };
2c2fa1
 
2c2fa1
+/* Reconfigure STATE to be compatible with Linux kernels with the PR
2c2fa1
+   external/20207 bug.  This is called when
2c2fa1
+   KERNEL_SUPPORTS_ANY_CONTIGUOUS_RANGE transitions to false.  Note we
2c2fa1
+   don't try to support combining watchpoints with matching (and thus
2c2fa1
+   shared) masks, as it's too late when we get here.  On buggy
2c2fa1
+   kernels, GDB will try to first setup the perfect matching ranges,
2c2fa1
+   which will run out of registers before this function can merge
2c2fa1
+   them.  It doesn't look like worth the effort to improve that, given
2c2fa1
+   eventually buggy kernels will be phased out.  */
2c2fa1
+
2c2fa1
+static void aarch64_notify_debug_reg_change (const struct aarch64_debug_reg_state *state, int is_watchpoint, unsigned int idx);
2c2fa1
+
2c2fa1
+static void
2c2fa1
+aarch64_downgrade_regs (struct aarch64_debug_reg_state *state)
2c2fa1
+{
2c2fa1
+  int i;
2c2fa1
+
2c2fa1
+  for (i = 0; i < aarch64_num_wp_regs; ++i)
2c2fa1
+    if ((state->dr_ctrl_wp[i] & 1) != 0)
2c2fa1
+      {
2c2fa1
+	uint8_t mask_orig;
2c2fa1
+	static const uint8_t old_valid[] = { 0x01, 0x03, 0x0f, 0xff };
2c2fa1
+	int old_validi;
2c2fa1
+	uint8_t mask = 0;
2c2fa1
+	int j;
2c2fa1
+
2c2fa1
+	gdb_assert (state->dr_ref_count_wp[i] != 0);
2c2fa1
+	mask_orig = (state->dr_ctrl_wp[i] >> 5) & 0xff;
2c2fa1
+	gdb_assert (mask_orig != 0);
2c2fa1
+	for (old_validi = 0; old_validi < sizeof(old_valid) / sizeof (*old_valid); old_validi++) {
2c2fa1
+	  const uint8_t old_mask = old_valid[old_validi];
2c2fa1
+	  if (mask_orig <= old_mask)
2c2fa1
+	    {
2c2fa1
+	      mask = old_mask;
2c2fa1
+	      break;
2c2fa1
+	    }
2c2fa1
+	}
2c2fa1
+	gdb_assert (mask != 0);
2c2fa1
+
2c2fa1
+	/* No update needed for this watchpoint?  */
2c2fa1
+	if (mask == mask_orig)
2c2fa1
+	  continue;
2c2fa1
+	state->dr_ctrl_wp[i] |= mask << 5;
2c2fa1
+	state->dr_addr_wp[i]
2c2fa1
+	  = align_down (state->dr_addr_wp[i], AARCH64_HWP_ALIGNMENT);
2c2fa1
+
2c2fa1
+	/* Try to match duplicate entries.  */
2c2fa1
+	for (j = 0; j < i; ++j)
2c2fa1
+	  if ((state->dr_ctrl_wp[j] & 1) != 0
2c2fa1
+	      && state->dr_addr_wp[j] == state->dr_addr_wp[i]
2c2fa1
+	      && state->dr_addr_orig_wp[j] == state->dr_addr_orig_wp[i]
2c2fa1
+	      && state->dr_ctrl_wp[j] == state->dr_ctrl_wp[i])
2c2fa1
+	    {
2c2fa1
+	      state->dr_ref_count_wp[j] += state->dr_ref_count_wp[i];
2c2fa1
+	      state->dr_ref_count_wp[i] = 0;
2c2fa1
+	      state->dr_addr_wp[i] = 0;
2c2fa1
+	      state->dr_addr_orig_wp[i] = 0;
2c2fa1
+	      state->dr_ctrl_wp[i] &= ~1;
2c2fa1
+	      break;
2c2fa1
+	    }
2c2fa1
+
2c2fa1
+	aarch64_notify_debug_reg_change (state, 1 /* is_watchpoint */, i);
2c2fa1
+      }
2c2fa1
+}
2c2fa1
+
2c2fa1
 /* Call ptrace to set the thread TID's hardware breakpoint/watchpoint
2c2fa1
    registers with data from *STATE.  */
2c2fa1
 
2c2fa1
 static void
2c2fa1
-aarch64_linux_set_debug_regs (const struct aarch64_debug_reg_state *state,
2c2fa1
+aarch64_linux_set_debug_regs (struct aarch64_debug_reg_state *state,
2c2fa1
 			      int tid, int watchpoint)
2c2fa1
 {
2c2fa1
   int i, count;
2c2fa1
@@ -331,7 +434,18 @@
2c2fa1
   if (ptrace (PTRACE_SETREGSET, tid,
2c2fa1
 	      watchpoint ? NT_ARM_HW_WATCH : NT_ARM_HW_BREAK,
2c2fa1
 	      (void *) &iov))
2c2fa1
-    error (_("Unexpected error setting hardware debug registers"));
2c2fa1
+    {
2c2fa1
+      /* Handle Linux kernels with the PR external/20207 bug.  */
2c2fa1
+      if (watchpoint && errno == EINVAL
2c2fa1
+	  && kernel_supports_any_contiguous_range)
2c2fa1
+	{
2c2fa1
+	  kernel_supports_any_contiguous_range = 0;
2c2fa1
+	  aarch64_downgrade_regs (state);
2c2fa1
+	  aarch64_linux_set_debug_regs (state, tid, watchpoint);
2c2fa1
+	  return;
2c2fa1
+	}
2c2fa1
+      error (_("Unexpected error setting hardware debug registers"));
2c2fa1
+    }
2c2fa1
 }
2c2fa1
 
2c2fa1
 struct aarch64_dr_update_callback_param
2c2fa1
@@ -452,8 +566,8 @@
2c2fa1
   fprintf_unfiltered (gdb_stdlog, "\tWATCHPOINTs:\n");
2c2fa1
   for (i = 0; i < aarch64_num_wp_regs; i++)
2c2fa1
     fprintf_unfiltered (gdb_stdlog,
2c2fa1
-			"\tWP%d: addr=0x%08lx, ctrl=0x%08x, ref.count=%d\n",
2c2fa1
-			i, state->dr_addr_wp[i],
2c2fa1
+			"\tWP%d: addr=0x%08lx (orig=0x%08lx), ctrl=0x%08x, ref.count=%d\n",
2c2fa1
+			i, state->dr_addr_wp[i], state->dr_addr_orig_wp[i],
2c2fa1
 			state->dr_ctrl_wp[i], state->dr_ref_count_wp[i]);
2c2fa1
 }
2c2fa1
 
2c2fa1
@@ -850,28 +964,30 @@
2c2fa1
 }
2c2fa1
 
2c2fa1
 /* Given the (potentially unaligned) watchpoint address in ADDR and
2c2fa1
-   length in LEN, return the aligned address and aligned length in
2c2fa1
-   *ALIGNED_ADDR_P and *ALIGNED_LEN_P, respectively.  The returned
2c2fa1
-   aligned address and length will be valid values to write to the
2c2fa1
-   hardware watchpoint value and control registers.
2c2fa1
+   length in LEN, return the aligned address, offset from that base
2c2fa1
+   address, and aligned length in *ALIGNED_ADDR_P, *ALIGNED_OFFSET_P
2c2fa1
+   and *ALIGNED_LEN_P, respectively.  The returned values will be
2c2fa1
+   valid values to write to the hardware watchpoint value and control
2c2fa1
+   registers.
2c2fa1
 
2c2fa1
    The given watchpoint may get truncated if more than one hardware
2c2fa1
    register is needed to cover the watched region.  *NEXT_ADDR_P
2c2fa1
    and *NEXT_LEN_P, if non-NULL, will return the address and length
2c2fa1
    of the remaining part of the watchpoint (which can be processed
2c2fa1
-   by calling this routine again to generate another aligned address
2c2fa1
-   and length pair.
2c2fa1
+   by calling this routine again to generate another aligned address,
2c2fa1
+   offset and length tuple.
2c2fa1
 
2c2fa1
    See the comment above the function of the same name in
2c2fa1
    gdbserver/linux-aarch64-low.c for more information.  */
2c2fa1
 
2c2fa1
 static void
2c2fa1
 aarch64_align_watchpoint (CORE_ADDR addr, int len, CORE_ADDR *aligned_addr_p,
2c2fa1
-			  int *aligned_len_p, CORE_ADDR *next_addr_p,
2c2fa1
-			  int *next_len_p)
2c2fa1
+			  int *aligned_offset_p, int *aligned_len_p,
2c2fa1
+			  CORE_ADDR *next_addr_p, int *next_len_p,
2c2fa1
+			  CORE_ADDR *next_addr_orig_p)
2c2fa1
 {
2c2fa1
   int aligned_len;
2c2fa1
-  unsigned int offset;
2c2fa1
+  unsigned int offset, aligned_offset;
2c2fa1
   CORE_ADDR aligned_addr;
2c2fa1
   const unsigned int alignment = AARCH64_HWP_ALIGNMENT;
2c2fa1
   const unsigned int max_wp_len = AARCH64_HWP_MAX_LEN_PER_REG;
2c2fa1
@@ -882,10 +998,12 @@
2c2fa1
   if (len <= 0)
2c2fa1
     return;
2c2fa1
 
2c2fa1
-  /* Address to be put into the hardware watchpoint value register
2c2fa1
-     must be aligned.  */
2c2fa1
+  /* The address put into the hardware watchpoint value register must
2c2fa1
+     be aligned.  */
2c2fa1
   offset = addr & (alignment - 1);
2c2fa1
   aligned_addr = addr - offset;
2c2fa1
+  aligned_offset
2c2fa1
+    = kernel_supports_any_contiguous_range ? addr & (alignment - 1) : 0;
2c2fa1
 
2c2fa1
   gdb_assert (offset >= 0 && offset < alignment);
2c2fa1
   gdb_assert (aligned_addr >= 0 && aligned_addr <= addr);
2c2fa1
@@ -893,9 +1011,10 @@
2c2fa1
 
2c2fa1
   if (offset + len >= max_wp_len)
2c2fa1
     {
2c2fa1
-      /* Need more than one watchpoint registers; truncate it at the
2c2fa1
+      /* Need more than one watchpoint register; truncate at the
2c2fa1
          alignment boundary.  */
2c2fa1
-      aligned_len = max_wp_len;
2c2fa1
+      aligned_len
2c2fa1
+	= max_wp_len - (kernel_supports_any_contiguous_range ? offset : 0);
2c2fa1
       len -= (max_wp_len - offset);
2c2fa1
       addr += (max_wp_len - offset);
2c2fa1
       gdb_assert ((addr & (alignment - 1)) == 0);
2c2fa1
@@ -908,19 +1027,24 @@
2c2fa1
 	aligned_len_array[AARCH64_HWP_MAX_LEN_PER_REG] =
2c2fa1
 	{ 1, 2, 4, 4, 8, 8, 8, 8 };
2c2fa1
 
2c2fa1
-      aligned_len = aligned_len_array[offset + len - 1];
2c2fa1
+      aligned_len = (kernel_supports_any_contiguous_range
2c2fa1
+		     ? len : aligned_len_array[offset + len - 1]);
2c2fa1
       addr += len;
2c2fa1
       len = 0;
2c2fa1
     }
2c2fa1
 
2c2fa1
   if (aligned_addr_p)
2c2fa1
     *aligned_addr_p = aligned_addr;
2c2fa1
+  if (aligned_offset_p)
2c2fa1
+    *aligned_offset_p = aligned_offset;
2c2fa1
   if (aligned_len_p)
2c2fa1
     *aligned_len_p = aligned_len;
2c2fa1
   if (next_addr_p)
2c2fa1
     *next_addr_p = addr;
2c2fa1
   if (next_len_p)
2c2fa1
     *next_len_p = len;
2c2fa1
+  if (next_addr_orig_p)
2c2fa1
+    *next_addr_orig_p = align_down (*next_addr_orig_p + alignment, alignment);
2c2fa1
 }
2c2fa1
 
2c2fa1
 /* Returns the number of hardware watchpoints of type TYPE that we can
2c2fa1
@@ -946,41 +1070,29 @@
2c2fa1
   return 1;
2c2fa1
 }
2c2fa1
 
2c2fa1
-/* ptrace expects control registers to be formatted as follows:
2c2fa1
-
2c2fa1
-   31                             13          5      3      1     0
2c2fa1
-   +--------------------------------+----------+------+------+----+
2c2fa1
-   |         RESERVED (SBZ)         |  LENGTH  | TYPE | PRIV | EN |
2c2fa1
-   +--------------------------------+----------+------+------+----+
2c2fa1
-
2c2fa1
-   The TYPE field is ignored for breakpoints.  */
2c2fa1
-
2c2fa1
-#define DR_CONTROL_ENABLED(ctrl)	(((ctrl) & 0x1) == 1)
2c2fa1
-#define DR_CONTROL_LENGTH(ctrl)		(((ctrl) >> 5) & 0xff)
2c2fa1
-
2c2fa1
 /* Utility function that returns the length in bytes of a watchpoint
2c2fa1
    according to the content of a hardware debug control register CTRL.
2c2fa1
-   Note that the kernel currently only supports the following Byte
2c2fa1
-   Address Select (BAS) values: 0x1, 0x3, 0xf and 0xff, which means
2c2fa1
-   that for a hardware watchpoint, its valid length can only be 1
2c2fa1
-   byte, 2 bytes, 4 bytes or 8 bytes.  */
2c2fa1
+   Any contiguous range of bytes in CTRL is supported.  The returned
2c2fa1
+   value can be between 0..8 (inclusive).  */
2c2fa1
 
2c2fa1
 static inline unsigned int
2c2fa1
 aarch64_watchpoint_length (unsigned int ctrl)
2c2fa1
 {
2c2fa1
-  switch (DR_CONTROL_LENGTH (ctrl))
2c2fa1
-    {
2c2fa1
-    case 0x01:
2c2fa1
-      return 1;
2c2fa1
-    case 0x03:
2c2fa1
-      return 2;
2c2fa1
-    case 0x0f:
2c2fa1
-      return 4;
2c2fa1
-    case 0xff:
2c2fa1
-      return 8;
2c2fa1
-    default:
2c2fa1
-      return 0;
2c2fa1
-    }
2c2fa1
+  uint8_t mask = DR_CONTROL_MASK (ctrl);
2c2fa1
+  unsigned retval;
2c2fa1
+
2c2fa1
+  /* Shift out bottom zeros.  */
2c2fa1
+  mask >>= aarch64_watchpoint_offset (ctrl);
2c2fa1
+
2c2fa1
+  /* Count bottom ones.  */
2c2fa1
+  for (retval = 0; (mask & 1) != 0; ++retval)
2c2fa1
+    mask >>= 1;
2c2fa1
+
2c2fa1
+  if (mask != 0)
2c2fa1
+    error (_("Unexpected hardware watchpoint length register value 0x%x"),
2c2fa1
+	   DR_CONTROL_MASK (ctrl));
2c2fa1
+
2c2fa1
+  return retval;
2c2fa1
 }
2c2fa1
 
2c2fa1
 /* Given the hardware breakpoint or watchpoint type TYPE and its
2c2fa1
@@ -988,10 +1100,13 @@
2c2fa1
    breakpoint/watchpoint control register.  */
2c2fa1
 
2c2fa1
 static unsigned int
2c2fa1
-aarch64_point_encode_ctrl_reg (int type, int len)
2c2fa1
+aarch64_point_encode_ctrl_reg (int type, int offset, int len)
2c2fa1
 {
2c2fa1
   unsigned int ctrl, ttype;
2c2fa1
 
2c2fa1
+  gdb_assert (offset == 0 || kernel_supports_any_contiguous_range);
2c2fa1
+  gdb_assert (offset + len <= AARCH64_HWP_MAX_LEN_PER_REG);
2c2fa1
+
2c2fa1
   /* type */
2c2fa1
   switch (type)
2c2fa1
     {
2c2fa1
@@ -1012,8 +1127,8 @@
2c2fa1
     }
2c2fa1
   ctrl = ttype << 3;
2c2fa1
 
2c2fa1
-  /* length bitmask */
2c2fa1
-  ctrl |= ((1 << len) - 1) << 5;
2c2fa1
+  /* offset and length bitmask */
2c2fa1
+  ctrl |= ((1 << len) - 1) << (5 + offset);
2c2fa1
   /* enabled at el0 */
2c2fa1
   ctrl |= (2 << 1) | 1;
2c2fa1
 
2c2fa1
@@ -1042,7 +1157,10 @@
2c2fa1
   if (addr & (alignment - 1))
2c2fa1
     return 0;
2c2fa1
 
2c2fa1
-  if (len != 8 && len != 4 && len != 2 && len != 1)
2c2fa1
+  if ((!kernel_supports_any_contiguous_range
2c2fa1
+       && len != 8 && len != 4 && len != 2 && len != 1)
2c2fa1
+      || (kernel_supports_any_contiguous_range
2c2fa1
+	  && (len < 1 || len > 8)))
2c2fa1
     return 0;
2c2fa1
 
2c2fa1
   return 1;
2c2fa1
@@ -1053,11 +1171,12 @@
2c2fa1
 
2c2fa1
 static int
2c2fa1
 aarch64_dr_state_insert_one_point (struct aarch64_debug_reg_state *state,
2c2fa1
-				   int type, CORE_ADDR addr, int len)
2c2fa1
+				   int type, CORE_ADDR addr, int offset, int len,
2c2fa1
+				   CORE_ADDR addr_orig)
2c2fa1
 {
2c2fa1
   int i, idx, num_regs, is_watchpoint;
2c2fa1
   unsigned int ctrl, *dr_ctrl_p, *dr_ref_count;
2c2fa1
-  CORE_ADDR *dr_addr_p;
2c2fa1
+  CORE_ADDR *dr_addr_p, *dr_addr_orig_p;
2c2fa1
 
2c2fa1
   /* Set up state pointers.  */
2c2fa1
   is_watchpoint = (type != hw_execute);
2c2fa1
@@ -1066,6 +1185,7 @@
2c2fa1
     {
2c2fa1
       num_regs = aarch64_num_wp_regs;
2c2fa1
       dr_addr_p = state->dr_addr_wp;
2c2fa1
+      dr_addr_orig_p = state->dr_addr_orig_wp;
2c2fa1
       dr_ctrl_p = state->dr_ctrl_wp;
2c2fa1
       dr_ref_count = state->dr_ref_count_wp;
2c2fa1
     }
2c2fa1
@@ -1073,11 +1193,12 @@
2c2fa1
     {
2c2fa1
       num_regs = aarch64_num_bp_regs;
2c2fa1
       dr_addr_p = state->dr_addr_bp;
2c2fa1
+      dr_addr_orig_p = NULL;
2c2fa1
       dr_ctrl_p = state->dr_ctrl_bp;
2c2fa1
       dr_ref_count = state->dr_ref_count_bp;
2c2fa1
     }
2c2fa1
 
2c2fa1
-  ctrl = aarch64_point_encode_ctrl_reg (type, len);
2c2fa1
+  ctrl = aarch64_point_encode_ctrl_reg (type, offset, len);
2c2fa1
 
2c2fa1
   /* Find an existing or free register in our cache.  */
2c2fa1
   idx = -1;
2c2fa1
@@ -1089,7 +1210,9 @@
2c2fa1
 	  idx = i;
2c2fa1
 	  /* no break; continue hunting for an existing one.  */
2c2fa1
 	}
2c2fa1
-      else if (dr_addr_p[i] == addr && dr_ctrl_p[i] == ctrl)
2c2fa1
+      else if (dr_addr_p[i] == addr
2c2fa1
+	       && (dr_addr_orig_p == NULL || dr_addr_orig_p[i] == addr_orig)
2c2fa1
+	       && dr_ctrl_p[i] == ctrl)
2c2fa1
 	{
2c2fa1
 	  gdb_assert (dr_ref_count[i] != 0);
2c2fa1
 	  idx = i;
2c2fa1
@@ -1106,6 +1229,8 @@
2c2fa1
     {
2c2fa1
       /* new entry */
2c2fa1
       dr_addr_p[idx] = addr;
2c2fa1
+      if (dr_addr_orig_p != NULL)
2c2fa1
+	dr_addr_orig_p[idx] = addr_orig;
2c2fa1
       dr_ctrl_p[idx] = ctrl;
2c2fa1
       dr_ref_count[idx] = 1;
2c2fa1
       /* Notify the change.  */
2c2fa1
@@ -1125,11 +1250,12 @@
2c2fa1
 
2c2fa1
 static int
2c2fa1
 aarch64_dr_state_remove_one_point (struct aarch64_debug_reg_state *state,
2c2fa1
-				   int type, CORE_ADDR addr, int len)
2c2fa1
+				   int type, CORE_ADDR addr, int offset, int len,
2c2fa1
+				   CORE_ADDR addr_orig)
2c2fa1
 {
2c2fa1
   int i, num_regs, is_watchpoint;
2c2fa1
   unsigned int ctrl, *dr_ctrl_p, *dr_ref_count;
2c2fa1
-  CORE_ADDR *dr_addr_p;
2c2fa1
+  CORE_ADDR *dr_addr_p, *dr_addr_orig_p;
2c2fa1
 
2c2fa1
   /* Set up state pointers.  */
2c2fa1
   is_watchpoint = (type != hw_execute);
2c2fa1
@@ -1138,6 +1264,7 @@
2c2fa1
     {
2c2fa1
       num_regs = aarch64_num_wp_regs;
2c2fa1
       dr_addr_p = state->dr_addr_wp;
2c2fa1
+      dr_addr_orig_p = state->dr_addr_orig_wp;
2c2fa1
       dr_ctrl_p = state->dr_ctrl_wp;
2c2fa1
       dr_ref_count = state->dr_ref_count_wp;
2c2fa1
     }
2c2fa1
@@ -1145,15 +1272,18 @@
2c2fa1
     {
2c2fa1
       num_regs = aarch64_num_bp_regs;
2c2fa1
       dr_addr_p = state->dr_addr_bp;
2c2fa1
+      dr_addr_orig_p = NULL;
2c2fa1
       dr_ctrl_p = state->dr_ctrl_bp;
2c2fa1
       dr_ref_count = state->dr_ref_count_bp;
2c2fa1
     }
2c2fa1
 
2c2fa1
-  ctrl = aarch64_point_encode_ctrl_reg (type, len);
2c2fa1
+  ctrl = aarch64_point_encode_ctrl_reg (type, offset, len);
2c2fa1
 
2c2fa1
   /* Find the entry that matches the ADDR and CTRL.  */
2c2fa1
   for (i = 0; i < num_regs; ++i)
2c2fa1
-    if (dr_addr_p[i] == addr && dr_ctrl_p[i] == ctrl)
2c2fa1
+    if (dr_addr_p[i] == addr
2c2fa1
+	&& (dr_addr_orig_p == NULL || dr_addr_orig_p[i] == addr_orig)
2c2fa1
+	&& dr_ctrl_p[i] == ctrl)
2c2fa1
       {
2c2fa1
 	gdb_assert (dr_ref_count[i] != 0);
2c2fa1
 	break;
2c2fa1
@@ -1169,6 +1299,8 @@
2c2fa1
       /* Clear the enable bit.  */
2c2fa1
       ctrl &= ~1;
2c2fa1
       dr_addr_p[i] = 0;
2c2fa1
+      if (dr_addr_orig_p != NULL)
2c2fa1
+	dr_addr_orig_p[i] = 0;
2c2fa1
       dr_ctrl_p[i] = ctrl;
2c2fa1
       /* Notify the change.  */
2c2fa1
       aarch64_notify_debug_reg_change (state, is_watchpoint, i);
2c2fa1
@@ -1192,9 +1324,9 @@
2c2fa1
   state = aarch64_get_debug_reg_state (ptid_get_pid (inferior_ptid));
2c2fa1
 
2c2fa1
   if (is_insert)
2c2fa1
-    return aarch64_dr_state_insert_one_point (state, type, addr, len);
2c2fa1
+    return aarch64_dr_state_insert_one_point (state, type, addr, 0, len, -1);
2c2fa1
   else
2c2fa1
-    return aarch64_dr_state_remove_one_point (state, type, addr, len);
2c2fa1
+    return aarch64_dr_state_remove_one_point (state, type, addr, 0, len, -1);
2c2fa1
 }
2c2fa1
 
2c2fa1
 /* Insert a hardware-assisted breakpoint at BP_TGT->placed_address.
2c2fa1
@@ -1271,9 +1403,9 @@
2c2fa1
     = aarch64_get_debug_reg_state (ptid_get_pid (inferior_ptid));
2c2fa1
 
2c2fa1
   if (is_insert)
2c2fa1
-    return aarch64_dr_state_insert_one_point (state, type, addr, len);
2c2fa1
+    return aarch64_dr_state_insert_one_point (state, type, addr, 0, len, addr);
2c2fa1
   else
2c2fa1
-    return aarch64_dr_state_remove_one_point (state, type, addr, len);
2c2fa1
+    return aarch64_dr_state_remove_one_point (state, type, addr, 0, len, addr);
2c2fa1
 }
2c2fa1
 
2c2fa1
 /* Insert/remove unaligned watchpoint by calling
2c2fa1
@@ -1289,28 +1421,41 @@
2c2fa1
 {
2c2fa1
   struct aarch64_debug_reg_state *state
2c2fa1
     = aarch64_get_debug_reg_state (ptid_get_pid (inferior_ptid));
2c2fa1
+  CORE_ADDR addr_orig = addr;
2c2fa1
 
2c2fa1
   while (len > 0)
2c2fa1
     {
2c2fa1
       CORE_ADDR aligned_addr;
2c2fa1
-      int aligned_len, ret;
2c2fa1
+      int aligned_offset, aligned_len, ret;
2c2fa1
+      CORE_ADDR addr_orig_next = addr_orig;
2c2fa1
 
2c2fa1
-      aarch64_align_watchpoint (addr, len, &aligned_addr, &aligned_len,
2c2fa1
-				&addr, &len;;
2c2fa1
+      aarch64_align_watchpoint (addr, len, &aligned_addr, &aligned_offset,
2c2fa1
+				&aligned_len, &addr, &len, &addr_orig_next);
2c2fa1
 
2c2fa1
       if (is_insert)
2c2fa1
 	ret = aarch64_dr_state_insert_one_point (state, type, aligned_addr,
2c2fa1
-						 aligned_len);
2c2fa1
+						 aligned_offset,
2c2fa1
+						 aligned_len, addr_orig);
2c2fa1
       else
2c2fa1
 	ret = aarch64_dr_state_remove_one_point (state, type, aligned_addr,
2c2fa1
-						 aligned_len);
2c2fa1
+						 aligned_offset,
2c2fa1
+						 aligned_len, addr_orig);
2c2fa1
 
2c2fa1
       if (debug_hw_points)
2c2fa1
 	fprintf_unfiltered (gdb_stdlog,
2c2fa1
 "handle_unaligned_watchpoint: is_insert: %d\n"
2c2fa1
 "                             aligned_addr: 0x%08lx, aligned_len: %d\n"
2c2fa1
-"                                next_addr: 0x%08lx,    next_len: %d\n",
2c2fa1
-		 is_insert, aligned_addr, aligned_len, addr, len);
2c2fa1
+"                                addr_orig: %s\n"
2c2fa1
+"                                                                "
2c2fa1
+"                                next_addr: %s,    next_len: %d\n"
2c2fa1
+"                                                           "
2c2fa1
+"                                addr_orig_next: %s\n",
2c2fa1
+		 is_insert, aligned_addr,
2c2fa1
+		      aligned_len, core_addr_to_string_nz (addr_orig),
2c2fa1
+		      core_addr_to_string_nz (addr), len,
2c2fa1
+		      core_addr_to_string_nz (addr_orig_next));
2c2fa1
+
2c2fa1
+      addr_orig = addr_orig_next;
2c2fa1
 
2c2fa1
       if (ret != 0)
2c2fa1
 	return ret;
2c2fa1
@@ -1456,16 +1601,38 @@
2c2fa1
   state = aarch64_get_debug_reg_state (ptid_get_pid (inferior_ptid));
2c2fa1
   for (i = aarch64_num_wp_regs - 1; i >= 0; --i)
2c2fa1
     {
2c2fa1
+      const unsigned int offset
2c2fa1
+	= aarch64_watchpoint_offset (state->dr_ctrl_wp[i]);
2c2fa1
       const unsigned int len = aarch64_watchpoint_length (state->dr_ctrl_wp[i]);
2c2fa1
       const CORE_ADDR addr_trap = (CORE_ADDR) siginfo.si_addr;
2c2fa1
-      const CORE_ADDR addr_watch = state->dr_addr_wp[i];
2c2fa1
+      const CORE_ADDR addr_watch = state->dr_addr_wp[i] + offset;
2c2fa1
+      const CORE_ADDR addr_watch_aligned = align_down (state->dr_addr_wp[i], 8);
2c2fa1
+      const CORE_ADDR addr_orig = state->dr_addr_orig_wp[i];
2c2fa1
 
2c2fa1
       if (state->dr_ref_count_wp[i]
2c2fa1
 	  && DR_CONTROL_ENABLED (state->dr_ctrl_wp[i])
2c2fa1
-	  && addr_trap >= addr_watch
2c2fa1
+	  && addr_trap >= addr_watch_aligned
2c2fa1
 	  && addr_trap < addr_watch + len)
2c2fa1
 	{
2c2fa1
-	  *addr_p = addr_trap;
2c2fa1
+	  /* ADDR_TRAP reports the first address of the memory range
2c2fa1
+	     accessed by the CPU, regardless of what was the memory
2c2fa1
+	     range watched.  Thus, a large CPU access that straddles
2c2fa1
+	     the ADDR_WATCH..ADDR_WATCH+LEN range may result in an
2c2fa1
+	     ADDR_TRAP that is lower than the
2c2fa1
+	     ADDR_WATCH..ADDR_WATCH+LEN range.  E.g.:
2c2fa1
+
2c2fa1
+	     addr: |   4   |   5   |   6   |   7   |   8   |
2c2fa1
+				   |---- range watched ----|
2c2fa1
+		   |----------- range accessed ------------|
2c2fa1
+
2c2fa1
+	     In this case, ADDR_TRAP will be 4.
2c2fa1
+
2c2fa1
+	     To match a watchpoint known to GDB core, we must never
2c2fa1
+	     report *ADDR_P outside of any ADDR_WATCH..ADDR_WATCH+LEN
2c2fa1
+	     range.  ADDR_WATCH <= ADDR_TRAP < ADDR_ORIG is a false
2c2fa1
+	     positive on kernels older than 4.10.  See PR
2c2fa1
+	     external/20207.  */
2c2fa1
+	  *addr_p = addr_orig;
2c2fa1
 	  return 1;
2c2fa1
 	}
2c2fa1
     }
2c2fa1
Index: gdb-7.6.1/gdb/common/common-utils.c
2c2fa1
===================================================================
2c2fa1
--- gdb-7.6.1.orig/gdb/common/common-utils.c	2013-02-14 18:11:41.000000000 +0100
2c2fa1
+++ gdb-7.6.1/gdb/common/common-utils.c	2018-05-05 17:12:49.570781881 +0200
2c2fa1
@@ -161,3 +161,23 @@
2c2fa1
   p[len] = 0;
2c2fa1
   return p;
2c2fa1
 }
2c2fa1
+
2c2fa1
+/* See common/common-utils.h.  */
2c2fa1
+
2c2fa1
+ULONGEST
2c2fa1
+align_up (ULONGEST v, int n)
2c2fa1
+{
2c2fa1
+  /* Check that N is really a power of two.  */
2c2fa1
+  gdb_assert (n && (n & (n-1)) == 0);
2c2fa1
+  return (v + n - 1) & -n;
2c2fa1
+}
2c2fa1
+
2c2fa1
+/* See common/common-utils.h.  */
2c2fa1
+
2c2fa1
+ULONGEST
2c2fa1
+align_down (ULONGEST v, int n)
2c2fa1
+{
2c2fa1
+  /* Check that N is really a power of two.  */
2c2fa1
+  gdb_assert (n && (n & (n-1)) == 0);
2c2fa1
+  return (v & -n);
2c2fa1
+}
2c2fa1
Index: gdb-7.6.1/gdb/common/common-utils.h
2c2fa1
===================================================================
2c2fa1
--- gdb-7.6.1.orig/gdb/common/common-utils.h	2013-02-14 18:11:41.000000000 +0100
2c2fa1
+++ gdb-7.6.1/gdb/common/common-utils.h	2018-05-05 17:12:49.570781881 +0200
2c2fa1
@@ -53,4 +53,36 @@
2c2fa1
 
2c2fa1
 char *savestring (const char *ptr, size_t len);
2c2fa1
 
2c2fa1
+/* Ensure that V is aligned to an N byte boundary (B's assumed to be a
2c2fa1
+   power of 2).  Round up/down when necessary.  Examples of correct
2c2fa1
+   use include:
2c2fa1
+
2c2fa1
+    addr = align_up (addr, 8); -- VALUE needs 8 byte alignment
2c2fa1
+    write_memory (addr, value, len);
2c2fa1
+    addr += len;
2c2fa1
+
2c2fa1
+   and:
2c2fa1
+
2c2fa1
+    sp = align_down (sp - len, 16); -- Keep SP 16 byte aligned
2c2fa1
+    write_memory (sp, value, len);
2c2fa1
+
2c2fa1
+   Note that uses such as:
2c2fa1
+
2c2fa1
+    write_memory (addr, value, len);
2c2fa1
+    addr += align_up (len, 8);
2c2fa1
+
2c2fa1
+   and:
2c2fa1
+
2c2fa1
+    sp -= align_up (len, 8);
2c2fa1
+    write_memory (sp, value, len);
2c2fa1
+
2c2fa1
+   are typically not correct as they don't ensure that the address (SP
2c2fa1
+   or ADDR) is correctly aligned (relying on previous alignment to
2c2fa1
+   keep things right).  This is also why the methods are called
2c2fa1
+   "align_..." instead of "round_..." as the latter reads better with
2c2fa1
+   this incorrect coding style.  */
2c2fa1
+
2c2fa1
+extern ULONGEST align_up (ULONGEST v, int n);
2c2fa1
+extern ULONGEST align_down (ULONGEST v, int n);
2c2fa1
+
2c2fa1
 #endif
2c2fa1
Index: gdb-7.6.1/gdb/gdbserver/linux-aarch64-low.c
2c2fa1
===================================================================
2c2fa1
--- gdb-7.6.1.orig/gdb/gdbserver/linux-aarch64-low.c	2018-05-05 17:12:47.501763392 +0200
2c2fa1
+++ gdb-7.6.1/gdb/gdbserver/linux-aarch64-low.c	2018-05-05 17:12:49.570781881 +0200
2c2fa1
@@ -40,6 +40,18 @@
2c2fa1
 #include <sys/reg.h>
2c2fa1
 #endif
2c2fa1
 
2c2fa1
+/* ptrace expects control registers to be formatted as follows:
2c2fa1
+
2c2fa1
+   31                             13          5      3      1     0
2c2fa1
+   +--------------------------------+----------+------+------+----+
2c2fa1
+   |         RESERVED (SBZ)         |   MASK   | TYPE | PRIV | EN |
2c2fa1
+   +--------------------------------+----------+------+------+----+
2c2fa1
+
2c2fa1
+   The TYPE field is ignored for breakpoints.  */
2c2fa1
+
2c2fa1
+#define DR_CONTROL_ENABLED(ctrl)	(((ctrl) & 0x1) == 1)
2c2fa1
+#define DR_CONTROL_MASK(ctrl)		(((ctrl) >> 5) & 0xff)
2c2fa1
+
2c2fa1
 #define AARCH64_X_REGS_NUM 31
2c2fa1
 #define AARCH64_V_REGS_NUM 32
2c2fa1
 #define AARCH64_X0_REGNO    0
2c2fa1
@@ -170,7 +182,10 @@
2c2fa1
   unsigned int dr_ref_count_bp[AARCH64_HBP_MAX_NUM];
2c2fa1
 
2c2fa1
   /* hardware watchpoint */
2c2fa1
+  /* Address aligned down to AARCH64_HWP_ALIGNMENT.  */
2c2fa1
   CORE_ADDR dr_addr_wp[AARCH64_HWP_MAX_NUM];
2c2fa1
+  /* Address as entered by user without any forced alignment.  */
2c2fa1
+  CORE_ADDR dr_addr_orig_wp[AARCH64_HWP_MAX_NUM];
2c2fa1
   unsigned int dr_ctrl_wp[AARCH64_HWP_MAX_NUM];
2c2fa1
   unsigned int dr_ref_count_wp[AARCH64_HWP_MAX_NUM];
2c2fa1
 };
2c2fa1
@@ -311,6 +326,29 @@
2c2fa1
     supply_register (regcache, AARCH64_V0_REGNO + i, &regset->vregs[i]);
2c2fa1
 }
2c2fa1
 
2c2fa1
+/* True if this kernel does not have the bug described by PR
2c2fa1
+   external/20207 (Linux >= 4.10).  A fixed kernel supports any
2c2fa1
+   contiguous range of bits in 8-bit byte DR_CONTROL_MASK.  A buggy
2c2fa1
+   kernel supports only 0x01, 0x03, 0x0f and 0xff.  We start by
2c2fa1
+   assuming the bug is fixed, and then detect the bug at
2c2fa1
+   PTRACE_SETREGSET time.  */
2c2fa1
+static int kernel_supports_any_contiguous_range = 1;
2c2fa1
+
2c2fa1
+/* Return starting byte 0..7 incl. of a watchpoint encoded by CTRL.  */
2c2fa1
+
2c2fa1
+static unsigned int
2c2fa1
+aarch64_watchpoint_offset (unsigned int ctrl)
2c2fa1
+{
2c2fa1
+  uint8_t mask = DR_CONTROL_MASK (ctrl);
2c2fa1
+  unsigned retval;
2c2fa1
+
2c2fa1
+  /* Shift out bottom zeros.  */
2c2fa1
+  for (retval = 0; mask && (mask & 1) == 0; ++retval)
2c2fa1
+    mask >>= 1;
2c2fa1
+
2c2fa1
+  return retval;
2c2fa1
+}
2c2fa1
+
2c2fa1
 /* Debugging of hardware breakpoint/watchpoint support.  */
2c2fa1
 extern int debug_hw_points;
2c2fa1
 
2c2fa1
@@ -383,8 +421,8 @@
2c2fa1
 
2c2fa1
   fprintf (stderr, "\tWATCHPOINTs:\n");
2c2fa1
   for (i = 0; i < aarch64_num_wp_regs; i++)
2c2fa1
-    fprintf (stderr, "\tWP%d: addr=0x%s, ctrl=0x%08x, ref.count=%d\n",
2c2fa1
-	     i, paddress (state->dr_addr_wp[i]),
2c2fa1
+    fprintf (stderr, "\tWP%d: addr=0x%s (orig=0x%s), ctrl=0x%08x, ref.count=%d\n",
2c2fa1
+	     i, paddress (state->dr_addr_wp[i]), paddress (state->dr_addr_orig_wp[i]),
2c2fa1
 	     state->dr_ctrl_wp[i], state->dr_ref_count_wp[i]);
2c2fa1
 }
2c2fa1
 
2c2fa1
@@ -422,27 +460,27 @@
2c2fa1
 
2c2fa1
 /* Utility function that returns the length in bytes of a watchpoint
2c2fa1
    according to the content of a hardware debug control register CTRL.
2c2fa1
-   Note that the kernel currently only supports the following Byte
2c2fa1
-   Address Select (BAS) values: 0x1, 0x3, 0xf and 0xff, which means
2c2fa1
-   that for a hardware watchpoint, its valid length can only be 1
2c2fa1
-   byte, 2 bytes, 4 bytes or 8 bytes.  */
2c2fa1
+   Any contiguous range of bytes in CTRL is supported.  The returned
2c2fa1
+   value can be between 0..8 (inclusive).  */
2c2fa1
 
2c2fa1
 static inline unsigned int
2c2fa1
 aarch64_watchpoint_length (unsigned int ctrl)
2c2fa1
 {
2c2fa1
-  switch (DR_CONTROL_LENGTH (ctrl))
2c2fa1
-    {
2c2fa1
-    case 0x01:
2c2fa1
-      return 1;
2c2fa1
-    case 0x03:
2c2fa1
-      return 2;
2c2fa1
-    case 0x0f:
2c2fa1
-      return 4;
2c2fa1
-    case 0xff:
2c2fa1
-      return 8;
2c2fa1
-    default:
2c2fa1
-      return 0;
2c2fa1
-    }
2c2fa1
+  uint8_t mask = DR_CONTROL_MASK (ctrl);
2c2fa1
+  unsigned retval;
2c2fa1
+
2c2fa1
+  /* Shift out bottom zeros.  */
2c2fa1
+  mask >>= aarch64_watchpoint_offset (ctrl);
2c2fa1
+
2c2fa1
+  /* Count bottom ones.  */
2c2fa1
+  for (retval = 0; (mask & 1) != 0; ++retval)
2c2fa1
+    mask >>= 1;
2c2fa1
+
2c2fa1
+  if (mask != 0)
2c2fa1
+    error (_("Unexpected hardware watchpoint length register value 0x%x"),
2c2fa1
+	   DR_CONTROL_MASK (ctrl));
2c2fa1
+
2c2fa1
+  return retval;
2c2fa1
 }
2c2fa1
 
2c2fa1
 /* Given the hardware breakpoint or watchpoint type TYPE and its
2c2fa1
@@ -450,14 +488,17 @@
2c2fa1
    breakpoint/watchpoint control register.  */
2c2fa1
 
2c2fa1
 static unsigned int
2c2fa1
-aarch64_point_encode_ctrl_reg (enum target_point_type type, int len)
2c2fa1
+aarch64_point_encode_ctrl_reg (enum target_point_type type, int offset, int len)
2c2fa1
 {
2c2fa1
   unsigned int ctrl;
2c2fa1
 
2c2fa1
+  gdb_assert (offset == 0 || kernel_supports_any_contiguous_range);
2c2fa1
+  gdb_assert (offset + len <= AARCH64_HWP_MAX_LEN_PER_REG);
2c2fa1
+
2c2fa1
   /* type */
2c2fa1
   ctrl = type << 3;
2c2fa1
-  /* length bitmask */
2c2fa1
-  ctrl |= ((1 << len) - 1) << 5;
2c2fa1
+  /* offset and length bitmask */
2c2fa1
+  ctrl |= ((1 << len) - 1) << (5 + offset);
2c2fa1
   /* enabled at el0 */
2c2fa1
   ctrl |= (2 << 1) | 1;
2c2fa1
 
2c2fa1
@@ -486,17 +527,23 @@
2c2fa1
   if (addr & (alignment - 1))
2c2fa1
     return 0;
2c2fa1
 
2c2fa1
-  if (len != 8 && len != 4 && len != 2 && len != 1)
2c2fa1
+  if ((!kernel_supports_any_contiguous_range
2c2fa1
+       && len != 8 && len != 4 && len != 2 && len != 1)
2c2fa1
+      || (kernel_supports_any_contiguous_range
2c2fa1
+	  && (len < 1 || len > 8)))
2c2fa1
     return 0;
2c2fa1
 
2c2fa1
   return 1;
2c2fa1
 }
2c2fa1
 
2c2fa1
 /* Given the (potentially unaligned) watchpoint address in ADDR and
2c2fa1
-   length in LEN, return the aligned address and aligned length in
2c2fa1
-   *ALIGNED_ADDR_P and *ALIGNED_LEN_P, respectively.  The returned
2c2fa1
-   aligned address and length will be valid to be written to the
2c2fa1
-   hardware watchpoint value and control registers.  See the comment
2c2fa1
+   length in LEN, return the aligned address, offset from that base
2c2fa1
+   address, and aligned length in *ALIGNED_ADDR_P, *ALIGNED_OFFSET_P
2c2fa1
+   and *ALIGNED_LEN_P, respectively.  The returned values will be
2c2fa1
+   valid values to write to the hardware watchpoint value and control
2c2fa1
+   registers.
2c2fa1
+
2c2fa1
+   See the comment
2c2fa1
    above aarch64_point_is_aligned for the information about the
2c2fa1
    alignment requirement.  The given watchpoint may get truncated if
2c2fa1
    more than one hardware register is needed to cover the watched
2c2fa1
@@ -533,11 +580,12 @@
2c2fa1
 
2c2fa1
 static void
2c2fa1
 aarch64_align_watchpoint (CORE_ADDR addr, int len, CORE_ADDR *aligned_addr_p,
2c2fa1
-			  int *aligned_len_p, CORE_ADDR *next_addr_p,
2c2fa1
-			  int *next_len_p)
2c2fa1
+			  int *aligned_offset_p, int *aligned_len_p,
2c2fa1
+			  CORE_ADDR *next_addr_p, int *next_len_p,
2c2fa1
+			  CORE_ADDR *next_addr_orig_p)
2c2fa1
 {
2c2fa1
   int aligned_len;
2c2fa1
-  unsigned int offset;
2c2fa1
+  unsigned int offset, aligned_offset;
2c2fa1
   CORE_ADDR aligned_addr;
2c2fa1
   const unsigned int alignment = AARCH64_HWP_ALIGNMENT;
2c2fa1
   const unsigned int max_wp_len = AARCH64_HWP_MAX_LEN_PER_REG;
2c2fa1
@@ -548,10 +596,12 @@
2c2fa1
   if (len <= 0)
2c2fa1
     return;
2c2fa1
 
2c2fa1
-  /* Address to be put into the hardware watchpoint value register
2c2fa1
-     must be aligned.  */
2c2fa1
+  /* The address put into the hardware watchpoint value register must
2c2fa1
+     be aligned.  */
2c2fa1
   offset = addr & (alignment - 1);
2c2fa1
   aligned_addr = addr - offset;
2c2fa1
+  aligned_offset
2c2fa1
+    = kernel_supports_any_contiguous_range ? addr & (alignment - 1) : 0;
2c2fa1
 
2c2fa1
   gdb_assert (offset >= 0 && offset < alignment);
2c2fa1
   gdb_assert (aligned_addr >= 0 && aligned_addr <= addr);
2c2fa1
@@ -559,9 +609,10 @@
2c2fa1
 
2c2fa1
   if (offset + len >= max_wp_len)
2c2fa1
     {
2c2fa1
-      /* Need more than one watchpoint registers; truncate it at the
2c2fa1
+      /* Need more than one watchpoint register; truncate at the
2c2fa1
 	 alignment boundary.  */
2c2fa1
-      aligned_len = max_wp_len;
2c2fa1
+      aligned_len
2c2fa1
+	= max_wp_len - (kernel_supports_any_contiguous_range ? offset : 0);
2c2fa1
       len -= (max_wp_len - offset);
2c2fa1
       addr += (max_wp_len - offset);
2c2fa1
       gdb_assert ((addr & (alignment - 1)) == 0);
2c2fa1
@@ -574,26 +625,96 @@
2c2fa1
 	aligned_len_array[AARCH64_HWP_MAX_LEN_PER_REG] =
2c2fa1
 	{ 1, 2, 4, 4, 8, 8, 8, 8 };
2c2fa1
 
2c2fa1
-      aligned_len = aligned_len_array[offset + len - 1];
2c2fa1
+      aligned_len = (kernel_supports_any_contiguous_range
2c2fa1
+		     ? len : aligned_len_array[offset + len - 1]);
2c2fa1
       addr += len;
2c2fa1
       len = 0;
2c2fa1
     }
2c2fa1
 
2c2fa1
   if (aligned_addr_p != NULL)
2c2fa1
     *aligned_addr_p = aligned_addr;
2c2fa1
+  if (aligned_offset_p)
2c2fa1
+    *aligned_offset_p = aligned_offset;
2c2fa1
   if (aligned_len_p != NULL)
2c2fa1
     *aligned_len_p = aligned_len;
2c2fa1
   if (next_addr_p != NULL)
2c2fa1
     *next_addr_p = addr;
2c2fa1
   if (next_len_p != NULL)
2c2fa1
     *next_len_p = len;
2c2fa1
+  if (next_addr_orig_p)
2c2fa1
+    *next_addr_orig_p = align_down (*next_addr_orig_p + alignment, alignment);
2c2fa1
+}
2c2fa1
+
2c2fa1
+/* Reconfigure STATE to be compatible with Linux kernels with the PR
2c2fa1
+   external/20207 bug.  This is called when
2c2fa1
+   KERNEL_SUPPORTS_ANY_CONTIGUOUS_RANGE transitions to false.  Note we
2c2fa1
+   don't try to support combining watchpoints with matching (and thus
2c2fa1
+   shared) masks, as it's too late when we get here.  On buggy
2c2fa1
+   kernels, GDB will try to first setup the perfect matching ranges,
2c2fa1
+   which will run out of registers before this function can merge
2c2fa1
+   them.  It doesn't look like worth the effort to improve that, given
2c2fa1
+   eventually buggy kernels will be phased out.  */
2c2fa1
+
2c2fa1
+static void aarch64_notify_debug_reg_change (const struct aarch64_debug_reg_state *state, int is_watchpoint, unsigned int idx);
2c2fa1
+
2c2fa1
+static void
2c2fa1
+aarch64_downgrade_regs (struct aarch64_debug_reg_state *state)
2c2fa1
+{
2c2fa1
+  int i;
2c2fa1
+
2c2fa1
+  for (i = 0; i < aarch64_num_wp_regs; ++i)
2c2fa1
+    if ((state->dr_ctrl_wp[i] & 1) != 0)
2c2fa1
+      {
2c2fa1
+	uint8_t mask_orig;
2c2fa1
+	static const uint8_t old_valid[] = { 0x01, 0x03, 0x0f, 0xff };
2c2fa1
+	int old_validi;
2c2fa1
+	uint8_t mask = 0;
2c2fa1
+	int j;
2c2fa1
+
2c2fa1
+	gdb_assert (state->dr_ref_count_wp[i] != 0);
2c2fa1
+	mask_orig = (state->dr_ctrl_wp[i] >> 5) & 0xff;
2c2fa1
+	gdb_assert (mask_orig != 0);
2c2fa1
+	for (old_validi = 0; old_validi < sizeof(old_valid) / sizeof (*old_valid); old_validi++) {
2c2fa1
+	  const uint8_t old_mask = old_valid[old_validi];
2c2fa1
+	  if (mask_orig <= old_mask)
2c2fa1
+	    {
2c2fa1
+	      mask = old_mask;
2c2fa1
+	      break;
2c2fa1
+	    }
2c2fa1
+	}
2c2fa1
+	gdb_assert (mask != 0);
2c2fa1
+
2c2fa1
+	/* No update needed for this watchpoint?  */
2c2fa1
+	if (mask == mask_orig)
2c2fa1
+	  continue;
2c2fa1
+	state->dr_ctrl_wp[i] |= mask << 5;
2c2fa1
+	state->dr_addr_wp[i]
2c2fa1
+	  = align_down (state->dr_addr_wp[i], AARCH64_HWP_ALIGNMENT);
2c2fa1
+
2c2fa1
+	/* Try to match duplicate entries.  */
2c2fa1
+	for (j = 0; j < i; ++j)
2c2fa1
+	  if ((state->dr_ctrl_wp[j] & 1) != 0
2c2fa1
+	      && state->dr_addr_wp[j] == state->dr_addr_wp[i]
2c2fa1
+	      && state->dr_addr_orig_wp[j] == state->dr_addr_orig_wp[i]
2c2fa1
+	      && state->dr_ctrl_wp[j] == state->dr_ctrl_wp[i])
2c2fa1
+	    {
2c2fa1
+	      state->dr_ref_count_wp[j] += state->dr_ref_count_wp[i];
2c2fa1
+	      state->dr_ref_count_wp[i] = 0;
2c2fa1
+	      state->dr_addr_wp[i] = 0;
2c2fa1
+	      state->dr_addr_orig_wp[i] = 0;
2c2fa1
+	      state->dr_ctrl_wp[i] &= ~1;
2c2fa1
+	      break;
2c2fa1
+	    }
2c2fa1
+
2c2fa1
+	aarch64_notify_debug_reg_change (state, 1 /* is_watchpoint */, i);
2c2fa1
+      }
2c2fa1
 }
2c2fa1
 
2c2fa1
 /* Call ptrace to set the thread TID's hardware breakpoint/watchpoint
2c2fa1
    registers with data from *STATE.  */
2c2fa1
 
2c2fa1
 static void
2c2fa1
-aarch64_linux_set_debug_regs (const struct aarch64_debug_reg_state *state,
2c2fa1
+aarch64_linux_set_debug_regs (struct aarch64_debug_reg_state *state,
2c2fa1
 			      int tid, int watchpoint)
2c2fa1
 {
2c2fa1
   int i, count;
2c2fa1
@@ -621,7 +742,18 @@
2c2fa1
   if (ptrace (PTRACE_SETREGSET, tid,
2c2fa1
 	      watchpoint ? NT_ARM_HW_WATCH : NT_ARM_HW_BREAK,
2c2fa1
 	      (void *) &iov))
2c2fa1
-    error (_("Unexpected error setting hardware debug registers"));
2c2fa1
+    {
2c2fa1
+      /* Handle Linux kernels with the PR external/20207 bug.  */
2c2fa1
+      if (watchpoint && errno == EINVAL
2c2fa1
+	  && kernel_supports_any_contiguous_range)
2c2fa1
+	{
2c2fa1
+	  kernel_supports_any_contiguous_range = 0;
2c2fa1
+	  aarch64_downgrade_regs (state);
2c2fa1
+	  aarch64_linux_set_debug_regs (state, tid, watchpoint);
2c2fa1
+	  return;
2c2fa1
+	}
2c2fa1
+      error (_("Unexpected error setting hardware debug registers"));
2c2fa1
+    }
2c2fa1
 }
2c2fa1
 
2c2fa1
 struct aarch64_dr_update_callback_param
2c2fa1
@@ -750,11 +882,12 @@
2c2fa1
 static int
2c2fa1
 aarch64_dr_state_insert_one_point (struct aarch64_debug_reg_state *state,
2c2fa1
 				   enum target_point_type type,
2c2fa1
-				   CORE_ADDR addr, int len)
2c2fa1
+				   CORE_ADDR addr, int offset, int len,
2c2fa1
+				   CORE_ADDR addr_orig)
2c2fa1
 {
2c2fa1
   int i, idx, num_regs, is_watchpoint;
2c2fa1
   unsigned int ctrl, *dr_ctrl_p, *dr_ref_count;
2c2fa1
-  CORE_ADDR *dr_addr_p;
2c2fa1
+  CORE_ADDR *dr_addr_p, *dr_addr_orig_p;
2c2fa1
 
2c2fa1
   /* Set up state pointers.  */
2c2fa1
   is_watchpoint = (type != hw_execute);
2c2fa1
@@ -763,6 +896,7 @@
2c2fa1
     {
2c2fa1
       num_regs = aarch64_num_wp_regs;
2c2fa1
       dr_addr_p = state->dr_addr_wp;
2c2fa1
+      dr_addr_orig_p = state->dr_addr_orig_wp;
2c2fa1
       dr_ctrl_p = state->dr_ctrl_wp;
2c2fa1
       dr_ref_count = state->dr_ref_count_wp;
2c2fa1
     }
2c2fa1
@@ -770,11 +904,12 @@
2c2fa1
     {
2c2fa1
       num_regs = aarch64_num_bp_regs;
2c2fa1
       dr_addr_p = state->dr_addr_bp;
2c2fa1
+      dr_addr_orig_p = NULL;
2c2fa1
       dr_ctrl_p = state->dr_ctrl_bp;
2c2fa1
       dr_ref_count = state->dr_ref_count_bp;
2c2fa1
     }
2c2fa1
 
2c2fa1
-  ctrl = aarch64_point_encode_ctrl_reg (type, len);
2c2fa1
+  ctrl = aarch64_point_encode_ctrl_reg (type, offset, len);
2c2fa1
 
2c2fa1
   /* Find an existing or free register in our cache.  */
2c2fa1
   idx = -1;
2c2fa1
@@ -786,7 +921,9 @@
2c2fa1
 	  idx = i;
2c2fa1
 	  /* no break; continue hunting for an exising one.  */
2c2fa1
 	}
2c2fa1
-      else if (dr_addr_p[i] == addr && dr_ctrl_p[i] == ctrl)
2c2fa1
+      else if (dr_addr_p[i] == addr
2c2fa1
+	       && (dr_addr_orig_p == NULL || dr_addr_orig_p[i] == addr_orig)
2c2fa1
+	       && dr_ctrl_p[i] == ctrl)
2c2fa1
 	{
2c2fa1
 	  gdb_assert (dr_ref_count[i] != 0);
2c2fa1
 	  idx = i;
2c2fa1
@@ -803,6 +940,8 @@
2c2fa1
     {
2c2fa1
       /* new entry */
2c2fa1
       dr_addr_p[idx] = addr;
2c2fa1
+      if (dr_addr_orig_p != NULL)
2c2fa1
+	dr_addr_orig_p[idx] = addr_orig;
2c2fa1
       dr_ctrl_p[idx] = ctrl;
2c2fa1
       dr_ref_count[idx] = 1;
2c2fa1
       /* Notify the change.  */
2c2fa1
@@ -823,11 +962,12 @@
2c2fa1
 static int
2c2fa1
 aarch64_dr_state_remove_one_point (struct aarch64_debug_reg_state *state,
2c2fa1
 				   enum target_point_type type,
2c2fa1
-				   CORE_ADDR addr, int len)
2c2fa1
+				   CORE_ADDR addr, int offset, int len,
2c2fa1
+				   CORE_ADDR addr_orig)
2c2fa1
 {
2c2fa1
   int i, num_regs, is_watchpoint;
2c2fa1
   unsigned int ctrl, *dr_ctrl_p, *dr_ref_count;
2c2fa1
-  CORE_ADDR *dr_addr_p;
2c2fa1
+  CORE_ADDR *dr_addr_p, *dr_addr_orig_p;
2c2fa1
 
2c2fa1
   /* Set up state pointers.  */
2c2fa1
   is_watchpoint = (type != hw_execute);
2c2fa1
@@ -836,6 +976,7 @@
2c2fa1
     {
2c2fa1
       num_regs = aarch64_num_wp_regs;
2c2fa1
       dr_addr_p = state->dr_addr_wp;
2c2fa1
+      dr_addr_orig_p = state->dr_addr_orig_wp;
2c2fa1
       dr_ctrl_p = state->dr_ctrl_wp;
2c2fa1
       dr_ref_count = state->dr_ref_count_wp;
2c2fa1
     }
2c2fa1
@@ -843,15 +984,18 @@
2c2fa1
     {
2c2fa1
       num_regs = aarch64_num_bp_regs;
2c2fa1
       dr_addr_p = state->dr_addr_bp;
2c2fa1
+      dr_addr_orig_p = NULL;
2c2fa1
       dr_ctrl_p = state->dr_ctrl_bp;
2c2fa1
       dr_ref_count = state->dr_ref_count_bp;
2c2fa1
     }
2c2fa1
 
2c2fa1
-  ctrl = aarch64_point_encode_ctrl_reg (type, len);
2c2fa1
+  ctrl = aarch64_point_encode_ctrl_reg (type, offset, len);
2c2fa1
 
2c2fa1
   /* Find the entry that matches the ADDR and CTRL.  */
2c2fa1
   for (i = 0; i < num_regs; ++i)
2c2fa1
-    if (dr_addr_p[i] == addr && dr_ctrl_p[i] == ctrl)
2c2fa1
+    if (dr_addr_p[i] == addr
2c2fa1
+	&& (dr_addr_orig_p == NULL || dr_addr_orig_p[i] == addr_orig)
2c2fa1
+	&& dr_ctrl_p[i] == ctrl)
2c2fa1
       {
2c2fa1
 	gdb_assert (dr_ref_count[i] != 0);
2c2fa1
 	break;
2c2fa1
@@ -867,6 +1011,8 @@
2c2fa1
       /* Clear the enable bit.  */
2c2fa1
       ctrl &= ~1;
2c2fa1
       dr_addr_p[i] = 0;
2c2fa1
+      if (dr_addr_orig_p != NULL)
2c2fa1
+	dr_addr_orig_p[i] = 0;
2c2fa1
       dr_ctrl_p[i] = ctrl;
2c2fa1
       /* Notify the change.  */
2c2fa1
       aarch64_notify_debug_reg_change (state, is_watchpoint, i);
2c2fa1
@@ -889,9 +1035,9 @@
2c2fa1
   state = aarch64_get_debug_reg_state ();
2c2fa1
 
2c2fa1
   if (is_insert)
2c2fa1
-    return aarch64_dr_state_insert_one_point (state, type, addr, len);
2c2fa1
+    return aarch64_dr_state_insert_one_point (state, type, addr, 0, len, -1);
2c2fa1
   else
2c2fa1
-    return aarch64_dr_state_remove_one_point (state, type, addr, len);
2c2fa1
+    return aarch64_dr_state_remove_one_point (state, type, addr, 0, len, -1);
2c2fa1
 }
2c2fa1
 
2c2fa1
 /* This is essentially the same as aarch64_handle_breakpoint, apart
2c2fa1
@@ -906,9 +1052,9 @@
2c2fa1
   state = aarch64_get_debug_reg_state ();
2c2fa1
 
2c2fa1
   if (is_insert)
2c2fa1
-    return aarch64_dr_state_insert_one_point (state, type, addr, len);
2c2fa1
+    return aarch64_dr_state_insert_one_point (state, type, addr, 0, len, addr);
2c2fa1
   else
2c2fa1
-    return aarch64_dr_state_remove_one_point (state, type, addr, len);
2c2fa1
+    return aarch64_dr_state_remove_one_point (state, type, addr, 0, len, addr);
2c2fa1
 }
2c2fa1
 
2c2fa1
 /* Insert/remove unaligned watchpoint by calling
2c2fa1
@@ -924,29 +1070,41 @@
2c2fa1
 {
2c2fa1
   struct aarch64_debug_reg_state *state
2c2fa1
     = aarch64_get_debug_reg_state ();
2c2fa1
+  CORE_ADDR addr_orig = addr;
2c2fa1
 
2c2fa1
   while (len > 0)
2c2fa1
     {
2c2fa1
       CORE_ADDR aligned_addr;
2c2fa1
-      int aligned_len, ret;
2c2fa1
+      int aligned_offset, aligned_len, ret;
2c2fa1
+      CORE_ADDR addr_orig_next = addr_orig;
2c2fa1
 
2c2fa1
-      aarch64_align_watchpoint (addr, len, &aligned_addr, &aligned_len,
2c2fa1
-				&addr, &len;;
2c2fa1
+      aarch64_align_watchpoint (addr, len, &aligned_addr, &aligned_offset,
2c2fa1
+				&aligned_len, &addr, &len, &addr_orig_next);
2c2fa1
 
2c2fa1
       if (is_insert)
2c2fa1
 	ret = aarch64_dr_state_insert_one_point (state, type, aligned_addr,
2c2fa1
-						 aligned_len);
2c2fa1
+						 aligned_offset,
2c2fa1
+						 aligned_len, addr_orig);
2c2fa1
       else
2c2fa1
 	ret = aarch64_dr_state_remove_one_point (state, type, aligned_addr,
2c2fa1
-						 aligned_len);
2c2fa1
+						 aligned_offset,
2c2fa1
+						 aligned_len, addr_orig);
2c2fa1
 
2c2fa1
       if (debug_hw_points)
2c2fa1
 	fprintf (stderr,
2c2fa1
  "handle_unaligned_watchpoint: is_insert: %d\n"
2c2fa1
  "                             aligned_addr: 0x%s, aligned_len: %d\n"
2c2fa1
- "                                next_addr: 0x%s,    next_len: %d\n",
2c2fa1
-		 is_insert, paddress (aligned_addr), aligned_len,
2c2fa1
-		 paddress (addr), len);
2c2fa1
+ "                                addr_orig: %s\n"
2c2fa1
+ "                                                                "
2c2fa1
+ "                                next_addr: %s,    next_len: %d\n"
2c2fa1
+ "                                                           "
2c2fa1
+ "                                addr_orig_next: %s\n",
2c2fa1
+		 is_insert, paddress (aligned_addr),
2c2fa1
+		      aligned_len, paddress (addr_orig),
2c2fa1
+		      paddress (addr), len,
2c2fa1
+		      paddress (addr_orig_next));
2c2fa1
+ 
2c2fa1
+       addr_orig = addr_orig_next;
2c2fa1
 
2c2fa1
       if (ret != 0)
2c2fa1
 	return ret;
2c2fa1
@@ -1065,14 +1223,39 @@
2c2fa1
   state = aarch64_get_debug_reg_state ();
2c2fa1
   for (i = aarch64_num_wp_regs - 1; i >= 0; --i)
2c2fa1
     {
2c2fa1
+      const unsigned int offset
2c2fa1
+	= aarch64_watchpoint_offset (state->dr_ctrl_wp[i]);
2c2fa1
       const unsigned int len = aarch64_watchpoint_length (state->dr_ctrl_wp[i]);
2c2fa1
       const CORE_ADDR addr_trap = (CORE_ADDR) siginfo.si_addr;
2c2fa1
-      const CORE_ADDR addr_watch = state->dr_addr_wp[i];
2c2fa1
+      const CORE_ADDR addr_watch = state->dr_addr_wp[i] + offset;
2c2fa1
+      const CORE_ADDR addr_watch_aligned = align_down (state->dr_addr_wp[i], 8);
2c2fa1
+      const CORE_ADDR addr_orig = state->dr_addr_orig_wp[i];
2c2fa1
+
2c2fa1
       if (state->dr_ref_count_wp[i]
2c2fa1
 	  && DR_CONTROL_ENABLED (state->dr_ctrl_wp[i])
2c2fa1
-	  && addr_trap >= addr_watch
2c2fa1
+	  && addr_trap >= addr_watch_aligned
2c2fa1
 	  && addr_trap < addr_watch + len)
2c2fa1
-	return addr_trap;
2c2fa1
+	{
2c2fa1
+	  /* ADDR_TRAP reports the first address of the memory range
2c2fa1
+	     accessed by the CPU, regardless of what was the memory
2c2fa1
+	     range watched.  Thus, a large CPU access that straddles
2c2fa1
+	     the ADDR_WATCH..ADDR_WATCH+LEN range may result in an
2c2fa1
+	     ADDR_TRAP that is lower than the
2c2fa1
+	     ADDR_WATCH..ADDR_WATCH+LEN range.  E.g.:
2c2fa1
+
2c2fa1
+	     addr: |   4   |   5   |   6   |   7   |   8   |
2c2fa1
+				   |---- range watched ----|
2c2fa1
+		   |----------- range accessed ------------|
2c2fa1
+
2c2fa1
+	     In this case, ADDR_TRAP will be 4.
2c2fa1
+
2c2fa1
+	     To match a watchpoint known to GDB core, we must never
2c2fa1
+	     report *ADDR_P outside of any ADDR_WATCH..ADDR_WATCH+LEN
2c2fa1
+	     range.  ADDR_WATCH <= ADDR_TRAP < ADDR_ORIG is a false
2c2fa1
+	     positive on kernels older than 4.10.  See PR
2c2fa1
+	     external/20207.  */
2c2fa1
+	  return addr_orig;
2c2fa1
+	}
2c2fa1
     }
2c2fa1
 
2c2fa1
   return (CORE_ADDR) 0;
2c2fa1
Index: gdb-7.6.1/gdb/testsuite/gdb.base/watchpoint-unaligned.c
2c2fa1
===================================================================
2c2fa1
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
2c2fa1
+++ gdb-7.6.1/gdb/testsuite/gdb.base/watchpoint-unaligned.c	2018-05-05 17:12:49.571781890 +0200
2c2fa1
@@ -0,0 +1,96 @@
2c2fa1
+/* This testcase is part of GDB, the GNU debugger.
2c2fa1
+
2c2fa1
+   Copyright 2017-2018 Free Software Foundation, Inc.
2c2fa1
+
2c2fa1
+   This program is free software; you can redistribute it and/or modify
2c2fa1
+   it under the terms of the GNU General Public License as published by
2c2fa1
+   the Free Software Foundation; either version 3 of the License, or
2c2fa1
+   (at your option) any later version.
2c2fa1
+
2c2fa1
+   This program is distributed in the hope that it will be useful,
2c2fa1
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
2c2fa1
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
2c2fa1
+   GNU General Public License for more details.
2c2fa1
+
2c2fa1
+   You should have received a copy of the GNU General Public License
2c2fa1
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
2c2fa1
+
2c2fa1
+#include <stdint.h>
2c2fa1
+#include <assert.h>
2c2fa1
+
2c2fa1
+static int again;
2c2fa1
+
2c2fa1
+static volatile struct
2c2fa1
+{
2c2fa1
+  uint64_t alignment;
2c2fa1
+  union
2c2fa1
+    {
2c2fa1
+      uint64_t size8[1];
2c2fa1
+      uint32_t size4[2];
2c2fa1
+      uint16_t size2[4];
2c2fa1
+      uint8_t size1[8];
2c2fa1
+      uint64_t size8twice[2];
2c2fa1
+    }
2c2fa1
+  u;
2c2fa1
+} data;
2c2fa1
+
2c2fa1
+static int size = 0;
2c2fa1
+static int offset;
2c2fa1
+
2c2fa1
+static void
2c2fa1
+write_size8twice (void)
2c2fa1
+{
2c2fa1
+  static const uint64_t first = 1;
2c2fa1
+  static const uint64_t second = 2;
2c2fa1
+
2c2fa1
+#ifdef __aarch64__
2c2fa1
+  asm volatile ("stp %1, %2, [%0]"
2c2fa1
+		: /* output */
2c2fa1
+		: "r" (data.u.size8twice), "r" (first), "r" (second) /* input */
2c2fa1
+		: "memory" /* clobber */);
2c2fa1
+#else
2c2fa1
+  data.u.size8twice[0] = first;
2c2fa1
+  data.u.size8twice[1] = second;
2c2fa1
+#endif
2c2fa1
+}
2c2fa1
+
2c2fa1
+int
2c2fa1
+main (void)
2c2fa1
+{
2c2fa1
+  volatile uint64_t local;
2c2fa1
+
2c2fa1
+  assert (sizeof (data) == 8 + 2 * 8);
2c2fa1
+
2c2fa1
+  write_size8twice ();
2c2fa1
+
2c2fa1
+  while (size)
2c2fa1
+    {
2c2fa1
+      switch (size)
2c2fa1
+	{
2c2fa1
+/* __s390x__ also defines __s390__ */
2c2fa1
+#ifdef __s390__
2c2fa1
+# define ACCESS(var) var = ~var
2c2fa1
+#else
2c2fa1
+# define ACCESS(var) local = var
2c2fa1
+#endif
2c2fa1
+	case 8:
2c2fa1
+	  ACCESS (data.u.size8[offset]);
2c2fa1
+	  break;
2c2fa1
+	case 4:
2c2fa1
+	  ACCESS (data.u.size4[offset]);
2c2fa1
+	  break;
2c2fa1
+	case 2:
2c2fa1
+	  ACCESS (data.u.size2[offset]);
2c2fa1
+	  break;
2c2fa1
+	case 1:
2c2fa1
+	  ACCESS (data.u.size1[offset]);
2c2fa1
+	  break;
2c2fa1
+#undef ACCESS
2c2fa1
+	default:
2c2fa1
+	  assert (0);
2c2fa1
+	}
2c2fa1
+      size = 0;
2c2fa1
+      size = size; /* start_again */
2c2fa1
+    }
2c2fa1
+  return 0; /* final_return */
2c2fa1
+}
2c2fa1
Index: gdb-7.6.1/gdb/testsuite/gdb.base/watchpoint-unaligned.exp
2c2fa1
===================================================================
2c2fa1
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
2c2fa1
+++ gdb-7.6.1/gdb/testsuite/gdb.base/watchpoint-unaligned.exp	2018-05-05 17:12:49.571781890 +0200
2c2fa1
@@ -0,0 +1,184 @@
2c2fa1
+# Copyright 2017-2018 Free Software Foundation, Inc.
2c2fa1
+#
2c2fa1
+# This program is free software; you can redistribute it and/or modify
2c2fa1
+# it under the terms of the GNU General Public License as published by
2c2fa1
+# the Free Software Foundation; either version 3 of the License, or
2c2fa1
+# (at your option) any later version.
2c2fa1
+#
2c2fa1
+# This program is distributed in the hope that it will be useful,
2c2fa1
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
2c2fa1
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
2c2fa1
+# GNU General Public License for more details.
2c2fa1
+#
2c2fa1
+# You should have received a copy of the GNU General Public License
2c2fa1
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
2c2fa1
+#
2c2fa1
+# This file is part of the gdb testsuite.
2c2fa1
+
2c2fa1
+# Test inserting read watchpoints on unaligned addresses.
2c2fa1
+
2c2fa1
+standard_testfile
2c2fa1
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile}] } {
2c2fa1
+    return -1
2c2fa1
+}
2c2fa1
+
2c2fa1
+if ![runto_main] {
2c2fa1
+    untested "could not run to main"
2c2fa1
+    return -1
2c2fa1
+}
2c2fa1
+
2c2fa1
+gdb_breakpoint [gdb_get_line_number "start_again"] "Breakpoint $decimal at $hex" "start_again"
2c2fa1
+
2c2fa1
+set sizes {1 2 4 8}
2c2fa1
+array set alignedend {1 1  2 2  3 4  4 4  5 8  6 8  7 8  8 8}
2c2fa1
+
2c2fa1
+set rwatch "rwatch"
2c2fa1
+set rwatch_exp "Hardware read watchpoint"
2c2fa1
+if {[istarget "s390*-*-*"]} {
2c2fa1
+    # Target does not support this type of hardware watchpoint."
2c2fa1
+    set rwatch "watch"
2c2fa1
+    set rwatch_exp "Hardware watchpoint"
2c2fa1
+}
2c2fa1
+
2c2fa1
+foreach wpsize $sizes {
2c2fa1
+    for {set wpoffset 0} {$wpoffset < 8 / $wpsize} {incr wpoffset} {
2c2fa1
+	set wpstart [expr $wpoffset * $wpsize]
2c2fa1
+	set wpend [expr ($wpoffset + 1) * $wpsize]
2c2fa1
+	set wpendaligned $alignedend($wpend)
2c2fa1
+	foreach rdsize $sizes {
2c2fa1
+	    for {set rdoffset 0} {$rdoffset < 8 / $rdsize} {incr rdoffset} {
2c2fa1
+		set rdstart [expr $rdoffset * $rdsize]
2c2fa1
+		set rdend [expr ($rdoffset + 1) * $rdsize]
2c2fa1
+		set expect_hit [expr max ($wpstart, $rdstart) < min ($wpend, $rdend)]
2c2fa1
+		set test "$rwatch data.u.size$wpsize\[$wpoffset\]"
2c2fa1
+		set wpnum ""
2c2fa1
+		gdb_test_multiple $test $test {
2c2fa1
+		    -re "$rwatch_exp (\[0-9\]+): .*\r\n$gdb_prompt $" {
2c2fa1
+			set wpnum $expect_out(1,string)
2c2fa1
+		    }
2c2fa1
+		    -re "Expression cannot be implemented with read/access watchpoint.\r\n$gdb_prompt $" {
2c2fa1
+			if {$wpsize == 8 && [istarget "arm*-*-*"]} {
2c2fa1
+			    untested $test
2c2fa1
+			    continue
2c2fa1
+			}
2c2fa1
+			fail $test
2c2fa1
+		    }
2c2fa1
+		}
2c2fa1
+		gdb_test_no_output "set variable size = $rdsize" ""
2c2fa1
+		gdb_test_no_output "set variable offset = $rdoffset" ""
2c2fa1
+		set test "continue"
2c2fa1
+		set got_hit 0
2c2fa1
+		gdb_test_multiple $test $test {
2c2fa1
+		    -re "$rwatch_exp $wpnum:.*alue = .*\r\n$gdb_prompt $" {
2c2fa1
+			set got_hit 1
2c2fa1
+			send_gdb "continue\n"
2c2fa1
+			exp_continue
2c2fa1
+		    }
2c2fa1
+		    -re " start_again .*\r\n$gdb_prompt $" {
2c2fa1
+		    }
2c2fa1
+		}
2c2fa1
+		gdb_test_no_output "delete $wpnum" ""
2c2fa1
+		set test "wp(size=$wpsize offset=$wpoffset) rd(size=$rdsize offset=$rdoffset) expect=$expect_hit"
2c2fa1
+		if {$expect_hit == $got_hit} {
2c2fa1
+		    pass $test
2c2fa1
+		} else {
2c2fa1
+		    # We do not know if we run on a fixed Linux kernel
2c2fa1
+		    # or not.  Report XFAIL only in the FAIL case.
2c2fa1
+		    if {$expect_hit == 0 && $rdstart < $wpendaligned} {
2c2fa1
+			setup_xfail external/20207 "aarch64*-*-linux*"
2c2fa1
+		    }
2c2fa1
+		    if {!$expect_hit && [expr max ($wpstart / 8, $rdstart / 8) < min (($wpend + 7) / 8, ($rdend + 7) / 8)]} {
2c2fa1
+			setup_xfail breakpoints/23131 "powerpc*-*-*"
2c2fa1
+		    }
2c2fa1
+		    fail $test
2c2fa1
+		}
2c2fa1
+	    }
2c2fa1
+	}
2c2fa1
+    }
2c2fa1
+}
2c2fa1
+
2c2fa1
+foreach wpcount {4 7} {
2c2fa1
+    array set wpoffset_to_wpnum {}
2c2fa1
+    for {set wpoffset 1} {$wpoffset <= $wpcount} {incr wpoffset} {
2c2fa1
+	set test "$rwatch data.u.size1\[$wpoffset\]"
2c2fa1
+	set wpnum ""
2c2fa1
+	gdb_test_multiple $test $test {
2c2fa1
+	    -re "$rwatch_exp (\[0-9\]+): .*\r\n$gdb_prompt $" {
2c2fa1
+		set wpoffset_to_wpnum($wpoffset) $expect_out(1,string)
2c2fa1
+	    }
2c2fa1
+	    -re "There are not enough available hardware resources for this watchpoint.\r\n$gdb_prompt $" {
2c2fa1
+		if {$wpoffset > 1} {
2c2fa1
+		    setup_xfail breakpoints/23131 "powerpc*-*-*"
2c2fa1
+		    setup_xfail breakpoints/23131 "arm*-*-*"
2c2fa1
+		}
2c2fa1
+		fail $test
2c2fa1
+		set wpoffset_to_wpnum($wpoffset) 0
2c2fa1
+	    }
2c2fa1
+	}
2c2fa1
+    }
2c2fa1
+    gdb_test_no_output "set variable size = 1" ""
2c2fa1
+    gdb_test_no_output "set variable offset = 1" ""
2c2fa1
+    set test "continue"
2c2fa1
+    set got_hit 0
2c2fa1
+    gdb_test_multiple $test $test {
2c2fa1
+	-re "\r\nCould not insert hardware watchpoint .*\r\n$gdb_prompt $" {
2c2fa1
+	}
2c2fa1
+	-re "$rwatch_exp $wpoffset_to_wpnum(1):.*alue = .*\r\n$gdb_prompt $" {
2c2fa1
+	    set got_hit 1
2c2fa1
+	    send_gdb "continue\n"
2c2fa1
+	    exp_continue
2c2fa1
+	}
2c2fa1
+	-re " start_again .*\r\n$gdb_prompt $" {
2c2fa1
+	}
2c2fa1
+    }
2c2fa1
+    for {set wpoffset 1} {$wpoffset <= $wpcount} {incr wpoffset} {
2c2fa1
+	if {$wpoffset_to_wpnum($wpoffset)} {
2c2fa1
+	    gdb_test_no_output "delete $wpoffset_to_wpnum($wpoffset)" ""
2c2fa1
+	}
2c2fa1
+    }
2c2fa1
+    set test "wpcount($wpcount)"
2c2fa1
+    if {!$wpoffset_to_wpnum([expr $wpcount - 1])} {
2c2fa1
+	untested $test
2c2fa1
+	continue
2c2fa1
+    }
2c2fa1
+    if {$wpcount > 4} {
2c2fa1
+	if {![istarget "s390*-*-*"]} {
2c2fa1
+	    setup_kfail tdep/22389 *-*-*
2c2fa1
+	}
2c2fa1
+    }
2c2fa1
+    gdb_assert $got_hit $test
2c2fa1
+}
2c2fa1
+
2c2fa1
+if ![runto_main] {
2c2fa1
+    return -1
2c2fa1
+}
2c2fa1
+gdb_breakpoint [gdb_get_line_number "final_return"] "Breakpoint $decimal at $hex" "final_return"
2c2fa1
+set test {watch data.u.size8twice[1]}
2c2fa1
+set wpnum ""
2c2fa1
+gdb_test_multiple $test $test {
2c2fa1
+    -re "Hardware watchpoint (\[0-9\]+): .*\r\n$gdb_prompt $" {
2c2fa1
+	set wpnum $expect_out(1,string)
2c2fa1
+    }
2c2fa1
+    -re "Watchpoint (\[0-9\]+): .*\r\n$gdb_prompt $" {
2c2fa1
+	if {[istarget "arm*-*-*"]} {
2c2fa1
+	    untested $test
2c2fa1
+	    set wpnum 0
2c2fa1
+	}
2c2fa1
+    }
2c2fa1
+}
2c2fa1
+if {$wpnum} {
2c2fa1
+    set test "continue"
2c2fa1
+    set got_hit 0
2c2fa1
+    gdb_test_multiple $test $test {
2c2fa1
+	-re "\r\nCould not insert hardware watchpoint .*\r\n$gdb_prompt $" {
2c2fa1
+	}
2c2fa1
+	-re "Hardware watchpoint $wpnum:.*New value = .*\r\n$gdb_prompt $" {
2c2fa1
+	    set got_hit 1
2c2fa1
+	    send_gdb "continue\n"
2c2fa1
+	    exp_continue
2c2fa1
+	}
2c2fa1
+	-re " final_return .*\r\n$gdb_prompt $" {
2c2fa1
+	}
2c2fa1
+    }
2c2fa1
+    gdb_assert $got_hit "size8twice write"
2c2fa1
+}
2c2fa1
Index: gdb-7.6.1/gdb/utils.c
2c2fa1
===================================================================
2c2fa1
--- gdb-7.6.1.orig/gdb/utils.c	2018-05-05 17:12:47.002758937 +0200
2c2fa1
+++ gdb-7.6.1/gdb/utils.c	2018-05-05 17:12:49.571781890 +0200
2c2fa1
@@ -3316,22 +3316,6 @@
2c2fa1
   return xstrdup (filename);
2c2fa1
 }
2c2fa1
 
2c2fa1
-ULONGEST
2c2fa1
-align_up (ULONGEST v, int n)
2c2fa1
-{
2c2fa1
-  /* Check that N is really a power of two.  */
2c2fa1
-  gdb_assert (n && (n & (n-1)) == 0);
2c2fa1
-  return (v + n - 1) & -n;
2c2fa1
-}
2c2fa1
-
2c2fa1
-ULONGEST
2c2fa1
-align_down (ULONGEST v, int n)
2c2fa1
-{
2c2fa1
-  /* Check that N is really a power of two.  */
2c2fa1
-  gdb_assert (n && (n & (n-1)) == 0);
2c2fa1
-  return (v & -n);
2c2fa1
-}
2c2fa1
-
2c2fa1
 /* Allocation function for the libiberty hash table which uses an
2c2fa1
    obstack.  The obstack is passed as DATA.  */
2c2fa1
 
2c2fa1
Index: gdb-7.6.1/gdb/utils.h
2c2fa1
===================================================================
2c2fa1
--- gdb-7.6.1.orig/gdb/utils.h	2018-05-05 17:12:47.002758937 +0200
2c2fa1
+++ gdb-7.6.1/gdb/utils.h	2018-05-05 17:12:49.572781899 +0200
2c2fa1
@@ -346,38 +346,6 @@
2c2fa1
 
2c2fa1
 extern int myread (int, char *, int);
2c2fa1
 
2c2fa1
-/* Ensure that V is aligned to an N byte boundary (B's assumed to be a
2c2fa1
-   power of 2).  Round up/down when necessary.  Examples of correct
2c2fa1
-   use include:
2c2fa1
-
2c2fa1
-   addr = align_up (addr, 8); -- VALUE needs 8 byte alignment
2c2fa1
-   write_memory (addr, value, len);
2c2fa1
-   addr += len;
2c2fa1
-
2c2fa1
-   and:
2c2fa1
-
2c2fa1
-   sp = align_down (sp - len, 16); -- Keep SP 16 byte aligned
2c2fa1
-   write_memory (sp, value, len);
2c2fa1
-
2c2fa1
-   Note that uses such as:
2c2fa1
-
2c2fa1
-   write_memory (addr, value, len);
2c2fa1
-   addr += align_up (len, 8);
2c2fa1
-
2c2fa1
-   and:
2c2fa1
-
2c2fa1
-   sp -= align_up (len, 8);
2c2fa1
-   write_memory (sp, value, len);
2c2fa1
-
2c2fa1
-   are typically not correct as they don't ensure that the address (SP
2c2fa1
-   or ADDR) is correctly aligned (relying on previous alignment to
2c2fa1
-   keep things right).  This is also why the methods are called
2c2fa1
-   "align_..." instead of "round_..." as the latter reads better with
2c2fa1
-   this incorrect coding style.  */
2c2fa1
-
2c2fa1
-extern ULONGEST align_up (ULONGEST v, int n);
2c2fa1
-extern ULONGEST align_down (ULONGEST v, int n);
2c2fa1
-
2c2fa1
 extern struct cleanup *make_cleanup_restore_selected_frame (void);
2c2fa1
 
2c2fa1
 #endif /* UTILS_H */
2c2fa1
Index: gdb-7.6.1/gdb/testsuite/lib/gdb.exp
2c2fa1
===================================================================
2c2fa1
--- gdb-7.6.1.orig/gdb/testsuite/lib/gdb.exp	2018-05-05 17:12:47.001758928 +0200
2c2fa1
+++ gdb-7.6.1/gdb/testsuite/lib/gdb.exp	2018-05-05 17:13:20.200055570 +0200
2c2fa1
@@ -1209,6 +1209,26 @@
2c2fa1
     }
2c2fa1
 }
2c2fa1
 
2c2fa1
+# Issue a PASS and return true if evaluating CONDITION in the caller's
2c2fa1
+# frame returns true, and issue a FAIL and return false otherwise.
2c2fa1
+# MESSAGE is the pass/fail message to be printed.  If MESSAGE is
2c2fa1
+# omitted or is empty, then the pass/fail messages use the condition
2c2fa1
+# string as the message.
2c2fa1
+
2c2fa1
+proc gdb_assert { condition {message ""} } {
2c2fa1
+    if { $message == ""} {
2c2fa1
+        set message $condition
2c2fa1
+    }
2c2fa1
+
2c2fa1
+    set res [uplevel 1 expr $condition]
2c2fa1
+    if {!$res} {
2c2fa1
+        fail $message
2c2fa1
+    } else {
2c2fa1
+        pass $message
2c2fa1
+    }
2c2fa1
+    return $res
2c2fa1
+}
2c2fa1
+
2c2fa1
 proc gdb_reinitialize_dir { subdir } {
2c2fa1
     global gdb_prompt
2c2fa1