OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gdb-7.1/] [gdb/] [mips-linux-nat.c] - Diff between revs 834 and 842

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 834 Rev 842
/* Native-dependent code for GNU/Linux on MIPS processors.
/* Native-dependent code for GNU/Linux on MIPS processors.
 
 
   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
   Free Software Foundation, Inc.
   Free Software Foundation, Inc.
 
 
   This file is part of GDB.
   This file is part of GDB.
 
 
   This program is free software; you can redistribute it and/or modify
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.
   (at your option) any later version.
 
 
   This program is distributed in the hope that it will be useful,
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   GNU General Public License for more details.
 
 
   You should have received a copy of the GNU General Public License
   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 
#include "defs.h"
#include "defs.h"
#include "command.h"
#include "command.h"
#include "gdbcmd.h"
#include "gdbcmd.h"
#include "gdb_assert.h"
#include "gdb_assert.h"
#include "inferior.h"
#include "inferior.h"
#include "mips-tdep.h"
#include "mips-tdep.h"
#include "target.h"
#include "target.h"
#include "regcache.h"
#include "regcache.h"
#include "linux-nat.h"
#include "linux-nat.h"
#include "mips-linux-tdep.h"
#include "mips-linux-tdep.h"
#include "target-descriptions.h"
#include "target-descriptions.h"
 
 
#include "gdb_proc_service.h"
#include "gdb_proc_service.h"
#include "gregset.h"
#include "gregset.h"
 
 
#include <sgidefs.h>
#include <sgidefs.h>
#include <sys/ptrace.h>
#include <sys/ptrace.h>
 
 
#include "features/mips-linux.c"
#include "features/mips-linux.c"
#include "features/mips64-linux.c"
#include "features/mips64-linux.c"
 
 
#ifndef PTRACE_GET_THREAD_AREA
#ifndef PTRACE_GET_THREAD_AREA
#define PTRACE_GET_THREAD_AREA 25
#define PTRACE_GET_THREAD_AREA 25
#endif
#endif
 
 
/* Assume that we have PTRACE_GETREGS et al. support.  If we do not,
/* Assume that we have PTRACE_GETREGS et al. support.  If we do not,
   we'll clear this and use PTRACE_PEEKUSER instead.  */
   we'll clear this and use PTRACE_PEEKUSER instead.  */
static int have_ptrace_regsets = 1;
static int have_ptrace_regsets = 1;
 
 
/* Whether or not to print the mirrored debug registers.  */
/* Whether or not to print the mirrored debug registers.  */
 
 
static int maint_show_dr;
static int maint_show_dr;
 
 
/* Saved function pointers to fetch and store a single register using
/* Saved function pointers to fetch and store a single register using
   PTRACE_PEEKUSER and PTRACE_POKEUSER.  */
   PTRACE_PEEKUSER and PTRACE_POKEUSER.  */
 
 
static void (*super_fetch_registers) (struct target_ops *,
static void (*super_fetch_registers) (struct target_ops *,
                                      struct regcache *, int);
                                      struct regcache *, int);
static void (*super_store_registers) (struct target_ops *,
static void (*super_store_registers) (struct target_ops *,
                                      struct regcache *, int);
                                      struct regcache *, int);
 
 
static void (*super_close) (int);
static void (*super_close) (int);
 
 
/* Map gdb internal register number to ptrace ``address''.
/* Map gdb internal register number to ptrace ``address''.
   These ``addresses'' are normally defined in <asm/ptrace.h>.
   These ``addresses'' are normally defined in <asm/ptrace.h>.
 
 
   ptrace does not provide a way to read (or set) MIPS_PS_REGNUM,
   ptrace does not provide a way to read (or set) MIPS_PS_REGNUM,
   and there's no point in reading or setting MIPS_ZERO_REGNUM.
   and there's no point in reading or setting MIPS_ZERO_REGNUM.
   We also can not set BADVADDR, CAUSE, or FCRIR via ptrace().  */
   We also can not set BADVADDR, CAUSE, or FCRIR via ptrace().  */
 
 
