+ regaddr = (CORE_ADDR) -1;
+
+ return regaddr;
+}
+
+/* Fetch the thread-local storage pointer for libthread_db. */
+
+ps_err_e
+ps_get_thread_area (struct ps_prochandle *ph,
+ lwpid_t lwpid, int idx, void **base)
+{
+ if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0)
+ return PS_ERR;
+
+ /* IDX is the bias from the thread pointer to the beginning of the
+ thread descriptor. It has to be subtracted due to implementation
+ quirks in libthread_db. */
+ *base = (void *) ((char *)*base - idx);
+
+ return PS_OK;
+}
+
+/* Wrapper functions. These are only used by libthread_db. */
+
+void
+supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregsetp)
+{
+ if (mips_isa_regsize (regcache->arch ()) == 4)
+ mips_supply_gregset (regcache, (const mips_elf_gregset_t *) gregsetp);
+ else
+ mips64_supply_gregset (regcache, (const mips64_elf_gregset_t *) gregsetp);
+}
+
+void
+fill_gregset (const struct regcache *regcache,
+ gdb_gregset_t *gregsetp, int regno)
+{
+ if (mips_isa_regsize (regcache->arch ()) == 4)
+ mips_fill_gregset (regcache, (mips_elf_gregset_t *) gregsetp, regno);
+ else
+ mips64_fill_gregset (regcache, (mips64_elf_gregset_t *) gregsetp, regno);
+}
+
+void
+supply_fpregset (struct regcache *regcache, const gdb_fpregset_t *fpregsetp)
+{
+ mips64_supply_fpregset (regcache, (const mips64_elf_fpregset_t *) fpregsetp);
+}
+
+void
+fill_fpregset (const struct regcache *regcache,
+ gdb_fpregset_t *fpregsetp, int regno)
+{
+ mips64_fill_fpregset (regcache, (mips64_elf_fpregset_t *) fpregsetp, regno);
+}
+
+
+/* Fetch REGNO (or all registers if REGNO == -1) from the target
+ using PTRACE_GETREGS et al. */
+
+void
+mips_linux_nat_target::mips64_regsets_fetch_registers
+ (struct regcache *regcache, int regno)
+{
+ struct gdbarch *gdbarch = regcache->arch ();
+ int is_fp, is_dsp;
+ int have_dsp;
+ int regi;
+ int tid;
+
+ if (regno >= mips_regnum (gdbarch)->fp0
+ && regno <= mips_regnum (gdbarch)->fp0 + 32)
+ is_fp = 1;
+ else if (regno == mips_regnum (gdbarch)->fp_control_status)
+ is_fp = 1;
+ else if (regno == mips_regnum (gdbarch)->fp_implementation_revision)
+ is_fp = 1;
+ else
+ is_fp = 0;
+
+ /* DSP registers are optional and not a part of any set. */
+ have_dsp = mips_regnum (gdbarch)->dspctl != -1;
+ if (!have_dsp)
+ is_dsp = 0;
+ else if (regno >= mips_regnum (gdbarch)->dspacc
+ && regno < mips_regnum (gdbarch)->dspacc + 6)
+ is_dsp = 1;
+ else if (regno == mips_regnum (gdbarch)->dspctl)
+ is_dsp = 1;
+ else
+ is_dsp = 0;
+
+ tid = get_ptrace_pid (regcache->ptid ());
+
+ if (regno == -1 || (!is_fp && !is_dsp))
+ {
+ mips64_elf_gregset_t regs;
+
+ if (ptrace (PTRACE_GETREGS, tid, 0L, (PTRACE_TYPE_ARG3) ®s) == -1)
+ {
+ if (errno == EIO)
+ {
+ have_ptrace_regsets = 0;
+ return;
+ }
+ perror_with_name (_("Couldn't get registers"));
+ }
+
+ mips64_supply_gregset (regcache,
+ (const mips64_elf_gregset_t *) ®s);
+ }
+
+ if (regno == -1 || is_fp)
+ {
+ mips64_elf_fpregset_t fp_regs;
+
+ if (ptrace (PTRACE_GETFPREGS, tid, 0L,
+ (PTRACE_TYPE_ARG3) &fp_regs) == -1)
+ {
+ if (errno == EIO)
+ {
+ have_ptrace_regsets = 0;
+ return;
+ }
+ perror_with_name (_("Couldn't get FP registers"));
+ }
+
+ mips64_supply_fpregset (regcache,
+ (const mips64_elf_fpregset_t *) &fp_regs);
+ }
+
+ if (is_dsp)
+ linux_nat_trad_target::fetch_registers (regcache, regno);
+ else if (regno == -1 && have_dsp)
+ {
+ for (regi = mips_regnum (gdbarch)->dspacc;
+ regi < mips_regnum (gdbarch)->dspacc + 6;
+ regi++)
+ linux_nat_trad_target::fetch_registers (regcache, regi);
+ linux_nat_trad_target::fetch_registers (regcache,
+ mips_regnum (gdbarch)->dspctl);
+ }
+}
+
+/* Store REGNO (or all registers if REGNO == -1) to the target
+ using PTRACE_SETREGS et al. */
+
+void
+mips_linux_nat_target::mips64_regsets_store_registers
+ (struct regcache *regcache, int regno)
+{
+ struct gdbarch *gdbarch = regcache->arch ();
+ int is_fp, is_dsp;
+ int have_dsp;
+ int regi;
+ int tid;
+
+ if (regno >= mips_regnum (gdbarch)->fp0
+ && regno <= mips_regnum (gdbarch)->fp0 + 32)
+ is_fp = 1;
+ else if (regno == mips_regnum (gdbarch)->fp_control_status)
+ is_fp = 1;
+ else if (regno == mips_regnum (gdbarch)->fp_implementation_revision)
+ is_fp = 1;
+ else
+ is_fp = 0;
+
+ /* DSP registers are optional and not a part of any set. */
+ have_dsp = mips_regnum (gdbarch)->dspctl != -1;
+ if (!have_dsp)
+ is_dsp = 0;
+ else if (regno >= mips_regnum (gdbarch)->dspacc
+ && regno < mips_regnum (gdbarch)->dspacc + 6)
+ is_dsp = 1;
+ else if (regno == mips_regnum (gdbarch)->dspctl)
+ is_dsp = 1;
+ else
+ is_dsp = 0;
+
+ tid = get_ptrace_pid (regcache->ptid ());
+
+ if (regno == -1 || (!is_fp && !is_dsp))
+ {
+ mips64_elf_gregset_t regs;
+
+ if (ptrace (PTRACE_GETREGS, tid, 0L, (PTRACE_TYPE_ARG3) ®s) == -1)
+ perror_with_name (_("Couldn't get registers"));
+
+ mips64_fill_gregset (regcache, ®s, regno);
+
+ if (ptrace (PTRACE_SETREGS, tid, 0L, (PTRACE_TYPE_ARG3) ®s) == -1)
+ perror_with_name (_("Couldn't set registers"));
+ }
+
+ if (regno == -1 || is_fp)
+ {
+ mips64_elf_fpregset_t fp_regs;
+
+ if (ptrace (PTRACE_GETFPREGS, tid, 0L,
+ (PTRACE_TYPE_ARG3) &fp_regs) == -1)
+ perror_with_name (_("Couldn't get FP registers"));
+
+ mips64_fill_fpregset (regcache, &fp_regs, regno);
+
+ if (ptrace (PTRACE_SETFPREGS, tid, 0L,
+ (PTRACE_TYPE_ARG3) &fp_regs) == -1)
+ perror_with_name (_("Couldn't set FP registers"));
+ }
+
+ if (is_dsp)
+ linux_nat_trad_target::store_registers (regcache, regno);
+ else if (regno == -1 && have_dsp)
+ {
+ for (regi = mips_regnum (gdbarch)->dspacc;
+ regi < mips_regnum (gdbarch)->dspacc + 6;
+ regi++)
+ linux_nat_trad_target::store_registers (regcache, regi);
+ linux_nat_trad_target::store_registers (regcache,
+ mips_regnum (gdbarch)->dspctl);
+ }
+}
+
+/* Fetch REGNO (or all registers if REGNO == -1) from the target
+ using any working method. */
+
+void
+mips_linux_nat_target::fetch_registers (struct regcache *regcache, int regnum)
+{
+ /* Unless we already know that PTRACE_GETREGS does not work, try it. */
+ if (have_ptrace_regsets)
+ mips64_regsets_fetch_registers (regcache, regnum);
+
+ /* If we know, or just found out, that PTRACE_GETREGS does not work, fall
+ back to PTRACE_PEEKUSER. */
+ if (!have_ptrace_regsets)
+ {
+ linux_nat_trad_target::fetch_registers (regcache, regnum);
+
+ /* Fill the inaccessible zero register with zero. */
+ if (regnum == MIPS_ZERO_REGNUM || regnum == -1)
+ regcache->raw_supply_zeroed (MIPS_ZERO_REGNUM);
+ }
+}
+
+/* Store REGNO (or all registers if REGNO == -1) to the target
+ using any working method. */
+
+void
+mips_linux_nat_target::store_registers (struct regcache *regcache, int regnum)
+{
+ /* Unless we already know that PTRACE_GETREGS does not work, try it. */
+ if (have_ptrace_regsets)
+ mips64_regsets_store_registers (regcache, regnum);
+
+ /* If we know, or just found out, that PTRACE_GETREGS does not work, fall
+ back to PTRACE_PEEKUSER. */
+ if (!have_ptrace_regsets)
+ linux_nat_trad_target::store_registers (regcache, regnum);
+}
+
+/* Return the address in the core dump or inferior of register
+ REGNO. */
+
+CORE_ADDR
+mips_linux_nat_target::register_u_offset (struct gdbarch *gdbarch,
+ int regno, int store_p)
+{
+ if (mips_abi_regsize (gdbarch) == 8)
+ return mips64_linux_register_addr (gdbarch, regno, store_p);
+ else
+ 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))