+ return mips_linux_register_addr (gdbarch, regno, store_p);
+}
+
+const struct target_desc *
+mips_linux_nat_target::read_description ()
+{
+ static int have_dsp = -1;
+
+ if (have_dsp < 0)
+ {
+ int tid = get_ptrace_pid (inferior_ptid);
+
+ errno = 0;
+ ptrace (PTRACE_PEEKUSER, tid, DSP_CONTROL, 0);
+ switch (errno)
+ {
+ case 0:
+ have_dsp = 1;
+ break;
+ case EIO:
+ have_dsp = 0;
+ break;
+ default:
+ perror_with_name (_("Couldn't check DSP support"));
+ break;
+ }
+ }
+
+ /* Report that target registers are a size we know for sure
+ that we can get from ptrace. */
+ if (_MIPS_SIM == _ABIO32)
+ return have_dsp ? tdesc_mips_dsp_linux : tdesc_mips_linux;
+ else
+ return have_dsp ? tdesc_mips64_dsp_linux : tdesc_mips64_linux;
+}
+
+/* -1 if the kernel and/or CPU do not support watch registers.
+ 1 if watch_readback is valid and we can read style, num_valid
+ and the masks.
+ 0 if we need to read the watch_readback. */
+
+static int watch_readback_valid;
+
+/* Cached watch register read values. */
+
+static struct pt_watch_regs watch_readback;
+
+static struct mips_watchpoint *current_watches;
+
+/* The current set of watch register values for writing the
+ registers. */
+
+static struct pt_watch_regs watch_mirror;
+
+static void
+mips_show_dr (const char *func, CORE_ADDR addr,
+ int len, enum target_hw_bp_type type)
+{
+ int i;
+
+ puts_unfiltered (func);
+ if (addr || len)
+ printf_unfiltered (" (addr=%s, len=%d, type=%s)",
+ paddress (target_gdbarch (), addr), len,
+ type == hw_write ? "data-write"
+ : (type == hw_read ? "data-read"
+ : (type == hw_access ? "data-read/write"
+ : (type == hw_execute ? "instruction-execute"
+ : "??unknown??"))));
+ puts_unfiltered (":\n");
+
+ for (i = 0; i < MAX_DEBUG_REGISTER; i++)
+ printf_unfiltered ("\tDR%d: lo=%s, hi=%s\n", i,
+ paddress (target_gdbarch (),
+ mips_linux_watch_get_watchlo (&watch_mirror,
+ i)),
+ paddress (target_gdbarch (),
+ mips_linux_watch_get_watchhi (&watch_mirror,
+ i)));
+}
+
+/* Target to_can_use_hw_breakpoint implementation. Return 1 if we can
+ handle the specified watch type. */
+
+int
+mips_linux_nat_target::can_use_hw_breakpoint (enum bptype type,
+ int cnt, int ot)
+{
+ int i;
+ uint32_t wanted_mask, irw_mask;
+
+ if (!mips_linux_read_watch_registers (inferior_ptid.lwp (),
+ &watch_readback,
+ &watch_readback_valid, 0))
+ return 0;
+
+ switch (type)
+ {
+ case bp_hardware_watchpoint:
+ wanted_mask = W_MASK;
+ break;
+ case bp_read_watchpoint:
+ wanted_mask = R_MASK;
+ break;
+ case bp_access_watchpoint:
+ wanted_mask = R_MASK | W_MASK;
+ break;
+ default:
+ return 0;
+ }
+
+ for (i = 0;
+ i < mips_linux_watch_get_num_valid (&watch_readback) && cnt;
+ i++)
+ {
+ irw_mask = mips_linux_watch_get_irw_mask (&watch_readback, i);
+ if ((irw_mask & wanted_mask) == wanted_mask)
+ cnt--;
+ }
+ return (cnt == 0) ? 1 : 0;
+}
+
+/* Target to_stopped_by_watchpoint implementation. Return 1 if
+ stopped by watchpoint. The watchhi R and W bits indicate the watch
+ register triggered. */
+
+bool
+mips_linux_nat_target::stopped_by_watchpoint ()
+{
+ int n;
+ int num_valid;
+
+ if (!mips_linux_read_watch_registers (inferior_ptid.lwp (),
+ &watch_readback,
+ &watch_readback_valid, 1))
+ return false;
+
+ num_valid = mips_linux_watch_get_num_valid (&watch_readback);
+
+ for (n = 0; n < MAX_DEBUG_REGISTER && n < num_valid; n++)
+ if (mips_linux_watch_get_watchhi (&watch_readback, n) & (R_MASK | W_MASK))
+ return true;
+
+ return false;
+}
+
+/* Target to_stopped_data_address implementation. Set the address
+ where the watch triggered (if known). Return 1 if the address was
+ known. */
+
+bool
+mips_linux_nat_target::stopped_data_address (CORE_ADDR *paddr)
+{
+ /* On mips we don't know the low order 3 bits of the data address,
+ so we must return false. */
+ return false;
+}
+
+/* Target to_region_ok_for_hw_watchpoint implementation. Return 1 if
+ the specified region can be covered by the watch registers. */
+
+int
+mips_linux_nat_target::region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
+{
+ struct pt_watch_regs dummy_regs;
+ int i;
+
+ if (!mips_linux_read_watch_registers (inferior_ptid.lwp (),
+ &watch_readback,
+ &watch_readback_valid, 0))
+ return 0;
+
+ dummy_regs = watch_readback;
+ /* Clear them out. */
+ for (i = 0; i < mips_linux_watch_get_num_valid (&dummy_regs); i++)
+ mips_linux_watch_set_watchlo (&dummy_regs, i, 0);
+ return mips_linux_watch_try_one_watch (&dummy_regs, addr, len, 0);
+}
+
+/* Write the mirrored watch register values for each thread. */
+
+static int
+write_watchpoint_regs (void)
+{
+ struct lwp_info *lp;
+ int tid;
+
+ ALL_LWPS (lp)
+ {
+ tid = lp->ptid.lwp ();
+ if (ptrace (PTRACE_SET_WATCH_REGS, tid, &watch_mirror, NULL) == -1)
+ perror_with_name (_("Couldn't write debug register"));
+ }
+ return 0;
+}
+
+/* linux_nat_target::low_new_thread implementation. Write the
+ mirrored watch register values for the new thread. */
+
+void
+mips_linux_nat_target::low_new_thread (struct lwp_info *lp)
+{
+ long tid = lp->ptid.lwp ();
+
+ if (!mips_linux_read_watch_registers (tid,
+ &watch_readback,
+ &watch_readback_valid, 0))
+ return;
+
+ if (ptrace (PTRACE_SET_WATCH_REGS, tid, &watch_mirror, NULL) == -1)
+ perror_with_name (_("Couldn't write debug register"));
+}
+
+/* Target to_insert_watchpoint implementation. Try to insert a new
+ watch. Return zero on success. */
+
+int
+mips_linux_nat_target::insert_watchpoint (CORE_ADDR addr, int len,
+ enum target_hw_bp_type type,
+ struct expression *cond)
+{
+ struct pt_watch_regs regs;
+ struct mips_watchpoint *new_watch;
+ struct mips_watchpoint **pw;
+
+ int retval;
+
+ if (!mips_linux_read_watch_registers (inferior_ptid.lwp (),
+ &watch_readback,
+ &watch_readback_valid, 0))
+ return -1;
+
+ if (len <= 0)
+ return -1;
+
+ regs = watch_readback;
+ /* Add the current watches. */
+ mips_linux_watch_populate_regs (current_watches, ®s);
+
+ /* Now try to add the new watch. */
+ if (!mips_linux_watch_try_one_watch (®s, addr, len,
+ mips_linux_watch_type_to_irw (type)))
+ return -1;
+
+ /* It fit. Stick it on the end of the list. */
+ new_watch = XNEW (struct mips_watchpoint);
+ new_watch->addr = addr;
+ new_watch->len = len;
+ new_watch->type = type;
+ new_watch->next = NULL;
+
+ pw = ¤t_watches;
+ while (*pw != NULL)
+ pw = &(*pw)->next;
+ *pw = new_watch;
+
+ watch_mirror = regs;
+ retval = write_watchpoint_regs ();
+
+ if (show_debug_regs)
+ mips_show_dr ("insert_watchpoint", addr, len, type);
+
+ return retval;