static CORE_ADDR
static CORE_ADDR
mips_linux_register_addr (struct gdbarch *gdbarch, int regno, int store)
mips_linux_register_addr (struct gdbarch *gdbarch, int regno, int store)
{
{
  CORE_ADDR regaddr;
  CORE_ADDR regaddr;
 
 
  if (regno < 0 || regno >= gdbarch_num_regs (gdbarch))
  if (regno < 0 || regno >= gdbarch_num_regs (gdbarch))
    error (_("Bogon register number %d."), regno);
    error (_("Bogon register number %d."), regno);
 
 
  if (regno > MIPS_ZERO_REGNUM && regno < MIPS_ZERO_REGNUM + 32)
  if (regno > MIPS_ZERO_REGNUM && regno < MIPS_ZERO_REGNUM + 32)
    regaddr = regno;
    regaddr = regno;
  else if ((regno >= mips_regnum (gdbarch)->fp0)
  else if ((regno >= mips_regnum (gdbarch)->fp0)
           && (regno < mips_regnum (gdbarch)->fp0 + 32))
           && (regno < mips_regnum (gdbarch)->fp0 + 32))
    regaddr = FPR_BASE + (regno - mips_regnum (gdbarch)->fp0);
    regaddr = FPR_BASE + (regno - mips_regnum (gdbarch)->fp0);
  else if (regno == mips_regnum (gdbarch)->pc)
  else if (regno == mips_regnum (gdbarch)->pc)
    regaddr = PC;
    regaddr = PC;
  else if (regno == mips_regnum (gdbarch)->cause)
  else if (regno == mips_regnum (gdbarch)->cause)
    regaddr = store? (CORE_ADDR) -1 : CAUSE;
    regaddr = store? (CORE_ADDR) -1 : CAUSE;
  else if (regno == mips_regnum (gdbarch)->badvaddr)
  else if (regno == mips_regnum (gdbarch)->badvaddr)
    regaddr = store? (CORE_ADDR) -1 : BADVADDR;
    regaddr = store? (CORE_ADDR) -1 : BADVADDR;
  else if (regno == mips_regnum (gdbarch)->lo)
  else if (regno == mips_regnum (gdbarch)->lo)
    regaddr = MMLO;
    regaddr = MMLO;
  else if (regno == mips_regnum (gdbarch)->hi)
  else if (regno == mips_regnum (gdbarch)->hi)
    regaddr = MMHI;
    regaddr = MMHI;
  else if (regno == mips_regnum (gdbarch)->fp_control_status)
  else if (regno == mips_regnum (gdbarch)->fp_control_status)
    regaddr = FPC_CSR;
    regaddr = FPC_CSR;
  else if (regno == mips_regnum (gdbarch)->fp_implementation_revision)
  else if (regno == mips_regnum (gdbarch)->fp_implementation_revision)
    regaddr = store? (CORE_ADDR) -1 : FPC_EIR;
    regaddr = store? (CORE_ADDR) -1 : FPC_EIR;
  else if (mips_linux_restart_reg_p (gdbarch) && regno == MIPS_RESTART_REGNUM)
  else if (mips_linux_restart_reg_p (gdbarch) && regno == MIPS_RESTART_REGNUM)
    regaddr = 0;
    regaddr = 0;
  else
  else
    regaddr = (CORE_ADDR) -1;
    regaddr = (CORE_ADDR) -1;
 
 
  return regaddr;
  return regaddr;
}
}
 
 
static CORE_ADDR
static CORE_ADDR
mips64_linux_register_addr (struct gdbarch *gdbarch, int regno, int store)
mips64_linux_register_addr (struct gdbarch *gdbarch, int regno, int store)
{
{
  CORE_ADDR regaddr;
  CORE_ADDR regaddr;
 
 
  if (regno < 0 || regno >= gdbarch_num_regs (gdbarch))
  if (regno < 0 || regno >= gdbarch_num_regs (gdbarch))
    error (_("Bogon register number %d."), regno);
    error (_("Bogon register number %d."), regno);
 
 
  if (regno > MIPS_ZERO_REGNUM && regno < MIPS_ZERO_REGNUM + 32)
  if (regno > MIPS_ZERO_REGNUM && regno < MIPS_ZERO_REGNUM + 32)
    regaddr = regno;
    regaddr = regno;
  else if ((regno >= mips_regnum (gdbarch)->fp0)
  else if ((regno >= mips_regnum (gdbarch)->fp0)
           && (regno < mips_regnum (gdbarch)->fp0 + 32))
           && (regno < mips_regnum (gdbarch)->fp0 + 32))
    regaddr = MIPS64_FPR_BASE + (regno - gdbarch_fp0_regnum (gdbarch));
    regaddr = MIPS64_FPR_BASE + (regno - gdbarch_fp0_regnum (gdbarch));
  else if (regno == mips_regnum (gdbarch)->pc)
  else if (regno == mips_regnum (gdbarch)->pc)
    regaddr = MIPS64_PC;
    regaddr = MIPS64_PC;
  else if (regno == mips_regnum (gdbarch)->cause)
  else if (regno == mips_regnum (gdbarch)->cause)
    regaddr = store? (CORE_ADDR) -1 : MIPS64_CAUSE;
    regaddr = store? (CORE_ADDR) -1 : MIPS64_CAUSE;
  else if (regno == mips_regnum (gdbarch)->badvaddr)
  else if (regno == mips_regnum (gdbarch)->badvaddr)
    regaddr = store? (CORE_ADDR) -1 : MIPS64_BADVADDR;
    regaddr = store? (CORE_ADDR) -1 : MIPS64_BADVADDR;
  else if (regno == mips_regnum (gdbarch)->lo)
  else if (regno == mips_regnum (gdbarch)->lo)
    regaddr = MIPS64_MMLO;
    regaddr = MIPS64_MMLO;
  else if (regno == mips_regnum (gdbarch)->hi)
  else if (regno == mips_regnum (gdbarch)->hi)
    regaddr = MIPS64_MMHI;
    regaddr = MIPS64_MMHI;
  else if (regno == mips_regnum (gdbarch)->fp_control_status)
  else if (regno == mips_regnum (gdbarch)->fp_control_status)
    regaddr = MIPS64_FPC_CSR;
    regaddr = MIPS64_FPC_CSR;
  else if (regno == mips_regnum (gdbarch)->fp_implementation_revision)
  else if (regno == mips_regnum (gdbarch)->fp_implementation_revision)
    regaddr = store? (CORE_ADDR) -1 : MIPS64_FPC_EIR;
    regaddr = store? (CORE_ADDR) -1 : MIPS64_FPC_EIR;
  else if (mips_linux_restart_reg_p (gdbarch) && regno == MIPS_RESTART_REGNUM)
  else if (mips_linux_restart_reg_p (gdbarch) && regno == MIPS_RESTART_REGNUM)
    regaddr = 0;
    regaddr = 0;
  else
  else
    regaddr = (CORE_ADDR) -1;
    regaddr = (CORE_ADDR) -1;
 
 
  return regaddr;
  return regaddr;
}
}
 
 
/* Fetch the thread-local storage pointer for libthread_db.  */
/* Fetch the thread-local storage pointer for libthread_db.  */
 
 
ps_err_e
ps_err_e
ps_get_thread_area (const struct ps_prochandle *ph,
ps_get_thread_area (const struct ps_prochandle *ph,
                    lwpid_t lwpid, int idx, void **base)
                    lwpid_t lwpid, int idx, void **base)
{
{
  if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0)
  if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0)
    return PS_ERR;
    return PS_ERR;
 
 
  /* IDX is the bias from the thread pointer to the beginning of the
  /* IDX is the bias from the thread pointer to the beginning of the
     thread descriptor.  It has to be subtracted due to implementation
     thread descriptor.  It has to be subtracted due to implementation
     quirks in libthread_db.  */
     quirks in libthread_db.  */
  *base = (void *) ((char *)*base - idx);
  *base = (void *) ((char *)*base - idx);
 
 
  return PS_OK;
  return PS_OK;
}
}
 
 
/* Wrapper functions.  These are only used by libthread_db.  */
/* Wrapper functions.  These are only used by libthread_db.  */
 
 
void
void
supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregsetp)
supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregsetp)
{
{
  if (mips_isa_regsize (get_regcache_arch (regcache)) == 4)
  if (mips_isa_regsize (get_regcache_arch (regcache)) == 4)
    mips_supply_gregset (regcache, (const mips_elf_gregset_t *) gregsetp);
    mips_supply_gregset (regcache, (const mips_elf_gregset_t *) gregsetp);
  else
  else
    mips64_supply_gregset (regcache, (const mips64_elf_gregset_t *) gregsetp);
    mips64_supply_gregset (regcache, (const mips64_elf_gregset_t *) gregsetp);
}
}
 
 
void
void
fill_gregset (const struct regcache *regcache,
fill_gregset (const struct regcache *regcache,
              gdb_gregset_t *gregsetp, int regno)
              gdb_gregset_t *gregsetp, int regno)
{
{
  if (mips_isa_regsize (get_regcache_arch (regcache)) == 4)
  if (mips_isa_regsize (get_regcache_arch (regcache)) == 4)
    mips_fill_gregset (regcache, (mips_elf_gregset_t *) gregsetp, regno);
    mips_fill_gregset (regcache, (mips_elf_gregset_t *) gregsetp, regno);
  else
  else
    mips64_fill_gregset (regcache, (mips64_elf_gregset_t *) gregsetp, regno);
    mips64_fill_gregset (regcache, (mips64_elf_gregset_t *) gregsetp, regno);
}
}
 
 
void
void
supply_fpregset (struct regcache *regcache, const gdb_fpregset_t *fpregsetp)
supply_fpregset (struct regcache *regcache, const gdb_fpregset_t *fpregsetp)
{
{
  if (mips_isa_regsize (get_regcache_arch (regcache)) == 4)
  if (mips_isa_regsize (get_regcache_arch (regcache)) == 4)
    mips_supply_fpregset (regcache, (const mips_elf_fpregset_t *) fpregsetp);
    mips_supply_fpregset (regcache, (const mips_elf_fpregset_t *) fpregsetp);
  else
  else
    mips64_supply_fpregset (regcache, (const mips64_elf_fpregset_t *) fpregsetp);
    mips64_supply_fpregset (regcache, (const mips64_elf_fpregset_t *) fpregsetp);
}
}
 
 
void
void
fill_fpregset (const struct regcache *regcache,
fill_fpregset (const struct regcache *regcache,
               gdb_fpregset_t *fpregsetp, int regno)
               gdb_fpregset_t *fpregsetp, int regno)
{
{
  if (mips_isa_regsize (get_regcache_arch (regcache)) == 4)
  if (mips_isa_regsize (get_regcache_arch (regcache)) == 4)
    mips_fill_fpregset (regcache, (mips_elf_fpregset_t *) fpregsetp, regno);
    mips_fill_fpregset (regcache, (mips_elf_fpregset_t *) fpregsetp, regno);
  else
  else
    mips64_fill_fpregset (regcache, (mips64_elf_fpregset_t *) fpregsetp, regno);
    mips64_fill_fpregset (regcache, (mips64_elf_fpregset_t *) fpregsetp, regno);
}
}
 
 
 
 
/* Fetch REGNO (or all registers if REGNO == -1) from the target
/* Fetch REGNO (or all registers if REGNO == -1) from the target
   using PTRACE_GETREGS et al.  */
   using PTRACE_GETREGS et al.  */
 
 
