+/* Are two break-/watch-points equal? */
+static int
+arm_linux_hw_breakpoint_equal (const struct arm_linux_hw_breakpoint *p1,
+ const struct arm_linux_hw_breakpoint *p2)
+{
+ return p1->address == p2->address && p1->control == p2->control;
+}
+
+/* Callback to mark a watch-/breakpoint to be updated in all threads of
+ the current process. */
+
+struct update_registers_data
+{
+ int watch;
+ int index;
+};
+
+static int
+update_registers_callback (struct lwp_info *lwp, void *arg)
+{
+ struct update_registers_data *data = (struct update_registers_data *) arg;
+
+ if (lwp->arch_private == NULL)
+ lwp->arch_private = XCNEW (struct arch_lwp_info);
+
+ /* The actual update is done later just before resuming the lwp,
+ we just mark that the registers need updating. */
+ if (data->watch)
+ lwp->arch_private->wpts_changed[data->index] = 1;
+ else
+ lwp->arch_private->bpts_changed[data->index] = 1;
+
+ /* If the lwp isn't stopped, force it to momentarily pause, so
+ we can update its breakpoint registers. */
+ if (!lwp->stopped)
+ linux_stop_lwp (lwp);
+
+ return 0;
+}
+
+/* Insert the hardware breakpoint (WATCHPOINT = 0) or watchpoint (WATCHPOINT
+ =1) BPT for thread TID. */
+static void
+arm_linux_insert_hw_breakpoint1 (const struct arm_linux_hw_breakpoint* bpt,
+ int watchpoint)
+{
+ int pid;
+ ptid_t pid_ptid;
+ gdb_byte count, i;
+ struct arm_linux_hw_breakpoint* bpts;
+ struct update_registers_data data;
+
+ pid = ptid_get_pid (inferior_ptid);
+ pid_ptid = pid_to_ptid (pid);
+
+ if (watchpoint)
+ {
+ count = arm_linux_get_hw_watchpoint_count ();
+ bpts = arm_linux_get_debug_reg_state (pid)->wpts;
+ }
+ else
+ {
+ count = arm_linux_get_hw_breakpoint_count ();
+ bpts = arm_linux_get_debug_reg_state (pid)->bpts;
+ }
+
+ for (i = 0; i < count; ++i)
+ if (!arm_hwbp_control_is_enabled (bpts[i].control))
+ {
+ data.watch = watchpoint;
+ data.index = i;
+ bpts[i] = *bpt;
+ iterate_over_lwps (pid_ptid, update_registers_callback, &data);
+ break;
+ }
+
+ gdb_assert (i != count);
+}
+
+/* Remove the hardware breakpoint (WATCHPOINT = 0) or watchpoint
+ (WATCHPOINT = 1) BPT for thread TID. */
+static void
+arm_linux_remove_hw_breakpoint1 (const struct arm_linux_hw_breakpoint *bpt,
+ int watchpoint)
+{
+ int pid;
+ gdb_byte count, i;
+ ptid_t pid_ptid;
+ struct arm_linux_hw_breakpoint* bpts;
+ struct update_registers_data data;
+
+ pid = ptid_get_pid (inferior_ptid);
+ pid_ptid = pid_to_ptid (pid);
+
+ if (watchpoint)
+ {
+ count = arm_linux_get_hw_watchpoint_count ();
+ bpts = arm_linux_get_debug_reg_state (pid)->wpts;
+ }
+ else
+ {
+ count = arm_linux_get_hw_breakpoint_count ();
+ bpts = arm_linux_get_debug_reg_state (pid)->bpts;
+ }
+
+ for (i = 0; i < count; ++i)
+ if (arm_linux_hw_breakpoint_equal (bpt, bpts + i))
+ {
+ data.watch = watchpoint;
+ data.index = i;
+ bpts[i].control = arm_hwbp_control_disable (bpts[i].control);
+ iterate_over_lwps (pid_ptid, update_registers_callback, &data);
+ break;
+ }
+
+ gdb_assert (i != count);
+}
+
+/* Insert a Hardware breakpoint. */
+int
+arm_linux_nat_target::insert_hw_breakpoint (struct gdbarch *gdbarch,
+ struct bp_target_info *bp_tgt)
+{
+ struct lwp_info *lp;
+ struct arm_linux_hw_breakpoint p;
+
+ if (arm_linux_get_hw_breakpoint_count () == 0)
+ return -1;
+
+ arm_linux_hw_breakpoint_initialize (gdbarch, bp_tgt, &p);
+
+ arm_linux_insert_hw_breakpoint1 (&p, 0);
+
+ return 0;
+}
+
+/* Remove a hardware breakpoint. */
+int
+arm_linux_nat_target::remove_hw_breakpoint (struct gdbarch *gdbarch,
+ struct bp_target_info *bp_tgt)
+{
+ struct lwp_info *lp;
+ struct arm_linux_hw_breakpoint p;
+
+ if (arm_linux_get_hw_breakpoint_count () == 0)
+ return -1;
+
+ arm_linux_hw_breakpoint_initialize (gdbarch, bp_tgt, &p);
+
+ arm_linux_remove_hw_breakpoint1 (&p, 0);
+
+ return 0;
+}
+
+/* Are we able to use a hardware watchpoint for the LEN bytes starting at
+ ADDR? */
+int
+arm_linux_nat_target::region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
+{
+ const struct arm_linux_hwbp_cap *cap = arm_linux_get_hwbp_cap ();
+ CORE_ADDR max_wp_length, aligned_addr;
+
+ /* Can not set watchpoints for zero or negative lengths. */
+ if (len <= 0)
+ return 0;
+
+ /* Need to be able to use the ptrace interface. */
+ if (cap == NULL || cap->wp_count == 0)
+ return 0;
+
+ /* Test that the range [ADDR, ADDR + LEN) fits into the largest address
+ range covered by a watchpoint. */
+ max_wp_length = (CORE_ADDR)cap->max_wp_length;
+ aligned_addr = addr & ~(max_wp_length - 1);
+
+ if (aligned_addr + max_wp_length < addr + len)
+ return 0;
+
+ /* The current ptrace interface can only handle watchpoints that are a
+ power of 2. */
+ if ((len & (len - 1)) != 0)
+ return 0;
+
+ /* All tests passed so we must be able to set a watchpoint. */
+ return 1;
+}
+
+/* Insert a Hardware breakpoint. */