#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_debug_reg_state *state)
{
/* The hardware breakpoint on AArch64 should always be 4-byte
- aligned. */
+ aligned, but on AArch32, it can be 2-byte aligned. */
if (!aarch64_point_is_aligned (0 /* is_watchpoint */ , addr, len))
return -1;
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;
+}