static void
static void
mips64_linux_regsets_fetch_registers (struct regcache *regcache, int regno)
mips64_linux_regsets_fetch_registers (struct regcache *regcache, int regno)
{
{
  struct gdbarch *gdbarch = get_regcache_arch (regcache);
  struct gdbarch *gdbarch = get_regcache_arch (regcache);
  int is_fp;
  int is_fp;
  int tid;
  int tid;
 
 
  if (regno >= mips_regnum (gdbarch)->fp0
  if (regno >= mips_regnum (gdbarch)->fp0
      && regno <= mips_regnum (gdbarch)->fp0 + 32)
      && regno <= mips_regnum (gdbarch)->fp0 + 32)
    is_fp = 1;
    is_fp = 1;
  else if (regno == mips_regnum (gdbarch)->fp_control_status)
  else if (regno == mips_regnum (gdbarch)->fp_control_status)
    is_fp = 1;
    is_fp = 1;
  else if (regno == mips_regnum (gdbarch)->fp_implementation_revision)
  else if (regno == mips_regnum (gdbarch)->fp_implementation_revision)
    is_fp = 1;
    is_fp = 1;
  else
  else
    is_fp = 0;
    is_fp = 0;
 
 
  tid = ptid_get_lwp (inferior_ptid);
  tid = ptid_get_lwp (inferior_ptid);
  if (tid == 0)
  if (tid == 0)
    tid = ptid_get_pid (inferior_ptid);
    tid = ptid_get_pid (inferior_ptid);
 
 
  if (regno == -1 || !is_fp)
  if (regno == -1 || !is_fp)
    {
    {
      mips64_elf_gregset_t regs;
      mips64_elf_gregset_t regs;
 
 
      if (ptrace (PTRACE_GETREGS, tid, 0L, (PTRACE_TYPE_ARG3) &regs) == -1)
      if (ptrace (PTRACE_GETREGS, tid, 0L, (PTRACE_TYPE_ARG3) &regs) == -1)
        {
        {
          if (errno == EIO)
          if (errno == EIO)
            {
            {
              have_ptrace_regsets = 0;
              have_ptrace_regsets = 0;
              return;
              return;
            }
            }
          perror_with_name (_("Couldn't get registers"));
          perror_with_name (_("Couldn't get registers"));
        }
        }
 
 
      mips64_supply_gregset (regcache,
      mips64_supply_gregset (regcache,
                             (const mips64_elf_gregset_t *) &regs);
                             (const mips64_elf_gregset_t *) &regs);
    }
    }
 
 
  if (regno == -1 || is_fp)
  if (regno == -1 || is_fp)
    {
    {
      mips64_elf_fpregset_t fp_regs;
      mips64_elf_fpregset_t fp_regs;
 
 
      if (ptrace (PTRACE_GETFPREGS, tid, 0L,
      if (ptrace (PTRACE_GETFPREGS, tid, 0L,
                  (PTRACE_TYPE_ARG3) &fp_regs) == -1)
                  (PTRACE_TYPE_ARG3) &fp_regs) == -1)
        {
        {
          if (errno == EIO)
          if (errno == EIO)
            {
            {
              have_ptrace_regsets = 0;
              have_ptrace_regsets = 0;
              return;
              return;
            }
            }
          perror_with_name (_("Couldn't get FP registers"));
          perror_with_name (_("Couldn't get FP registers"));
        }
        }
 
 
      mips64_supply_fpregset (regcache,
      mips64_supply_fpregset (regcache,
                              (const mips64_elf_fpregset_t *) &fp_regs);
                              (const mips64_elf_fpregset_t *) &fp_regs);
    }
    }
}
}
 
 
/* Store REGNO (or all registers if REGNO == -1) to the target
/* Store REGNO (or all registers if REGNO == -1) to the target
   using PTRACE_SETREGS et al.  */
   using PTRACE_SETREGS et al.  */
 
 
static void
static void
mips64_linux_regsets_store_registers (const struct regcache *regcache, int regno)
mips64_linux_regsets_store_registers (const struct regcache *regcache, int regno)
{
{
  struct gdbarch *gdbarch = get_regcache_arch (regcache);
  struct gdbarch *gdbarch = get_regcache_arch (regcache);
  int is_fp;
  int is_fp;
  int tid;
  int tid;
 
 
  if (regno >= mips_regnum (gdbarch)->fp0
  if (regno >= mips_regnum (gdbarch)->fp0
      && regno <= mips_regnum (gdbarch)->fp0 + 32)
      && regno <= mips_regnum (gdbarch)->fp0 + 32)
    is_fp = 1;
    is_fp = 1;
  else if (regno == mips_regnum (gdbarch)->fp_control_status)
  else if (regno == mips_regnum (gdbarch)->fp_control_status)
    is_fp = 1;
    is_fp = 1;
  else if (regno == mips_regnum (gdbarch)->fp_implementation_revision)
  else if (regno == mips_regnum (gdbarch)->fp_implementation_revision)
    is_fp = 1;
    is_fp = 1;
  else
  else
    is_fp = 0;
    is_fp = 0;
 
 
  tid = ptid_get_lwp (inferior_ptid);
  tid = ptid_get_lwp (inferior_ptid);
  if (tid == 0)
  if (tid == 0)
    tid = ptid_get_pid (inferior_ptid);
    tid = ptid_get_pid (inferior_ptid);
 
 
  if (regno == -1 || !is_fp)
  if (regno == -1 || !is_fp)
    {
    {
      mips64_elf_gregset_t regs;
      mips64_elf_gregset_t regs;
 
 
      if (ptrace (PTRACE_GETREGS, tid, 0L, (PTRACE_TYPE_ARG3) &regs) == -1)
      if (ptrace (PTRACE_GETREGS, tid, 0L, (PTRACE_TYPE_ARG3) &regs) == -1)
        perror_with_name (_("Couldn't get registers"));
        perror_with_name (_("Couldn't get registers"));
 
 
      mips64_fill_gregset (regcache, &regs, regno);
      mips64_fill_gregset (regcache, &regs, regno);
 
 
      if (ptrace (PTRACE_SETREGS, tid, 0L, (PTRACE_TYPE_ARG3) &regs) == -1)
      if (ptrace (PTRACE_SETREGS, tid, 0L, (PTRACE_TYPE_ARG3) &regs) == -1)
        perror_with_name (_("Couldn't set registers"));
        perror_with_name (_("Couldn't set registers"));
    }
    }
 
 
  if (regno == -1 || is_fp)
  if (regno == -1 || is_fp)
    {
    {
      mips64_elf_fpregset_t fp_regs;
      mips64_elf_fpregset_t fp_regs;
 
 
      if (ptrace (PTRACE_GETFPREGS, tid, 0L,
      if (ptrace (PTRACE_GETFPREGS, tid, 0L,
                  (PTRACE_TYPE_ARG3) &fp_regs) == -1)
                  (PTRACE_TYPE_ARG3) &fp_regs) == -1)
        perror_with_name (_("Couldn't get FP registers"));
        perror_with_name (_("Couldn't get FP registers"));
 
 
      mips64_fill_fpregset (regcache, &fp_regs, regno);
      mips64_fill_fpregset (regcache, &fp_regs, regno);
 
 
      if (ptrace (PTRACE_SETFPREGS, tid, 0L,
      if (ptrace (PTRACE_SETFPREGS, tid, 0L,
                  (PTRACE_TYPE_ARG3) &fp_regs) == -1)
                  (PTRACE_TYPE_ARG3) &fp_regs) == -1)
        perror_with_name (_("Couldn't set FP registers"));
        perror_with_name (_("Couldn't set FP registers"));
    }
    }
}
}
 
 
/* Fetch REGNO (or all registers if REGNO == -1) from the target
/* Fetch REGNO (or all registers if REGNO == -1) from the target
   using any working method.  */
   using any working method.  */
 
 
static void
static void
mips64_linux_fetch_registers (struct target_ops *ops,
mips64_linux_fetch_registers (struct target_ops *ops,
                              struct regcache *regcache, int regnum)
                              struct regcache *regcache, int regnum)
{
{
  /* Unless we already know that PTRACE_GETREGS does not work, try it.  */
  /* Unless we already know that PTRACE_GETREGS does not work, try it.  */
  if (have_ptrace_regsets)
  if (have_ptrace_regsets)
    mips64_linux_regsets_fetch_registers (regcache, regnum);
    mips64_linux_regsets_fetch_registers (regcache, regnum);
 
 
  /* If we know, or just found out, that PTRACE_GETREGS does not work, fall
  /* If we know, or just found out, that PTRACE_GETREGS does not work, fall
     back to PTRACE_PEEKUSER.  */
     back to PTRACE_PEEKUSER.  */
  if (!have_ptrace_regsets)
  if (!have_ptrace_regsets)
    super_fetch_registers (ops, regcache, regnum);
    super_fetch_registers (ops, regcache, regnum);
}
}
 
 
/* Store REGNO (or all registers if REGNO == -1) to the target
/* Store REGNO (or all registers if REGNO == -1) to the target
   using any working method.  */
   using any working method.  */
 
 
static void
static void
mips64_linux_store_registers (struct target_ops *ops,
mips64_linux_store_registers (struct target_ops *ops,
                              struct regcache *regcache, int regnum)
                              struct regcache *regcache, int regnum)
{
{
  /* Unless we already know that PTRACE_GETREGS does not work, try it.  */
  /* Unless we already know that PTRACE_GETREGS does not work, try it.  */
  if (have_ptrace_regsets)
  if (have_ptrace_regsets)
    mips64_linux_regsets_store_registers (regcache, regnum);
    mips64_linux_regsets_store_registers (regcache, regnum);
 
 
  /* If we know, or just found out, that PTRACE_GETREGS does not work, fall
  /* If we know, or just found out, that PTRACE_GETREGS does not work, fall
     back to PTRACE_PEEKUSER.  */
     back to PTRACE_PEEKUSER.  */
  if (!have_ptrace_regsets)
  if (!have_ptrace_regsets)
    super_store_registers (ops, regcache, regnum);
    super_store_registers (ops, regcache, regnum);
}
}
 
 
/* Return the address in the core dump or inferior of register
/* Return the address in the core dump or inferior of register
   REGNO.  */
   REGNO.  */
 
 
