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