-/* Copyright (C) 2009-2015 Free Software Foundation, Inc.
+/* Copyright (C) 2009-2016 Free Software Foundation, Inc.
Contributed by ARM Ltd.
This file is part of GDB.
#include "common-defs.h"
#include "break-common.h"
+#include "common-regcache.h"
#include "nat/linux-nat.h"
#include "aarch64-linux-hw-point.h"
static int
aarch64_point_is_aligned (int is_watchpoint, CORE_ADDR addr, int len)
{
- unsigned int alignment = is_watchpoint ? AARCH64_HWP_ALIGNMENT
- : AARCH64_HBP_ALIGNMENT;
+ unsigned int alignment = 0;
+
+ if (is_watchpoint)
+ alignment = AARCH64_HWP_ALIGNMENT;
+ else
+ {
+ struct regcache *regcache
+ = get_thread_regcache_for_ptid (current_lwp_ptid ());
+
+ /* Set alignment to 2 only if the current process is 32-bit,
+ since thumb instruction can be 2-byte aligned. Otherwise, set
+ alignment to AARCH64_HBP_ALIGNMENT. */
+ if (regcache_register_size (regcache, 0) == 8)
+ alignment = AARCH64_HBP_ALIGNMENT;
+ else
+ alignment = 2;
+ }
if (addr & (alignment - 1))
return 0;
{
struct aarch64_dr_update_callback_param *param_p
= (struct aarch64_dr_update_callback_param *) ptr;
- int pid = ptid_get_pid (ptid_of_lwp (lwp));
+ int tid = ptid_get_lwp (ptid_of_lwp (lwp));
int idx = param_p->idx;
int is_watchpoint = param_p->is_watchpoint;
struct arch_lwp_info *info = lwp_arch_private_info (lwp);
if (show_debug_regs)
{
debug_printf ("debug_reg_change_callback: \n\tOn entry:\n");
- debug_printf ("\tpid%d, dr_changed_bp=0x%s, "
- "dr_changed_wp=0x%s\n", pid,
+ debug_printf ("\ttid%d, dr_changed_bp=0x%s, "
+ "dr_changed_wp=0x%s\n", tid,
phex (info->dr_changed_bp, 8),
phex (info->dr_changed_wp, 8));
}
if (show_debug_regs)
{
- debug_printf ("\tOn exit:\n\tpid%d, dr_changed_bp=0x%s, "
- "dr_changed_wp=0x%s\n", pid,
+ debug_printf ("\tOn exit:\n\ttid%d, dr_changed_bp=0x%s, "
+ "dr_changed_wp=0x%s\n", tid,
phex (info->dr_changed_bp, 8),
phex (info->dr_changed_wp, 8));
}
/* Set up state pointers. */
is_watchpoint = (type != hw_execute);
- gdb_assert (aarch64_point_is_aligned (is_watchpoint, addr, len));
if (is_watchpoint)
{
num_regs = aarch64_num_wp_regs;
int len, int is_insert,
struct aarch64_debug_reg_state *state)
{
- /* The hardware breakpoint on AArch64 should always be 4-byte
- aligned. */
- if (!aarch64_point_is_aligned (0 /* is_watchpoint */ , addr, len))
- return -1;
-
if (is_insert)
- return aarch64_dr_state_insert_one_point (state, type, addr, len);
+ {
+ /* The hardware breakpoint on AArch64 should always be 4-byte
+ aligned, but on AArch32, it can be 2-byte aligned. Note that
+ we only check the alignment on inserting breakpoint because
+ aarch64_point_is_aligned needs the inferior_ptid inferior's
+ regcache to decide whether the inferior is 32-bit or 64-bit.
+ However when GDB follows the parent process and detach breakpoints
+ from child process, inferior_ptid is the child ptid, but the
+ child inferior doesn't exist in GDB's view yet. */
+ if (!aarch64_point_is_aligned (0 /* is_watchpoint */ , addr, len))
+ return -1;
+
+ return aarch64_dr_state_insert_one_point (state, type, addr, len);
+ }
else
return aarch64_dr_state_remove_one_point (state, type, addr, len);
}
ctrl = watchpoint ? state->dr_ctrl_wp : state->dr_ctrl_bp;
if (count == 0)
return;
- iov.iov_len = (offsetof (struct user_hwdebug_state, dbg_regs[count - 1])
- + sizeof (regs.dbg_regs [count - 1]));
+ iov.iov_len = (offsetof (struct user_hwdebug_state, dbg_regs)
+ + count * sizeof (regs.dbg_regs[0]));
for (i = 0; i < count; i++)
{
aarch64_num_bp_regs = 0;
}
}
+
+/* Return true if we can watch a memory region that starts address
+ ADDR and whose length is LEN in bytes. */
+
+int
+aarch64_linux_region_ok_for_watchpoint (CORE_ADDR addr, int len)
+{
+ CORE_ADDR aligned_addr;
+
+ /* Can not set watchpoints for zero or negative lengths. */
+ if (len <= 0)
+ return 0;
+
+ /* Must have hardware watchpoint debug register(s). */
+ if (aarch64_num_wp_regs == 0)
+ return 0;
+
+ /* We support unaligned watchpoint address and arbitrary length,
+ as long as the size of the whole watched area after alignment
+ doesn't exceed size of the total area that all watchpoint debug
+ registers can watch cooperatively.
+
+ This is a very relaxed rule, but unfortunately there are
+ limitations, e.g. false-positive hits, due to limited support of
+ hardware debug registers in the kernel. See comment above
+ aarch64_align_watchpoint for more information. */
+
+ aligned_addr = addr & ~(AARCH64_HWP_MAX_LEN_PER_REG - 1);
+ if (aligned_addr + aarch64_num_wp_regs * AARCH64_HWP_MAX_LEN_PER_REG
+ < addr + len)
+ return 0;
+
+ /* All tests passed so we are likely to be able to set the watchpoint.
+ The reason that it is 'likely' rather than 'must' is because
+ we don't check the current usage of the watchpoint registers, and
+ there may not be enough registers available for this watchpoint.
+ Ideally we should check the cached debug register state, however
+ the checking is costly. */
+ return 1;
+}