static CORE_ADDR
static CORE_ADDR
mips_linux_register_u_offset (struct gdbarch *gdbarch, int regno, int store_p)
mips_linux_register_u_offset (struct gdbarch *gdbarch, int regno, int store_p)
{
{
  if (mips_abi_regsize (gdbarch) == 8)
  if (mips_abi_regsize (gdbarch) == 8)
    return mips64_linux_register_addr (gdbarch, regno, store_p);
    return mips64_linux_register_addr (gdbarch, regno, store_p);
  else
  else
    return mips_linux_register_addr (gdbarch, regno, store_p);
    return mips_linux_register_addr (gdbarch, regno, store_p);
}
}
 
 
static const struct target_desc *
static const struct target_desc *
mips_linux_read_description (struct target_ops *ops)
mips_linux_read_description (struct target_ops *ops)
{
{
  /* Report that target registers are a size we know for sure
  /* Report that target registers are a size we know for sure
     that we can get from ptrace.  */
     that we can get from ptrace.  */
  if (_MIPS_SIM == _ABIO32)
  if (_MIPS_SIM == _ABIO32)
    return tdesc_mips_linux;
    return tdesc_mips_linux;
  else
  else
    return tdesc_mips64_linux;
    return tdesc_mips64_linux;
}
}
 
 
#ifndef PTRACE_GET_WATCH_REGS
#ifndef PTRACE_GET_WATCH_REGS
#  define PTRACE_GET_WATCH_REGS 0xd0
#  define PTRACE_GET_WATCH_REGS 0xd0
#endif
#endif
 
 
#ifndef PTRACE_SET_WATCH_REGS
#ifndef PTRACE_SET_WATCH_REGS
#  define PTRACE_SET_WATCH_REGS 0xd1
#  define PTRACE_SET_WATCH_REGS 0xd1
#endif
#endif
 
 
#define W_BIT 0
#define W_BIT 0
#define R_BIT 1
#define R_BIT 1
#define I_BIT 2
#define I_BIT 2
 
 
#define W_MASK (1 << W_BIT)
#define W_MASK (1 << W_BIT)
#define R_MASK (1 << R_BIT)
#define R_MASK (1 << R_BIT)
#define I_MASK (1 << I_BIT)
#define I_MASK (1 << I_BIT)
 
 
#define IRW_MASK (I_MASK | R_MASK | W_MASK)
#define IRW_MASK (I_MASK | R_MASK | W_MASK)
 
 
enum pt_watch_style {
enum pt_watch_style {
  pt_watch_style_mips32,
  pt_watch_style_mips32,
  pt_watch_style_mips64
  pt_watch_style_mips64
};
};
 
 
#define MAX_DEBUG_REGISTER 8
#define MAX_DEBUG_REGISTER 8
 
 
/* A value of zero in a watchlo indicates that it is available. */
/* A value of zero in a watchlo indicates that it is available. */
 
 
struct mips32_watch_regs
struct mips32_watch_regs
{
{
  uint32_t watchlo[MAX_DEBUG_REGISTER];
  uint32_t watchlo[MAX_DEBUG_REGISTER];
  /* Lower 16 bits of watchhi. */
  /* Lower 16 bits of watchhi. */
  uint16_t watchhi[MAX_DEBUG_REGISTER];
  uint16_t watchhi[MAX_DEBUG_REGISTER];
  /* Valid mask and I R W bits.
  /* Valid mask and I R W bits.
   * bit 0 -- 1 if W bit is usable.
   * bit 0 -- 1 if W bit is usable.
   * bit 1 -- 1 if R bit is usable.
   * bit 1 -- 1 if R bit is usable.
   * bit 2 -- 1 if I bit is usable.
   * bit 2 -- 1 if I bit is usable.
   * bits 3 - 11 -- Valid watchhi mask bits.
   * bits 3 - 11 -- Valid watchhi mask bits.
   */
   */
  uint16_t watch_masks[MAX_DEBUG_REGISTER];
  uint16_t watch_masks[MAX_DEBUG_REGISTER];
  /* The number of valid watch register pairs.  */
  /* The number of valid watch register pairs.  */
  uint32_t num_valid;
  uint32_t num_valid;
  /* There is confusion across gcc versions about structure alignment,
  /* There is confusion across gcc versions about structure alignment,
     so we force 8 byte alignment for these structures so they match
     so we force 8 byte alignment for these structures so they match
     the kernel even if it was build with a different gcc version.  */
     the kernel even if it was build with a different gcc version.  */
} __attribute__ ((aligned (8)));
} __attribute__ ((aligned (8)));
 
 
struct mips64_watch_regs
struct mips64_watch_regs
{
{
  uint64_t watchlo[MAX_DEBUG_REGISTER];
  uint64_t watchlo[MAX_DEBUG_REGISTER];
  uint16_t watchhi[MAX_DEBUG_REGISTER];
  uint16_t watchhi[MAX_DEBUG_REGISTER];
  uint16_t watch_masks[MAX_DEBUG_REGISTER];
  uint16_t watch_masks[MAX_DEBUG_REGISTER];
  uint32_t num_valid;
  uint32_t num_valid;
} __attribute__ ((aligned (8)));
} __attribute__ ((aligned (8)));
 
 
struct pt_watch_regs
struct pt_watch_regs
{
{
  enum pt_watch_style style;
  enum pt_watch_style style;
  union
  union
  {
  {
    struct mips32_watch_regs mips32;
    struct mips32_watch_regs mips32;
    struct mips64_watch_regs mips64;
    struct mips64_watch_regs mips64;
  };
  };
};
};
 
 
/* -1 if the kernel and/or CPU do not support watch registers.
/* -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
    1 if watch_readback is valid and we can read style, num_valid
      and the masks.
      and the masks.
    0 if we need to read the watch_readback.  */
    0 if we need to read the watch_readback.  */
 
 
static int watch_readback_valid;
static int watch_readback_valid;
 
 
/* Cached watch register read values.  */
/* Cached watch register read values.  */
 
 
static struct pt_watch_regs watch_readback;
static struct pt_watch_regs watch_readback;
 
 
/* We keep list of all watchpoints we should install and calculate the
/* We keep list of all watchpoints we should install and calculate the
   watch register values each time the list changes.  This allows for
   watch register values each time the list changes.  This allows for
   easy sharing of watch registers for more than one watchpoint.  */
   easy sharing of watch registers for more than one watchpoint.  */
 
 
struct mips_watchpoint
struct mips_watchpoint
{
{
  CORE_ADDR addr;
  CORE_ADDR addr;
  int len;
  int len;
  int type;
  int type;
  struct mips_watchpoint *next;
  struct mips_watchpoint *next;
};
};
 
 
static struct mips_watchpoint *current_watches;
static struct mips_watchpoint *current_watches;
 
 
/*  The current set of watch register values for writing the
/*  The current set of watch register values for writing the
    registers.  */
    registers.  */
 
 
static struct pt_watch_regs watch_mirror;
static struct pt_watch_regs watch_mirror;
 
 
/* Assuming usable watch registers, return the irw_mask.  */
/* Assuming usable watch registers, return the irw_mask.  */
 
 
static uint32_t
static uint32_t
get_irw_mask (struct pt_watch_regs *regs, int set)
get_irw_mask (struct pt_watch_regs *regs, int set)
{
{
  switch (regs->style)
  switch (regs->style)
    {
    {
    case pt_watch_style_mips32:
    case pt_watch_style_mips32:
      return regs->mips32.watch_masks[set] & IRW_MASK;
      return regs->mips32.watch_masks[set] & IRW_MASK;
    case pt_watch_style_mips64:
    case pt_watch_style_mips64:
      return regs->mips64.watch_masks[set] & IRW_MASK;
      return regs->mips64.watch_masks[set] & IRW_MASK;
    default:
    default:
      internal_error (__FILE__, __LINE__,
      internal_error (__FILE__, __LINE__,
                      _("Unrecognized watch register style"));
                      _("Unrecognized watch register style"));
    }
    }
}
}
 
 
/* Assuming usable watch registers, return the reg_mask.  */
/* Assuming usable watch registers, return the reg_mask.  */
 
 
static uint32_t
static uint32_t
get_reg_mask (struct pt_watch_regs *regs, int set)
get_reg_mask (struct pt_watch_regs *regs, int set)
{
{
  switch (regs->style)
  switch (regs->style)
    {
    {
    case pt_watch_style_mips32:
    case pt_watch_style_mips32:
      return regs->mips32.watch_masks[set] & ~IRW_MASK;
      return regs->mips32.watch_masks[set] & ~IRW_MASK;
    case pt_watch_style_mips64:
    case pt_watch_style_mips64:
      return regs->mips64.watch_masks[set] & ~IRW_MASK;
      return regs->mips64.watch_masks[set] & ~IRW_MASK;
    default:
    default:
      internal_error (__FILE__, __LINE__,
      internal_error (__FILE__, __LINE__,
                      _("Unrecognized watch register style"));
                      _("Unrecognized watch register style"));
    }
    }
}
}
 
 
/* Assuming usable watch registers, return the num_valid.  */
/* Assuming usable watch registers, return the num_valid.  */
 
 
static uint32_t
static uint32_t
get_num_valid (struct pt_watch_regs *regs)
get_num_valid (struct pt_watch_regs *regs)
{
{
  switch (regs->style)
  switch (regs->style)
    {
    {
    case pt_watch_style_mips32:
    case pt_watch_style_mips32:
      return regs->mips32.num_valid;
      return regs->mips32.num_valid;
    case pt_watch_style_mips64:
    case pt_watch_style_mips64:
      return regs->mips64.num_valid;
      return regs->mips64.num_valid;
    default:
    default:
      internal_error (__FILE__, __LINE__,
      internal_error (__FILE__, __LINE__,
                      _("Unrecognized watch register style"));
                      _("Unrecognized watch register style"));
    }
    }
}
}
 
 
/* Assuming usable watch registers, return the watchlo.  */
/* Assuming usable watch registers, return the watchlo.  */
 
 
static CORE_ADDR
static CORE_ADDR
get_watchlo (struct pt_watch_regs *regs, int set)
get_watchlo (struct pt_watch_regs *regs, int set)
{
{
  switch (regs->style)
  switch (regs->style)
    {
    {
    case pt_watch_style_mips32:
    case pt_watch_style_mips32:
      return regs->mips32.watchlo[set];
      return regs->mips32.watchlo[set];
    case pt_watch_style_mips64:
    case pt_watch_style_mips64:
      return regs->mips64.watchlo[set];
      return regs->mips64.watchlo[set];
    default:
    default:
      internal_error (__FILE__, __LINE__,
      internal_error (__FILE__, __LINE__,
                      _("Unrecognized watch register style"));
                      _("Unrecognized watch register style"));
    }
    }
}
}
 
 
/* Assuming usable watch registers, set a watchlo value.  */
/* Assuming usable watch registers, set a watchlo value.  */
 
 
static void
static void
set_watchlo (struct pt_watch_regs *regs, int set, CORE_ADDR value)
set_watchlo (struct pt_watch_regs *regs, int set, CORE_ADDR value)
{
{
  switch (regs->style)
  switch (regs->style)
    {
    {
    case pt_watch_style_mips32:
    case pt_watch_style_mips32:
      /*  The cast will never throw away bits as 64 bit addresses can
      /*  The cast will never throw away bits as 64 bit addresses can
          never be used on a 32 bit kernel.  */
          never be used on a 32 bit kernel.  */
      regs->mips32.watchlo[set] = (uint32_t)value;
      regs->mips32.watchlo[set] = (uint32_t)value;
      break;
      break;
    case pt_watch_style_mips64:
    case pt_watch_style_mips64:
      regs->mips64.watchlo[set] = value;
      regs->mips64.watchlo[set] = value;
      break;
      break;
    default:
    default:
      internal_error (__FILE__, __LINE__,
      internal_error (__FILE__, __LINE__,
                      _("Unrecognized watch register style"));
                      _("Unrecognized watch register style"));
    }
    }
}
}
 
 
/* Assuming usable watch registers, return the watchhi.  */
/* Assuming usable watch registers, return the watchhi.  */
 
 
static uint32_t
static uint32_t
get_watchhi (struct pt_watch_regs *regs, int n)
get_watchhi (struct pt_watch_regs *regs, int n)
{
{
  switch (regs->style)
  switch (regs->style)
    {
    {
    case pt_watch_style_mips32:
    case pt_watch_style_mips32:
      return regs->mips32.watchhi[n];
      return regs->mips32.watchhi[n];
    case pt_watch_style_mips64:
    case pt_watch_style_mips64:
      return regs->mips64.watchhi[n];
      return regs->mips64.watchhi[n];
    default:
    default:
      internal_error (__FILE__, __LINE__,
      internal_error (__FILE__, __LINE__,
                      _("Unrecognized watch register style"));
                      _("Unrecognized watch register style"));
    }
    }
}
}
 
 
/* Assuming usable watch registers, set a watchhi value.  */
/* Assuming usable watch registers, set a watchhi value.  */
 
 
static void
static void
set_watchhi (struct pt_watch_regs *regs, int n, uint16_t value)
set_watchhi (struct pt_watch_regs *regs, int n, uint16_t value)
{
{
  switch (regs->style)
  switch (regs->style)
    {
    {
    case pt_watch_style_mips32:
    case pt_watch_style_mips32:
      regs->mips32.watchhi[n] = value;
      regs->mips32.watchhi[n] = value;
      break;
      break;
    case pt_watch_style_mips64:
    case pt_watch_style_mips64:
      regs->mips64.watchhi[n] = value;
      regs->mips64.watchhi[n] = value;
      break;
      break;
    default:
    default:
      internal_error (__FILE__, __LINE__,
      internal_error (__FILE__, __LINE__,
                      _("Unrecognized watch register style"));
                      _("Unrecognized watch register style"));
    }
    }
}
}
 
 
static void
static void
mips_show_dr (const char *func, CORE_ADDR addr,
mips_show_dr (const char *func, CORE_ADDR addr,
              int len, enum target_hw_bp_type type)
              int len, enum target_hw_bp_type type)
{
{
  int i;
  int i;
 
 
  puts_unfiltered (func);
  puts_unfiltered (func);
  if (addr || len)
  if (addr || len)
    printf_unfiltered (" (addr=%s, len=%d, type=%s)",
    printf_unfiltered (" (addr=%s, len=%d, type=%s)",
                       paddress (target_gdbarch, addr), len,
                       paddress (target_gdbarch, addr), len,
                       type == hw_write ? "data-write"
                       type == hw_write ? "data-write"
                       : (type == hw_read ? "data-read"
                       : (type == hw_read ? "data-read"
                          : (type == hw_access ? "data-read/write"
                          : (type == hw_access ? "data-read/write"
                             : (type == hw_execute ? "instruction-execute"
                             : (type == hw_execute ? "instruction-execute"
                                : "??unknown??"))));
                                : "??unknown??"))));
  puts_unfiltered (":\n");
  puts_unfiltered (":\n");
 
 
  for (i = 0; i < MAX_DEBUG_REGISTER; i++)
  for (i = 0; i < MAX_DEBUG_REGISTER; i++)
    printf_unfiltered ("\tDR%d: lo=%s, hi=%s\n", i,
    printf_unfiltered ("\tDR%d: lo=%s, hi=%s\n", i,
                       paddress (target_gdbarch,
                       paddress (target_gdbarch,
                                 get_watchlo (&watch_mirror, i)),
                                 get_watchlo (&watch_mirror, i)),
                       paddress (target_gdbarch,
                       paddress (target_gdbarch,
                                 get_watchhi (&watch_mirror, i)));
                                 get_watchhi (&watch_mirror, i)));
}
}
 
 
/* Return 1 if watch registers are usable.  Cached information is used
/* Return 1 if watch registers are usable.  Cached information is used
   unless force is true.  */
   unless force is true.  */
 
 
static int
static int
mips_linux_read_watch_registers (int force)
mips_linux_read_watch_registers (int force)
{
{
  int tid;
  int tid;
 
 
  if (force || watch_readback_valid == 0)
  if (force || watch_readback_valid == 0)
    {
    {
      tid = ptid_get_lwp (inferior_ptid);
      tid = ptid_get_lwp (inferior_ptid);
      if (ptrace (PTRACE_GET_WATCH_REGS, tid, &watch_readback) == -1)
      if (ptrace (PTRACE_GET_WATCH_REGS, tid, &watch_readback) == -1)
        {
        {
          watch_readback_valid = -1;
          watch_readback_valid = -1;
          return 0;
          return 0;
        }
        }
      switch (watch_readback.style)
      switch (watch_readback.style)
        {
        {
        case pt_watch_style_mips32:
        case pt_watch_style_mips32:
          if (watch_readback.mips32.num_valid == 0)
          if (watch_readback.mips32.num_valid == 0)
            {
            {
              watch_readback_valid = -1;
              watch_readback_valid = -1;
              return 0;
              return 0;
            }
            }
          break;
          break;
        case pt_watch_style_mips64:
        case pt_watch_style_mips64:
          if (watch_readback.mips64.num_valid == 0)
          if (watch_readback.mips64.num_valid == 0)
            {
            {
              watch_readback_valid = -1;
              watch_readback_valid = -1;
              return 0;
              return 0;
            }
            }
          break;
          break;
        default:
        default:
          watch_readback_valid = -1;
          watch_readback_valid = -1;
          return 0;
          return 0;
        }
        }
      /* Watch registers appear to be usable.  */
      /* Watch registers appear to be usable.  */
      watch_readback_valid = 1;
      watch_readback_valid = 1;
    }
    }
  return (watch_readback_valid == 1) ? 1 : 0;
  return (watch_readback_valid == 1) ? 1 : 0;
}
}
 
 
/* Convert GDB's type to an IRW mask.  */
/* Convert GDB's type to an IRW mask.  */
 
 
static unsigned
static unsigned
type_to_irw (int type)
type_to_irw (int type)
{
{
  switch (type)
  switch (type)
    {
    {
    case hw_write:
    case hw_write:
      return W_MASK;
      return W_MASK;
    case hw_read:
    case hw_read:
      return R_MASK;
      return R_MASK;
    case hw_access:
    case hw_access:
      return (W_MASK | R_MASK);
      return (W_MASK | R_MASK);
    default:
    default:
      return 0;
      return 0;
    }
    }
}
}
 
 
/* Target to_can_use_hw_breakpoint implementation.  Return 1 if we can
/* Target to_can_use_hw_breakpoint implementation.  Return 1 if we can
   handle the specified watch type.  */
   handle the specified watch type.  */
 
 
static int
static int
mips_linux_can_use_hw_breakpoint (int type, int cnt, int ot)
mips_linux_can_use_hw_breakpoint (int type, int cnt, int ot)
{
{
  int i;
  int i;
  uint32_t wanted_mask, irw_mask;
  uint32_t wanted_mask, irw_mask;
 
 
  if (!mips_linux_read_watch_registers (0))
  if (!mips_linux_read_watch_registers (0))
    return 0;
    return 0;
 
 
   switch (type)
   switch (type)
    {
    {
    case bp_hardware_watchpoint:
    case bp_hardware_watchpoint:
      wanted_mask = W_MASK;
      wanted_mask = W_MASK;
      break;
      break;
    case bp_read_watchpoint:
    case bp_read_watchpoint:
      wanted_mask = R_MASK;
      wanted_mask = R_MASK;
      break;
      break;
    case bp_access_watchpoint:
    case bp_access_watchpoint:
      wanted_mask = R_MASK | W_MASK;
      wanted_mask = R_MASK | W_MASK;
      break;
      break;
    default:
    default:
      return 0;
      return 0;
    }
    }
 
 
  for (i = 0; i < get_num_valid (&watch_readback) && cnt; i++)
  for (i = 0; i < get_num_valid (&watch_readback) && cnt; i++)
    {
    {
      irw_mask = get_irw_mask (&watch_readback, i);
      irw_mask = get_irw_mask (&watch_readback, i);
      if ((irw_mask & wanted_mask) == wanted_mask)
      if ((irw_mask & wanted_mask) == wanted_mask)
        cnt--;
        cnt--;
    }
    }
  return (cnt == 0) ? 1 : 0;
  return (cnt == 0) ? 1 : 0;
}
}
 
 
/* Target to_stopped_by_watchpoint implementation.  Return 1 if
/* Target to_stopped_by_watchpoint implementation.  Return 1 if
   stopped by watchpoint.  The watchhi R and W bits indicate the watch
   stopped by watchpoint.  The watchhi R and W bits indicate the watch
   register triggered. */
   register triggered. */
 
 
static int
static int
mips_linux_stopped_by_watchpoint (void)
mips_linux_stopped_by_watchpoint (void)
{
{
  int n;
  int n;
  int num_valid;
  int num_valid;
 
 
  if (!mips_linux_read_watch_registers (1))
  if (!mips_linux_read_watch_registers (1))
    return 0;
    return 0;
 
 
  num_valid = get_num_valid (&watch_readback);
  num_valid = get_num_valid (&watch_readback);
 
 
  for (n = 0; n < MAX_DEBUG_REGISTER && n < num_valid; n++)
  for (n = 0; n < MAX_DEBUG_REGISTER && n < num_valid; n++)
    if (get_watchhi (&watch_readback, n) & (R_MASK | W_MASK))
    if (get_watchhi (&watch_readback, n) & (R_MASK | W_MASK))
      return 1;
      return 1;
 
 
  return 0;
  return 0;
}
}
 
 
/* Target to_stopped_data_address implementation.  Set the address
/* Target to_stopped_data_address implementation.  Set the address
   where the watch triggered (if known).  Return 1 if the address was
   where the watch triggered (if known).  Return 1 if the address was
   known.  */
   known.  */
 
 
static int
static int
mips_linux_stopped_data_address (struct target_ops *t, CORE_ADDR *paddr)
mips_linux_stopped_data_address (struct target_ops *t, CORE_ADDR *paddr)
{
{
  /* On mips we don't know the low order 3 bits of the data address,
  /* On mips we don't know the low order 3 bits of the data address,
     so we must return false.  */
     so we must return false.  */
  return 0;
  return 0;
}
}
 
 
/* Set any low order bits in mask that are not set.  */
/* Set any low order bits in mask that are not set.  */
 
 
static CORE_ADDR
static CORE_ADDR
fill_mask (CORE_ADDR mask)
fill_mask (CORE_ADDR mask)
{
{
  CORE_ADDR f = 1;
  CORE_ADDR f = 1;
  while (f && f < mask)
  while (f && f < mask)
    {
    {
      mask |= f;
      mask |= f;
      f <<= 1;
      f <<= 1;
    }
    }
  return mask;
  return mask;
}
}
 
 
/* Try to add a single watch to the specified registers.  Return 1 on
/* Try to add a single watch to the specified registers.  Return 1 on
   success, 0 on failure.  */
   success, 0 on failure.  */
 
 
static int
static int
try_one_watch (struct pt_watch_regs *regs, CORE_ADDR addr,
try_one_watch (struct pt_watch_regs *regs, CORE_ADDR addr,
               int len, unsigned irw)
               int len, unsigned irw)
{
{
  CORE_ADDR base_addr, last_byte, break_addr, segment_len;
  CORE_ADDR base_addr, last_byte, break_addr, segment_len;
  CORE_ADDR mask_bits, t_low, t_low_end;
  CORE_ADDR mask_bits, t_low, t_low_end;
  uint16_t t_hi;
  uint16_t t_hi;
  int i, free_watches;
  int i, free_watches;
  struct pt_watch_regs regs_copy;
  struct pt_watch_regs regs_copy;
 
 
  if (len <= 0)
  if (len <= 0)
    return 0;
    return 0;
 
 
  last_byte = addr + len - 1;
  last_byte = addr + len - 1;
  mask_bits = fill_mask (addr ^ last_byte) | IRW_MASK;
  mask_bits = fill_mask (addr ^ last_byte) | IRW_MASK;
  base_addr = addr & ~mask_bits;
  base_addr = addr & ~mask_bits;
 
 
  /* Check to see if it is covered by current registers.  */
  /* Check to see if it is covered by current registers.  */
  for (i = 0; i < get_num_valid (regs); i++)
  for (i = 0; i < get_num_valid (regs); i++)
    {
    {
      t_low = get_watchlo (regs, i);
      t_low = get_watchlo (regs, i);
      if (t_low != 0 && irw == ((unsigned)t_low & irw))
      if (t_low != 0 && irw == ((unsigned)t_low & irw))
        {
        {
          t_hi = get_watchhi (regs, i) | IRW_MASK;
          t_hi = get_watchhi (regs, i) | IRW_MASK;
          t_low &= ~(CORE_ADDR)t_hi;
          t_low &= ~(CORE_ADDR)t_hi;
          if (addr >= t_low && last_byte <= (t_low + t_hi))
          if (addr >= t_low && last_byte <= (t_low + t_hi))
            return 1;
            return 1;
        }
        }
    }
    }
  /* Try to find an empty register.  */
  /* Try to find an empty register.  */
  free_watches = 0;
  free_watches = 0;
  for (i = 0; i < get_num_valid (regs); i++)
  for (i = 0; i < get_num_valid (regs); i++)
    {
    {
      t_low = get_watchlo (regs, i);
      t_low = get_watchlo (regs, i);
      if (t_low == 0 && irw == (get_irw_mask (regs, i) & irw))
      if (t_low == 0 && irw == (get_irw_mask (regs, i) & irw))
        {
        {
          if (mask_bits <= (get_reg_mask (regs, i) | IRW_MASK))
          if (mask_bits <= (get_reg_mask (regs, i) | IRW_MASK))
            {
            {
              /* It fits, we'll take it.  */
              /* It fits, we'll take it.  */
              set_watchlo (regs, i, base_addr | irw);
              set_watchlo (regs, i, base_addr | irw);
              set_watchhi (regs, i, mask_bits & ~IRW_MASK);
              set_watchhi (regs, i, mask_bits & ~IRW_MASK);
              return 1;
              return 1;
            }
            }
          else
          else
            {
            {
              /* It doesn't fit, but has the proper IRW capabilities.  */
              /* It doesn't fit, but has the proper IRW capabilities.  */
              free_watches++;
              free_watches++;
            }
            }
        }
        }
    }
    }
  if (free_watches > 1)
  if (free_watches > 1)
    {
    {
      /* Try to split it across several registers.  */
      /* Try to split it across several registers.  */
      regs_copy = *regs;
      regs_copy = *regs;
      for (i = 0; i < get_num_valid (&regs_copy); i++)
      for (i = 0; i < get_num_valid (&regs_copy); i++)
        {
        {
          t_low = get_watchlo (&regs_copy, i);
          t_low = get_watchlo (&regs_copy, i);
          t_hi = get_reg_mask (&regs_copy, i) | IRW_MASK;
          t_hi = get_reg_mask (&regs_copy, i) | IRW_MASK;
          if (t_low == 0 && irw == (t_hi & irw))
          if (t_low == 0 && irw == (t_hi & irw))
            {
            {
              t_low = addr & ~(CORE_ADDR)t_hi;
              t_low = addr & ~(CORE_ADDR)t_hi;
              break_addr = t_low + t_hi + 1;
              break_addr = t_low + t_hi + 1;
              if (break_addr >= addr + len)
              if (break_addr >= addr + len)
                segment_len = len;
                segment_len = len;
              else
              else
                segment_len = break_addr - addr;
                segment_len = break_addr - addr;
              mask_bits = fill_mask (addr ^ (addr + segment_len - 1));
              mask_bits = fill_mask (addr ^ (addr + segment_len - 1));
              set_watchlo (&regs_copy, i, (addr & ~mask_bits) | irw);
              set_watchlo (&regs_copy, i, (addr & ~mask_bits) | irw);
              set_watchhi (&regs_copy, i, mask_bits & ~IRW_MASK);
              set_watchhi (&regs_copy, i, mask_bits & ~IRW_MASK);
              if (break_addr >= addr + len)
              if (break_addr >= addr + len)
                {
                {
                  *regs = regs_copy;
                  *regs = regs_copy;
                  return 1;
                  return 1;
                }
                }
              len = addr + len - break_addr;
              len = addr + len - break_addr;
              addr = break_addr;
              addr = break_addr;
            }
            }
        }
        }
    }
    }
  /* It didn't fit anywhere, we failed.  */
  /* It didn't fit anywhere, we failed.  */
  return 0;
  return 0;
}
}
 
 
/* Target to_region_ok_for_hw_watchpoint implementation.  Return 1 if
/* Target to_region_ok_for_hw_watchpoint implementation.  Return 1 if
   the specified region can be covered by the watch registers.  */
   the specified region can be covered by the watch registers.  */
 
 
static int
static int
mips_linux_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
mips_linux_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
{
{
  struct pt_watch_regs dummy_regs;
  struct pt_watch_regs dummy_regs;
  int i;
  int i;
 
 
  if (!mips_linux_read_watch_registers (0))
  if (!mips_linux_read_watch_registers (0))
    return 0;
    return 0;
 
 
  dummy_regs = watch_readback;
  dummy_regs = watch_readback;
  /* Clear them out.  */
  /* Clear them out.  */
  for (i = 0; i < get_num_valid (&dummy_regs); i++)
  for (i = 0; i < get_num_valid (&dummy_regs); i++)
    set_watchlo (&dummy_regs, i, 0);
    set_watchlo (&dummy_regs, i, 0);
  return try_one_watch (&dummy_regs, addr, len, 0);
  return try_one_watch (&dummy_regs, addr, len, 0);
}
}
 
 
 
 
/* Write the mirrored watch register values for each thread.  */
/* Write the mirrored watch register values for each thread.  */
 
 
static int
static int
write_watchpoint_regs (void)
write_watchpoint_regs (void)
{
{
  struct lwp_info *lp;
  struct lwp_info *lp;
  ptid_t ptid;
  ptid_t ptid;
  int tid;
  int tid;
 
 
  ALL_LWPS (lp, ptid)
  ALL_LWPS (lp, ptid)
    {
    {
      tid = ptid_get_lwp (ptid);
      tid = ptid_get_lwp (ptid);
      if (ptrace (PTRACE_SET_WATCH_REGS, tid, &watch_mirror) == -1)
      if (ptrace (PTRACE_SET_WATCH_REGS, tid, &watch_mirror) == -1)
        perror_with_name (_("Couldn't write debug register"));
        perror_with_name (_("Couldn't write debug register"));
    }
    }
  return 0;
  return 0;
}
}
 
 
/* linux_nat new_thread implementation.  Write the mirrored watch
/* linux_nat new_thread implementation.  Write the mirrored watch
 register values for the new thread.  */
 register values for the new thread.  */
 
 
static void
static void
mips_linux_new_thread (ptid_t ptid)
mips_linux_new_thread (ptid_t ptid)
{
{
  int tid;
  int tid;
 
 
  if (!mips_linux_read_watch_registers (0))
  if (!mips_linux_read_watch_registers (0))
    return;
    return;
 
 
  tid = ptid_get_lwp (ptid);
  tid = ptid_get_lwp (ptid);
  if (ptrace (PTRACE_SET_WATCH_REGS, tid, &watch_mirror) == -1)
  if (ptrace (PTRACE_SET_WATCH_REGS, tid, &watch_mirror) == -1)
    perror_with_name (_("Couldn't write debug register"));
    perror_with_name (_("Couldn't write debug register"));
}
}
 
 
/* Fill in the watch registers with the currently cached watches.  */
/* Fill in the watch registers with the currently cached watches.  */
 
 
static void
static void
populate_regs_from_watches (struct pt_watch_regs *regs)
populate_regs_from_watches (struct pt_watch_regs *regs)
{
{
  struct mips_watchpoint *w;
  struct mips_watchpoint *w;
  int i;
  int i;
 
 
  /* Clear them out.  */
  /* Clear them out.  */
  for (i = 0; i < get_num_valid (regs); i++)
  for (i = 0; i < get_num_valid (regs); i++)
    {
    {
      set_watchlo (regs, i, 0);
      set_watchlo (regs, i, 0);
      set_watchhi (regs, i, 0);
      set_watchhi (regs, i, 0);
    }
    }
 
 
  w = current_watches;
  w = current_watches;
  while (w)
  while (w)
    {
    {
      i = try_one_watch (regs, w->addr, w->len, type_to_irw (w->type));
      i = try_one_watch (regs, w->addr, w->len, type_to_irw (w->type));
      /* They must all fit, because we previously calculated that they
      /* They must all fit, because we previously calculated that they
         would.  */
         would.  */
      gdb_assert (i);
      gdb_assert (i);
      w = w->next;
      w = w->next;
    }
    }
}
}
 
 
/* Target to_insert_watchpoint implementation.  Try to insert a new
/* Target to_insert_watchpoint implementation.  Try to insert a new
   watch.  Return zero on success.  */
   watch.  Return zero on success.  */
 
 
static int
static int
mips_linux_insert_watchpoint (CORE_ADDR addr, int len, int type)
mips_linux_insert_watchpoint (CORE_ADDR addr, int len, int type)
{
{
  struct pt_watch_regs regs;
  struct pt_watch_regs regs;
  struct mips_watchpoint *new_watch;
  struct mips_watchpoint *new_watch;
  struct mips_watchpoint **pw;
  struct mips_watchpoint **pw;
 
 
  int i;
  int i;
  int retval;
  int retval;
 
 
  if (!mips_linux_read_watch_registers (0))
  if (!mips_linux_read_watch_registers (0))
    return -1;
    return -1;
 
 
  if (len <= 0)
  if (len <= 0)
    return -1;
    return -1;
 
 
  regs = watch_readback;
  regs = watch_readback;
  /* Add the current watches.  */
  /* Add the current watches.  */
  populate_regs_from_watches (&regs);
  populate_regs_from_watches (&regs);
 
 
  /* Now try to add the new watch.  */
  /* Now try to add the new watch.  */
  if (!try_one_watch (&regs, addr, len, type_to_irw (type)))
  if (!try_one_watch (&regs, addr, len, type_to_irw (type)))
    return -1;
    return -1;
 
 
  /* It fit.  Stick it on the end of the list.  */
  /* It fit.  Stick it on the end of the list.  */
  new_watch = (struct mips_watchpoint *)
  new_watch = (struct mips_watchpoint *)
    xmalloc (sizeof (struct mips_watchpoint));
    xmalloc (sizeof (struct mips_watchpoint));
  new_watch->addr = addr;
  new_watch->addr = addr;
  new_watch->len = len;
  new_watch->len = len;
  new_watch->type = type;
  new_watch->type = type;
  new_watch->next = NULL;
  new_watch->next = NULL;
 
 
  pw = &current_watches;
  pw = &current_watches;
  while (*pw != NULL)
  while (*pw != NULL)
    pw = &(*pw)->next;
    pw = &(*pw)->next;
  *pw = new_watch;
  *pw = new_watch;
 
 
  watch_mirror = regs;
  watch_mirror = regs;
  retval = write_watchpoint_regs ();
  retval = write_watchpoint_regs ();
 
 
  if (maint_show_dr)
  if (maint_show_dr)
    mips_show_dr ("insert_watchpoint", addr, len, type);
    mips_show_dr ("insert_watchpoint", addr, len, type);
 
 
  return retval;
  return retval;
}
}
 
 
/* Target to_remove_watchpoint implementation.  Try to remove a watch.
/* Target to_remove_watchpoint implementation.  Try to remove a watch.
   Return zero on success.  */
   Return zero on success.  */
 
 
static int
static int
mips_linux_remove_watchpoint (CORE_ADDR addr, int len, int type)
mips_linux_remove_watchpoint (CORE_ADDR addr, int len, int type)
{
{
  int retval;
  int retval;
  int deleted_one;
  int deleted_one;
 
 
  struct mips_watchpoint **pw;
  struct mips_watchpoint **pw;
  struct mips_watchpoint *w;
  struct mips_watchpoint *w;
 
 
  /* Search for a known watch that matches.  Then unlink and free
  /* Search for a known watch that matches.  Then unlink and free
     it.  */
     it.  */
  deleted_one = 0;
  deleted_one = 0;
  pw = &current_watches;
  pw = &current_watches;
  while ((w = *pw))
  while ((w = *pw))
    {
    {
      if (w->addr == addr && w->len == len && w->type == type)
      if (w->addr == addr && w->len == len && w->type == type)
        {
        {
          *pw = w->next;
          *pw = w->next;
          xfree (w);
          xfree (w);
          deleted_one = 1;
          deleted_one = 1;
          break;
          break;
        }
        }
      pw = &(w->next);
      pw = &(w->next);
    }
    }
 
 
  if (!deleted_one)
  if (!deleted_one)
    return -1;  /* We don't know about it, fail doing nothing.  */
    return -1;  /* We don't know about it, fail doing nothing.  */
 
 
  /* At this point watch_readback is known to be valid because we
  /* At this point watch_readback is known to be valid because we
     could not have added the watch without reading it.  */
     could not have added the watch without reading it.  */
  gdb_assert (watch_readback_valid == 1);
  gdb_assert (watch_readback_valid == 1);
 
 
  watch_mirror = watch_readback;
  watch_mirror = watch_readback;
  populate_regs_from_watches (&watch_mirror);
  populate_regs_from_watches (&watch_mirror);
 
 
  retval = write_watchpoint_regs ();
  retval = write_watchpoint_regs ();
 
 
  if (maint_show_dr)
  if (maint_show_dr)
    mips_show_dr ("remove_watchpoint", addr, len, type);
    mips_show_dr ("remove_watchpoint", addr, len, type);
 
 
  return retval;
  return retval;
}
}
 
 
/* Target to_close implementation.  Free any watches and call the
/* Target to_close implementation.  Free any watches and call the
   super implementation.  */
   super implementation.  */
 
 
static void
static void
mips_linux_close (int quitting)
mips_linux_close (int quitting)
{
{
  struct mips_watchpoint *w;
  struct mips_watchpoint *w;
  struct mips_watchpoint *nw;
  struct mips_watchpoint *nw;
 
 
  /* Clean out the current_watches list.  */
  /* Clean out the current_watches list.  */
  w = current_watches;
  w = current_watches;
  while (w)
  while (w)
    {
    {
      nw = w->next;
      nw = w->next;
      xfree (w);
      xfree (w);
      w = nw;
      w = nw;
    }
    }
  current_watches = NULL;
  current_watches = NULL;
 
 
  if (super_close)
  if (super_close)
    super_close (quitting);
    super_close (quitting);
}
}
 
 
void _initialize_mips_linux_nat (void);
void _initialize_mips_linux_nat (void);
 
 
void
void
_initialize_mips_linux_nat (void)
_initialize_mips_linux_nat (void)
{
{
  struct target_ops *t;
  struct target_ops *t;
 
 
  add_setshow_boolean_cmd ("show-debug-regs", class_maintenance,
  add_setshow_boolean_cmd ("show-debug-regs", class_maintenance,
                           &maint_show_dr, _("\
                           &maint_show_dr, _("\
Set whether to show variables that mirror the mips debug registers."), _("\
Set whether to show variables that mirror the mips debug registers."), _("\
Show whether to show variables that mirror the mips debug registers."), _("\
Show whether to show variables that mirror the mips debug registers."), _("\
Use \"on\" to enable, \"off\" to disable.\n\
Use \"on\" to enable, \"off\" to disable.\n\
If enabled, the debug registers values are shown when GDB inserts\n\
If enabled, the debug registers values are shown when GDB inserts\n\
or removes a hardware breakpoint or watchpoint, and when the inferior\n\
or removes a hardware breakpoint or watchpoint, and when the inferior\n\
triggers a breakpoint or watchpoint."),
triggers a breakpoint or watchpoint."),
                           NULL,
                           NULL,
                           NULL,
                           NULL,
                           &maintenance_set_cmdlist,
                           &maintenance_set_cmdlist,
                           &maintenance_show_cmdlist);
                           &maintenance_show_cmdlist);
 
 
  t = linux_trad_target (mips_linux_register_u_offset);
  t = linux_trad_target (mips_linux_register_u_offset);
 
 
  super_close = t->to_close;
  super_close = t->to_close;
  t->to_close = mips_linux_close;
  t->to_close = mips_linux_close;
 
 
  super_fetch_registers = t->to_fetch_registers;
  super_fetch_registers = t->to_fetch_registers;
  super_store_registers = t->to_store_registers;
  super_store_registers = t->to_store_registers;
 
 
  t->to_fetch_registers = mips64_linux_fetch_registers;
  t->to_fetch_registers = mips64_linux_fetch_registers;
  t->to_store_registers = mips64_linux_store_registers;
  t->to_store_registers = mips64_linux_store_registers;
 
 
  t->to_can_use_hw_breakpoint = mips_linux_can_use_hw_breakpoint;
  t->to_can_use_hw_breakpoint = mips_linux_can_use_hw_breakpoint;
  t->to_remove_watchpoint = mips_linux_remove_watchpoint;
  t->to_remove_watchpoint = mips_linux_remove_watchpoint;
  t->to_insert_watchpoint = mips_linux_insert_watchpoint;
  t->to_insert_watchpoint = mips_linux_insert_watchpoint;
  t->to_stopped_by_watchpoint = mips_linux_stopped_by_watchpoint;
  t->to_stopped_by_watchpoint = mips_linux_stopped_by_watchpoint;
  t->to_stopped_data_address = mips_linux_stopped_data_address;
  t->to_stopped_data_address = mips_linux_stopped_data_address;
  t->to_region_ok_for_hw_watchpoint = mips_linux_region_ok_for_hw_watchpoint;
  t->to_region_ok_for_hw_watchpoint = mips_linux_region_ok_for_hw_watchpoint;
 
 
  t->to_read_description = mips_linux_read_description;
  t->to_read_description = mips_linux_read_description;
 
 
  linux_nat_add_target (t);
  linux_nat_add_target (t);
  linux_nat_set_new_thread (t, mips_linux_new_thread);
  linux_nat_set_new_thread (t, mips_linux_new_thread);
 
 
  /* Initialize the standard target descriptions.  */
  /* Initialize the standard target descriptions.  */
  initialize_tdesc_mips_linux ();
  initialize_tdesc_mips_linux ();
  initialize_tdesc_mips64_linux ();
  initialize_tdesc_mips64_linux ();
}
}
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.