Add amd64_x32_linux_record_tdep and amd64_x32_sys
[deliverable/binutils-gdb.git] / gdb / ppc-linux-nat.c
index 18ddee79fcf99ad13e9594903bed3fc0b0e827e9..d6820be99c5857815e7639be44a2ea034301c9d9 100644 (file)
@@ -1,7 +1,6 @@
 /* PPC GNU/Linux native support.
 
-   Copyright (C) 1988, 1989, 1991, 1992, 1994, 1996, 2000, 2001, 2002, 2003,
-   2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1988-2013 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -19,7 +18,7 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
-#include "gdb_string.h"
+#include <string.h>
 #include "observer.h"
 #include "frame.h"
 #include "inferior.h"
@@ -32,7 +31,6 @@
 
 #include <stdint.h>
 #include <sys/types.h>
-#include <sys/param.h>
 #include <signal.h>
 #include <sys/user.h>
 #include <sys/ioctl.h>
@@ -41,7 +39,7 @@
 #include <sys/procfs.h>
 #include <sys/ptrace.h>
 
-/* Prototypes for supply_gregset etc. */
+/* Prototypes for supply_gregset etc.  */
 #include "gregset.h"
 #include "ppc-tdep.h"
 #include "ppc-linux-tdep.h"
 #endif
 
 /* Similarly for the hardware watchpoint support.  These requests are used
-   when the BookE kernel interface is not available.  */
+   when the PowerPC HWDEBUG ptrace interface is not available.  */
 #ifndef PTRACE_GET_DEBUGREG
 #define PTRACE_GET_DEBUGREG    25
 #endif
 #define PTRACE_GETSIGINFO    0x4202
 #endif
 
-/* These requests are used when the BookE kernel interface is available.
-   It exposes the additional debug features of BookE processors, such as
-   ranged breakpoints and watchpoints and hardware-accelerated condition
-   evaluation.  */
+/* These requests are used when the PowerPC HWDEBUG ptrace interface is
+   available.  It exposes the debug facilities of PowerPC processors, as well
+   as additional features of BookE processors, such as ranged breakpoints and
+   watchpoints and hardware-accelerated condition evaluation.  */
 #ifndef PPC_PTRACE_GETHWDBGINFO
 
-/* Not having PPC_PTRACE_GETHWDBGINFO defined means that the new BookE
-   interface is not present in ptrace.h, so we'll have to pretty much include
-   it all here so that the code at least compiles on older systems.  */
+/* Not having PPC_PTRACE_GETHWDBGINFO defined means that the PowerPC HWDEBUG 
+   ptrace interface is not present in ptrace.h, so we'll have to pretty much
+   include it all here so that the code at least compiles on older systems.  */
 #define PPC_PTRACE_GETHWDBGINFO 0x89
 #define PPC_PTRACE_SETHWDEBUG   0x88
 #define PPC_PTRACE_DELHWDEBUG   0x87
 
 struct ppc_debug_info
 {
-        uint32_t version;               /* Only version 1 exists to date */
+        uint32_t version;               /* Only version 1 exists to date */
         uint32_t num_instruction_bps;
         uint32_t num_data_bps;
         uint32_t num_condition_regs;
         uint32_t data_bp_alignment;
-        uint32_t sizeof_condition;      /* size of the DVC register */
+        uint32_t sizeof_condition;      /* size of the DVC register */
         uint64_t features;
 };
 
@@ -179,7 +177,11 @@ struct ppc_hw_breakpoint
         (1<<((n)+PPC_BREAKPOINT_CONDITION_BE_SHIFT))
 #endif /* PPC_PTRACE_GETHWDBGINFO */
 
-
+/* Feature defined on Linux kernel v3.9: DAWR interface, that enables wider
+   watchpoint (up to 512 bytes).  */
+#ifndef PPC_DEBUG_FEATURE_DATA_BP_DAWR
+#define PPC_DEBUG_FEATURE_DATA_BP_DAWR 0x10
+#endif /* PPC_DEBUG_FEATURE_DATA_BP_DAWR */
 
 /* Similarly for the general-purpose (gp0 -- gp31)
    and floating-point registers (fp0 -- fp31).  */
@@ -204,7 +206,7 @@ struct ppc_hw_breakpoint
 
    There are 32 vector registers 16 bytes longs, plus a VSCR register
    which is only 4 bytes long, but is fetched as a 16 bytes
-   quantity. Up to here we have the elf_vrregset_t structure.
+   quantity.  Up to here we have the elf_vrregset_t structure.
    Appended to this there is space for the VRSAVE register: 4 bytes.
    Even though this vrsave register is not included in the regset
    typedef, it is handled by the ptrace requests.
@@ -263,7 +265,7 @@ typedef char gdb_vrregset_t[SIZEOF_VRREGS];
 
 typedef char gdb_vsxregset_t[SIZEOF_VSXREGS];
 
-/* On PPC processors that support the the Signal Processing Extension
+/* On PPC processors that support the Signal Processing Extension
    (SPE) APU, the general-purpose registers are 64 bits long.
    However, the ordinary Linux kernel PTRACE_PEEKUSER / PTRACE_POKEUSER
    ptrace calls only access the lower half of each register, to allow
@@ -274,7 +276,7 @@ typedef char gdb_vsxregset_t[SIZEOF_VSXREGS];
 
    GDB itself continues to claim the general-purpose registers are 32
    bits long.  It has unnamed raw registers that hold the upper halves
-   of the gprs, and the the full 64-bit SIMD views of the registers,
+   of the gprs, and the full 64-bit SIMD views of the registers,
    'ev0' -- 'ev31', are pseudo-registers that splice the top and
    bottom halves together.
 
@@ -324,10 +326,14 @@ PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5, PT_R6, PT_R7,
 PT_R8, PT_R9, PT_R10, PT_R11, PT_R12, PT_R13, PT_R14, PT_R15,
 PT_R16, PT_R17, PT_R18, PT_R19, PT_R20, PT_R21, PT_R22, PT_R23,
 PT_R24, PT_R25, PT_R26, PT_R27, PT_R28, PT_R29, PT_R30, PT_R31,
-PT_FPR0, PT_FPR0 + 2, PT_FPR0 + 4, PT_FPR0 + 6, PT_FPR0 + 8, PT_FPR0 + 10, PT_FPR0 + 12, PT_FPR0 + 14,
-PT_FPR0 + 16, PT_FPR0 + 18, PT_FPR0 + 20, PT_FPR0 + 22, PT_FPR0 + 24, PT_FPR0 + 26, PT_FPR0 + 28, PT_FPR0 + 30,
-PT_FPR0 + 32, PT_FPR0 + 34, PT_FPR0 + 36, PT_FPR0 + 38, PT_FPR0 + 40, PT_FPR0 + 42, PT_FPR0 + 44, PT_FPR0 + 46,
-PT_FPR0 + 48, PT_FPR0 + 50, PT_FPR0 + 52, PT_FPR0 + 54, PT_FPR0 + 56, PT_FPR0 + 58, PT_FPR0 + 60, PT_FPR0 + 62,
+PT_FPR0, PT_FPR0 + 2, PT_FPR0 + 4, PT_FPR0 + 6,
+PT_FPR0 + 8, PT_FPR0 + 10, PT_FPR0 + 12, PT_FPR0 + 14,
+PT_FPR0 + 16, PT_FPR0 + 18, PT_FPR0 + 20, PT_FPR0 + 22,
+PT_FPR0 + 24, PT_FPR0 + 26, PT_FPR0 + 28, PT_FPR0 + 30,
+PT_FPR0 + 32, PT_FPR0 + 34, PT_FPR0 + 36, PT_FPR0 + 38,
+PT_FPR0 + 40, PT_FPR0 + 42, PT_FPR0 + 44, PT_FPR0 + 46,
+PT_FPR0 + 48, PT_FPR0 + 50, PT_FPR0 + 52, PT_FPR0 + 54,
+PT_FPR0 + 56, PT_FPR0 + 58, PT_FPR0 + 60, PT_FPR0 + 62,
 PT_NIP, PT_MSR, PT_CCR, PT_LNK, PT_CTR, PT_XER, PT_MQ */
 /* *INDENT_ON * */
 
@@ -340,7 +346,7 @@ ppc_register_u_addr (struct gdbarch *gdbarch, int regno)
      interface, and not the wordsize of the program's ABI.  */
   int wordsize = sizeof (long);
 
-  /* General purpose registers occupy 1 slot each in the buffer */
+  /* General purpose registers occupy 1 slot each in the buffer */
   if (regno >= tdep->ppc_gp0_regnum 
       && regno < tdep->ppc_gp0_regnum + ppc_num_gprs)
     u_addr = ((regno - tdep->ppc_gp0_regnum + PT_R0) * wordsize);
@@ -353,7 +359,7 @@ ppc_register_u_addr (struct gdbarch *gdbarch, int regno)
       && regno < tdep->ppc_fp0_regnum + ppc_num_fprs)
     u_addr = (PT_FPR0 * wordsize) + ((regno - tdep->ppc_fp0_regnum) * 8);
 
-  /* UISA special purpose registers: 1 slot each */
+  /* UISA special purpose registers: 1 slot each */
   if (regno == gdbarch_pc_regnum (gdbarch))
     u_addr = PT_NIP * wordsize;
   if (regno == tdep->ppc_lr_regnum)
@@ -458,7 +464,8 @@ fetch_altivec_register (struct regcache *regcache, int tid, int regno)
     offset = vrregsize - register_size (gdbarch, tdep->ppc_vrsave_regnum);
   
   regcache_raw_supply (regcache, regno,
-                      regs + (regno - tdep->ppc_vr0_regnum) * vrregsize + offset);
+                      regs + (regno
+                              - tdep->ppc_vr0_regnum) * vrregsize + offset);
 }
 
 /* Fetch the top 32 bits of TID's general-purpose registers and the
@@ -542,8 +549,8 @@ fetch_register (struct regcache *regcache, int tid, int regno)
   /* This isn't really an address.  But ptrace thinks of it as one.  */
   CORE_ADDR regaddr = ppc_register_u_addr (gdbarch, regno);
   int bytes_transferred;
-  unsigned int offset;         /* Offset of registers within the u area. */
-  char buf[MAX_REGISTER_SIZE];
+  unsigned int offset;         /* Offset of registers within the u area.  */
+  gdb_byte buf[MAX_REGISTER_SIZE];
 
   if (altivec_register_p (gdbarch, regno))
     {
@@ -588,17 +595,19 @@ fetch_register (struct regcache *regcache, int tid, int regno)
        bytes_transferred < register_size (gdbarch, regno);
        bytes_transferred += sizeof (long))
     {
+      long l;
+
       errno = 0;
-      *(long *) &buf[bytes_transferred]
-        = ptrace (PTRACE_PEEKUSER, tid, (PTRACE_TYPE_ARG3) regaddr, 0);
+      l = ptrace (PTRACE_PEEKUSER, tid, (PTRACE_TYPE_ARG3) regaddr, 0);
       regaddr += sizeof (long);
       if (errno != 0)
        {
           char message[128];
-         sprintf (message, "reading register %s (#%d)", 
-                  gdbarch_register_name (gdbarch, regno), regno);
+         xsnprintf (message, sizeof (message), "reading register %s (#%d)",
+                    gdbarch_register_name (gdbarch, regno), regno);
          perror_with_name (message);
        }
+      memcpy (&buf[bytes_transferred], &l, sizeof (l));
     }
 
   /* Now supply the register.  Keep in mind that the regcache's idea
@@ -854,12 +863,12 @@ static void
 ppc_linux_fetch_inferior_registers (struct target_ops *ops,
                                    struct regcache *regcache, int regno)
 {
-  /* Overload thread id onto process id */
-  int tid = TIDGET (inferior_ptid);
+  /* Overload thread id onto process id */
+  int tid = ptid_get_lwp (inferior_ptid);
 
-  /* No thread id, just use process id */
+  /* No thread id, just use process id */
   if (tid == 0)
-    tid = PIDGET (inferior_ptid);
+    tid = ptid_get_pid (inferior_ptid);
 
   if (regno == -1)
     fetch_ppc_registers (regcache, tid);
@@ -867,7 +876,7 @@ ppc_linux_fetch_inferior_registers (struct target_ops *ops,
     fetch_register (regcache, tid, regno);
 }
 
-/* Store one VSX register. */
+/* Store one VSX register.  */
 static void
 store_vsx_register (const struct regcache *regcache, int tid, int regno)
 {
@@ -896,7 +905,7 @@ store_vsx_register (const struct regcache *regcache, int tid, int regno)
     perror_with_name (_("Unable to store VSX register"));
 }
 
-/* Store one register. */
+/* Store one register.  */
 static void
 store_altivec_register (const struct regcache *regcache, int tid, int regno)
 {
@@ -924,7 +933,8 @@ store_altivec_register (const struct regcache *regcache, int tid, int regno)
     offset = vrregsize - register_size (gdbarch, tdep->ppc_vrsave_regnum);
 
   regcache_raw_collect (regcache, regno,
-                       regs + (regno - tdep->ppc_vr0_regnum) * vrregsize + offset);
+                       regs + (regno
+                               - tdep->ppc_vr0_regnum) * vrregsize + offset);
 
   ret = ptrace (PTRACE_SETVRREGS, tid, 0, &regs);
   if (ret < 0)
@@ -1027,7 +1037,7 @@ store_register (const struct regcache *regcache, int tid, int regno)
   CORE_ADDR regaddr = ppc_register_u_addr (gdbarch, regno);
   int i;
   size_t bytes_to_transfer;
-  char buf[MAX_REGISTER_SIZE];
+  gdb_byte buf[MAX_REGISTER_SIZE];
 
   if (altivec_register_p (gdbarch, regno))
     {
@@ -1067,9 +1077,11 @@ store_register (const struct regcache *regcache, int tid, int regno)
 
   for (i = 0; i < bytes_to_transfer; i += sizeof (long))
     {
+      long l;
+
+      memcpy (&l, &buf[i], sizeof (l));
       errno = 0;
-      ptrace (PTRACE_POKEUSER, tid, (PTRACE_TYPE_ARG3) regaddr,
-             *(long *) &buf[i]);
+      ptrace (PTRACE_POKEUSER, tid, (PTRACE_TYPE_ARG3) regaddr, l);
       regaddr += sizeof (long);
 
       if (errno == EIO 
@@ -1085,8 +1097,8 @@ store_register (const struct regcache *regcache, int tid, int regno)
       if (errno != 0)
        {
           char message[128];
-         sprintf (message, "writing register %s (#%d)", 
-                  gdbarch_register_name (gdbarch, regno), regno);
+         xsnprintf (message, sizeof (message), "writing register %s (#%d)",
+                    gdbarch_register_name (gdbarch, regno), regno);
          perror_with_name (message);
        }
     }
@@ -1341,7 +1353,8 @@ store_ppc_registers (const struct regcache *regcache, int tid)
 }
 
 /* Fetch the AT_HWCAP entry from the aux vector.  */
-unsigned long ppc_linux_get_hwcap (void)
+static unsigned long
+ppc_linux_get_hwcap (void)
 {
   CORE_ADDR field;
 
@@ -1352,16 +1365,17 @@ unsigned long ppc_linux_get_hwcap (void)
 }
 
 /* The cached DABR value, to install in new threads.
-   This variable is used when we are dealing with non-BookE
-   processors.  */
+   This variable is used when the PowerPC HWDEBUG ptrace
+   interface is not available.  */
 static long saved_dabr_value;
 
 /* Global structure that will store information about the available
-   features on this BookE processor.  */
-static struct ppc_debug_info booke_debug_info;
+   features provided by the PowerPC HWDEBUG ptrace interface.  */
+static struct ppc_debug_info hwdebug_info;
 
 /* Global variable that holds the maximum number of slots that the
-   kernel will use.  This is only used when the processor is BookE.  */
+   kernel will use.  This is only used when PowerPC HWDEBUG ptrace interface
+   is available.  */
 static size_t max_slots_number = 0;
 
 struct hw_break_tuple
@@ -1371,7 +1385,8 @@ struct hw_break_tuple
 };
 
 /* This is an internal VEC created to store information about *points inserted
-   for each thread.  This is used for BookE processors.  */
+   for each thread.  This is used when PowerPC HWDEBUG ptrace interface is
+   available.  */
 typedef struct thread_points
   {
     /* The TID to which this *point relates.  */
@@ -1388,41 +1403,44 @@ DEF_VEC_P (thread_points_p);
 
 VEC(thread_points_p) *ppc_threads = NULL;
 
-/* The version of the kernel interface that we will use if the processor is
-   BookE.  */
+/* The version of the PowerPC HWDEBUG kernel interface that we will use, if
+   available.  */
 #define PPC_DEBUG_CURRENT_VERSION 1
 
-/* Returns non-zero if we support the ptrace interface which enables
-   booke debugging resources.  */
+/* Returns non-zero if we support the PowerPC HWDEBUG ptrace interface.  */
 static int
-have_ptrace_booke_interface (void)
+have_ptrace_hwdebug_interface (void)
 {
-  static int have_ptrace_booke_interface = -1;
+  static int have_ptrace_hwdebug_interface = -1;
 
-  if (have_ptrace_booke_interface == -1)
+  if (have_ptrace_hwdebug_interface == -1)
     {
       int tid;
 
-      tid = TIDGET (inferior_ptid);
+      tid = ptid_get_lwp (inferior_ptid);
       if (tid == 0)
-       tid = PIDGET (inferior_ptid);
+       tid = ptid_get_pid (inferior_ptid);
 
-      /* Check for kernel support for BOOKE debug registers.  */
-      if (ptrace (PPC_PTRACE_GETHWDBGINFO, tid, 0, &booke_debug_info) >= 0)
+      /* Check for kernel support for PowerPC HWDEBUG ptrace interface.  */
+      if (ptrace (PPC_PTRACE_GETHWDBGINFO, tid, 0, &hwdebug_info) >= 0)
        {
-         have_ptrace_booke_interface = 1;
-         max_slots_number = booke_debug_info.num_instruction_bps
-           + booke_debug_info.num_data_bps + booke_debug_info.num_condition_regs;
-       }
-      else
-       {
-         /* Old school interface and no BOOKE debug registers support.  */
-         have_ptrace_booke_interface = 0;
-         memset (&booke_debug_info, 0, sizeof (struct ppc_debug_info));
+         /* Check whether PowerPC HWDEBUG ptrace interface is functional and
+            provides any supported feature.  */
+         if (hwdebug_info.features != 0)
+           {
+             have_ptrace_hwdebug_interface = 1;
+             max_slots_number = hwdebug_info.num_instruction_bps
+               + hwdebug_info.num_data_bps
+               + hwdebug_info.num_condition_regs;
+             return have_ptrace_hwdebug_interface;
+           }
        }
+      /* Old school interface and no PowerPC HWDEBUG ptrace support.  */
+      have_ptrace_hwdebug_interface = 0;
+      memset (&hwdebug_info, 0, sizeof (struct ppc_debug_info));
     }
 
-  return have_ptrace_booke_interface;
+  return have_ptrace_hwdebug_interface;
 }
 
 static int
@@ -1430,18 +1448,18 @@ ppc_linux_can_use_hw_breakpoint (int type, int cnt, int ot)
 {
   int total_hw_wp, total_hw_bp;
 
-  if (have_ptrace_booke_interface ())
+  if (have_ptrace_hwdebug_interface ())
     {
-      /* For PPC BookE processors, the number of available hardware
-         watchpoints and breakpoints is stored at the booke_debug_info
-        struct.  */
-      total_hw_bp = booke_debug_info.num_instruction_bps;
-      total_hw_wp = booke_debug_info.num_data_bps;
+      /* When PowerPC HWDEBUG ptrace interface is available, the number of
+        available hardware watchpoints and breakpoints is stored at the
+        hwdebug_info struct.  */
+      total_hw_bp = hwdebug_info.num_instruction_bps;
+      total_hw_wp = hwdebug_info.num_data_bps;
     }
   else
     {
-      /* For PPC server processors, we accept 1 hardware watchpoint and 0
-        hardware breakpoints.  */
+      /* When we do not have PowerPC HWDEBUG ptrace interface, we should
+        consider having 1 hardware watchpoint and no hardware breakpoints.  */
       total_hw_bp = 0;
       total_hw_wp = 1;
     }
@@ -1449,7 +1467,7 @@ ppc_linux_can_use_hw_breakpoint (int type, int cnt, int ot)
   if (type == bp_hardware_watchpoint || type == bp_read_watchpoint
       || type == bp_access_watchpoint || type == bp_watchpoint)
     {
-      if (cnt > total_hw_wp)
+      if (cnt + ot > total_hw_wp)
        return -1;
     }
   else if (type == bp_hardware_breakpoint)
@@ -1458,17 +1476,17 @@ ppc_linux_can_use_hw_breakpoint (int type, int cnt, int ot)
        return -1;
     }
 
-  if (!have_ptrace_booke_interface ())
+  if (!have_ptrace_hwdebug_interface ())
     {
       int tid;
       ptid_t ptid = inferior_ptid;
 
-      /* We need to know whether ptrace supports PTRACE_SET_DEBUGREG and whether
-        the target has DABR.  If either answer is no, the ptrace call will
-        return -1.  Fail in that case.  */
-      tid = TIDGET (ptid);
+      /* We need to know whether ptrace supports PTRACE_SET_DEBUGREG
+        and whether the target has DABR.  If either answer is no, the
+        ptrace call will return -1.  Fail in that case.  */
+      tid = ptid_get_lwp (ptid);
       if (tid == 0)
-       tid = PIDGET (ptid);
+       tid = ptid_get_pid (ptid);
 
       if (ptrace (PTRACE_SET_DEBUGREG, tid, 0, 0) == -1)
        return 0;
@@ -1484,20 +1502,38 @@ ppc_linux_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
   if (len <= 0)
     return 0;
 
-  /* The new BookE ptrace interface tells if there are alignment restrictions
-     for watchpoints in the processors.  In that case, we use that information
-     to determine the hardcoded watchable region for watchpoints.  */
-  if (have_ptrace_booke_interface ())
+  /* The PowerPC HWDEBUG ptrace interface tells if there are alignment
+     restrictions for watchpoints in the processors.  In that case, we use that
+     information to determine the hardcoded watchable region for
+     watchpoints.  */
+  if (have_ptrace_hwdebug_interface ())
     {
-      if (booke_debug_info.data_bp_alignment
-         && (addr + len > (addr & ~(booke_debug_info.data_bp_alignment - 1))
-             + booke_debug_info.data_bp_alignment))
+      int region_size;
+      /* Embedded DAC-based processors, like the PowerPC 440 have ranged
+        watchpoints and can watch any access within an arbitrary memory
+        region. This is useful to watch arrays and structs, for instance.  It
+         takes two hardware watchpoints though.  */
+      if (len > 1
+         && hwdebug_info.features & PPC_DEBUG_FEATURE_DATA_BP_RANGE
+         && ppc_linux_get_hwcap () & PPC_FEATURE_BOOKE)
+       return 2;
+      /* Check if the processor provides DAWR interface.  */
+      if (hwdebug_info.features & PPC_DEBUG_FEATURE_DATA_BP_DAWR)
+       /* DAWR interface allows to watch up to 512 byte wide ranges which
+          can't cross a 512 byte boundary.  */
+       region_size = 512;
+      else
+       region_size = hwdebug_info.data_bp_alignment;
+      /* Server processors provide one hardware watchpoint and addr+len should
+         fall in the watchable region provided by the ptrace interface.  */
+      if (region_size
+         && (addr + len > (addr & ~(region_size - 1)) + region_size))
        return 0;
     }
   /* addr+len must fall in the 8 byte watchable region for DABR-based
-     processors (i.e., server processors).  Without the new BookE ptrace
-     interface, DAC-based processors (i.e., embedded processors) will use
-     addresses aligned to 4-bytes due to the way the read/write flags are
+     processors (i.e., server processors).  Without the new PowerPC HWDEBUG 
+     ptrace interface, DAC-based processors (i.e., embedded processors) will
+     use addresses aligned to 4-bytes due to the way the read/write flags are
      passed in the old ptrace interface.  */
   else if (((ppc_linux_get_hwcap () & PPC_FEATURE_BOOKE)
           && (addr + len) > (addr & ~3) + 4)
@@ -1509,13 +1545,13 @@ ppc_linux_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
 
 /* This function compares two ppc_hw_breakpoint structs field-by-field.  */
 static int
-booke_cmp_hw_point (struct ppc_hw_breakpoint *a, struct ppc_hw_breakpoint *b)
+hwdebug_point_cmp (struct ppc_hw_breakpoint *a, struct ppc_hw_breakpoint *b)
 {
-  return (a->trigger_type       == b->trigger_type
-         && a->addr_mode       == b->addr_mode
-         && a->condition_mode  == b->condition_mode
-         && a->addr            == b->addr
-         && a->addr2           == b->addr2
+  return (a->trigger_type == b->trigger_type
+         && a->addr_mode == b->addr_mode
+         && a->condition_mode == b->condition_mode
+         && a->addr == b->addr
+         && a->addr2 == b->addr2
          && a->condition_value == b->condition_value);
 }
 
@@ -1524,7 +1560,7 @@ booke_cmp_hw_point (struct ppc_hw_breakpoint *a, struct ppc_hw_breakpoint *b)
    it returns NULL.  If ALLOC_NEW is non-zero, a new thread_points for the
    provided TID will be created and returned.  */
 static struct thread_points *
-booke_find_thread_points_by_tid (int tid, int alloc_new)
+hwdebug_find_thread_points_by_tid (int tid, int alloc_new)
 {
   int i;
   struct thread_points *t;
@@ -1540,7 +1576,8 @@ booke_find_thread_points_by_tid (int tid, int alloc_new)
   if (alloc_new)
     {
       t = xmalloc (sizeof (struct thread_points));
-      t->hw_breaks = xzalloc (max_slots_number * sizeof (struct hw_break_tuple));
+      t->hw_breaks
+       = xzalloc (max_slots_number * sizeof (struct hw_break_tuple));
       t->tid = tid;
       VEC_safe_push (thread_points_p, ppc_threads, t);
     }
@@ -1552,7 +1589,7 @@ booke_find_thread_points_by_tid (int tid, int alloc_new)
    *point (i.e., calling `ptrace' in order to issue the request to the
    kernel) and registering it internally in GDB.  */
 static void
-booke_insert_point (struct ppc_hw_breakpoint *b, int tid)
+hwdebug_insert_point (struct ppc_hw_breakpoint *b, int tid)
 {
   int i;
   long slot;
@@ -1570,7 +1607,7 @@ booke_insert_point (struct ppc_hw_breakpoint *b, int tid)
     perror_with_name (_("Unexpected error setting breakpoint or watchpoint"));
 
   /* Everything went fine, so we have to register this *point.  */
-  t = booke_find_thread_points_by_tid (tid, 1);
+  t = hwdebug_find_thread_points_by_tid (tid, 1);
   gdb_assert (t != NULL);
   hw_breaks = t->hw_breaks;
 
@@ -1592,18 +1629,18 @@ booke_insert_point (struct ppc_hw_breakpoint *b, int tid)
    *point (i.e., calling `ptrace' in order to issue the request to the
    kernel), and unregistering it internally at GDB.  */
 static void
-booke_remove_point (struct ppc_hw_breakpoint *b, int tid)
+hwdebug_remove_point (struct ppc_hw_breakpoint *b, int tid)
 {
   int i;
   struct hw_break_tuple *hw_breaks;
   struct thread_points *t;
 
-  t = booke_find_thread_points_by_tid (tid, 0);
+  t = hwdebug_find_thread_points_by_tid (tid, 0);
   gdb_assert (t != NULL);
   hw_breaks = t->hw_breaks;
 
   for (i = 0; i < max_slots_number; i++)
-    if (hw_breaks[i].hw_break && booke_cmp_hw_point (hw_breaks[i].hw_break, b))
+    if (hw_breaks[i].hw_break && hwdebug_point_cmp (hw_breaks[i].hw_break, b))
       break;
 
   gdb_assert (i != max_slots_number);
@@ -1614,33 +1651,58 @@ booke_remove_point (struct ppc_hw_breakpoint *b, int tid)
   errno = 0;
   if (ptrace (PPC_PTRACE_DELHWDEBUG, tid, 0, hw_breaks[i].slot) < 0)
     if (errno != ENOENT)
-      perror_with_name (_("Unexpected error deleting breakpoint or watchpoint"));
+      perror_with_name (_("Unexpected error deleting "
+                         "breakpoint or watchpoint"));
 
   xfree (hw_breaks[i].hw_break);
   hw_breaks[i].hw_break = NULL;
 }
 
+/* Return the number of registers needed for a ranged breakpoint.  */
+
+static int
+ppc_linux_ranged_break_num_registers (struct target_ops *target)
+{
+  return ((have_ptrace_hwdebug_interface ()
+          && hwdebug_info.features & PPC_DEBUG_FEATURE_INSN_BP_RANGE)?
+         2 : -1);
+}
+
+/* Insert the hardware breakpoint described by BP_TGT.  Returns 0 for
+   success, 1 if hardware breakpoints are not supported or -1 for failure.  */
+
 static int
 ppc_linux_insert_hw_breakpoint (struct gdbarch *gdbarch,
                                  struct bp_target_info *bp_tgt)
 {
-  ptid_t ptid;
   struct lwp_info *lp;
   struct ppc_hw_breakpoint p;
 
-  if (!have_ptrace_booke_interface ())
+  if (!have_ptrace_hwdebug_interface ())
     return -1;
 
-  p.version         = PPC_DEBUG_CURRENT_VERSION;
-  p.trigger_type    = PPC_BREAKPOINT_TRIGGER_EXECUTE;
-  p.addr_mode       = PPC_BREAKPOINT_MODE_EXACT;
-  p.condition_mode  = PPC_BREAKPOINT_CONDITION_NONE;
-  p.addr            = (uint64_t) bp_tgt->placed_address;
-  p.addr2           = 0;
+  p.version = PPC_DEBUG_CURRENT_VERSION;
+  p.trigger_type = PPC_BREAKPOINT_TRIGGER_EXECUTE;
+  p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
+  p.addr = (uint64_t) bp_tgt->placed_address;
   p.condition_value = 0;
 
-  ALL_LWPS (lp, ptid)
-    booke_insert_point (&p, TIDGET (ptid));
+  if (bp_tgt->length)
+    {
+      p.addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
+
+      /* The breakpoint will trigger if the address of the instruction is
+        within the defined range, as follows: p.addr <= address < p.addr2.  */
+      p.addr2 = (uint64_t) bp_tgt->placed_address + bp_tgt->length;
+    }
+  else
+    {
+      p.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
+      p.addr2 = 0;
+    }
+
+  ALL_LWPS (lp)
+    hwdebug_insert_point (&p, ptid_get_lwp (lp->ptid));
 
   return 0;
 }
@@ -1649,23 +1711,34 @@ static int
 ppc_linux_remove_hw_breakpoint (struct gdbarch *gdbarch,
                                  struct bp_target_info *bp_tgt)
 {
-  ptid_t ptid;
   struct lwp_info *lp;
   struct ppc_hw_breakpoint p;
 
-  if (!have_ptrace_booke_interface ())
+  if (!have_ptrace_hwdebug_interface ())
     return -1;
 
-  p.version         = PPC_DEBUG_CURRENT_VERSION;
-  p.trigger_type    = PPC_BREAKPOINT_TRIGGER_EXECUTE;
-  p.addr_mode       = PPC_BREAKPOINT_MODE_EXACT;
-  p.condition_mode  = PPC_BREAKPOINT_CONDITION_NONE;
-  p.addr            = (uint64_t) bp_tgt->placed_address;
-  p.addr2           = 0;
+  p.version = PPC_DEBUG_CURRENT_VERSION;
+  p.trigger_type = PPC_BREAKPOINT_TRIGGER_EXECUTE;
+  p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
+  p.addr = (uint64_t) bp_tgt->placed_address;
   p.condition_value = 0;
 
-  ALL_LWPS (lp, ptid)
-    booke_remove_point (&p, TIDGET (ptid));
+  if (bp_tgt->length)
+    {
+      p.addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
+
+      /* The breakpoint will trigger if the address of the instruction is within
+        the defined range, as follows: p.addr <= address < p.addr2.  */
+      p.addr2 = (uint64_t) bp_tgt->placed_address + bp_tgt->length;
+    }
+  else
+    {
+      p.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
+      p.addr2 = 0;
+    }
+
+  ALL_LWPS (lp)
+    hwdebug_remove_point (&p, ptid_get_lwp (lp->ptid));
 
   return 0;
 }
@@ -1685,19 +1758,75 @@ get_trigger_type (int rw)
   return t;
 }
 
+/* Insert a new masked watchpoint at ADDR using the mask MASK.
+   RW may be hw_read for a read watchpoint, hw_write for a write watchpoint
+   or hw_access for an access watchpoint.  Returns 0 on success and throws
+   an error on failure.  */
+
+static int
+ppc_linux_insert_mask_watchpoint (struct target_ops *ops, CORE_ADDR addr,
+                                 CORE_ADDR mask, int rw)
+{
+  struct lwp_info *lp;
+  struct ppc_hw_breakpoint p;
+
+  gdb_assert (have_ptrace_hwdebug_interface ());
+
+  p.version = PPC_DEBUG_CURRENT_VERSION;
+  p.trigger_type = get_trigger_type (rw);
+  p.addr_mode = PPC_BREAKPOINT_MODE_MASK;
+  p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
+  p.addr = addr;
+  p.addr2 = mask;
+  p.condition_value = 0;
+
+  ALL_LWPS (lp)
+    hwdebug_insert_point (&p, ptid_get_lwp (lp->ptid));
+
+  return 0;
+}
+
+/* Remove a masked watchpoint at ADDR with the mask MASK.
+   RW may be hw_read for a read watchpoint, hw_write for a write watchpoint
+   or hw_access for an access watchpoint.  Returns 0 on success and throws
+   an error on failure.  */
+
+static int
+ppc_linux_remove_mask_watchpoint (struct target_ops *ops, CORE_ADDR addr,
+                                 CORE_ADDR mask, int rw)
+{
+  struct lwp_info *lp;
+  struct ppc_hw_breakpoint p;
+
+  gdb_assert (have_ptrace_hwdebug_interface ());
+
+  p.version = PPC_DEBUG_CURRENT_VERSION;
+  p.trigger_type = get_trigger_type (rw);
+  p.addr_mode = PPC_BREAKPOINT_MODE_MASK;
+  p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
+  p.addr = addr;
+  p.addr2 = mask;
+  p.condition_value = 0;
+
+  ALL_LWPS (lp)
+    hwdebug_remove_point (&p, ptid_get_lwp (lp->ptid));
+
+  return 0;
+}
+
 /* Check whether we have at least one free DVC register.  */
 static int
 can_use_watchpoint_cond_accel (void)
 {
   struct thread_points *p;
-  int tid = TIDGET (inferior_ptid);
-  int cnt = booke_debug_info.num_condition_regs, i;
+  int tid = ptid_get_lwp (inferior_ptid);
+  int cnt = hwdebug_info.num_condition_regs, i;
   CORE_ADDR tmp_value;
 
-  if (!have_ptrace_booke_interface () || cnt == 0)
+  if (!have_ptrace_hwdebug_interface () || cnt == 0)
     return 0;
 
-  p = booke_find_thread_points_by_tid (tid, 0);
+  p = hwdebug_find_thread_points_by_tid (tid, 0);
 
   if (p)
     {
@@ -1736,10 +1865,10 @@ calculate_dvc (CORE_ADDR addr, int len, CORE_ADDR data_value,
      We need to calculate where our watch region is relative to that
      window and enable comparison of the bytes which fall within it.  */
 
-  align_offset = addr % booke_debug_info.sizeof_condition;
+  align_offset = addr % hwdebug_info.sizeof_condition;
   addr_end_data = addr + len;
   addr_end_dvc = (addr - align_offset
-                 + booke_debug_info.sizeof_condition);
+                 + hwdebug_info.sizeof_condition);
   num_bytes_off_dvc = (addr_end_data > addr_end_dvc)?
                         addr_end_data - addr_end_dvc : 0;
   num_byte_enable = len - num_bytes_off_dvc;
@@ -1749,7 +1878,8 @@ calculate_dvc (CORE_ADDR addr, int len, CORE_ADDR data_value,
 
   *condition_mode = PPC_BREAKPOINT_CONDITION_AND;
   for (i = 0; i < num_byte_enable; i++)
-    *condition_mode |= PPC_BREAKPOINT_CONDITION_BE (i + rightmost_enabled_byte);
+    *condition_mode
+      |= PPC_BREAKPOINT_CONDITION_BE (i + rightmost_enabled_byte);
 
   /* Now we need to match the position within the DVC of the comparison
      value with where the watch region is relative to the window
@@ -1798,7 +1928,7 @@ num_memory_accesses (struct value *v)
          if (!value_lazy (v))
            found_memory_cnt++;
        }
-      /* Other kinds of values are not fine. */
+      /* Other kinds of values are not fine.  */
       else
        return -1;
     }
@@ -1810,10 +1940,11 @@ num_memory_accesses (struct value *v)
    DVC (Data Value Compare) register in BookE processors.  The expression
    must test the watch value for equality with a constant expression.
    If the function returns 1, DATA_VALUE will contain the constant against
-   which the watch value should be compared.  */
+   which the watch value should be compared and LEN will contain the size
+   of the constant.  */
 static int
 check_condition (CORE_ADDR watch_addr, struct expression *cond,
-                CORE_ADDR *data_value)
+                CORE_ADDR *data_value, int *len)
 {
   int pc = 1, num_accesses_left, num_accesses_right;
   struct value *left_val, *right_val, *left_chain, *right_chain;
@@ -1821,7 +1952,7 @@ check_condition (CORE_ADDR watch_addr, struct expression *cond,
   if (cond->elts[0].opcode != BINOP_EQUAL)
     return 0;
 
-  fetch_subexp_value (cond, &pc, &left_val, NULL, &left_chain);
+  fetch_subexp_value (cond, &pc, &left_val, NULL, &left_chain, 0);
   num_accesses_left = num_memory_accesses (left_chain);
 
   if (left_val == NULL || num_accesses_left < 0)
@@ -1831,7 +1962,7 @@ check_condition (CORE_ADDR watch_addr, struct expression *cond,
       return 0;
     }
 
-  fetch_subexp_value (cond, &pc, &right_val, NULL, &right_chain);
+  fetch_subexp_value (cond, &pc, &right_val, NULL, &right_chain, 0);
   num_accesses_right = num_memory_accesses (right_chain);
 
   if (right_val == NULL || num_accesses_right < 0)
@@ -1845,11 +1976,23 @@ check_condition (CORE_ADDR watch_addr, struct expression *cond,
   if (num_accesses_left == 1 && num_accesses_right == 0
       && VALUE_LVAL (left_val) == lval_memory
       && value_address (left_val) == watch_addr)
-    *data_value = value_as_long (right_val);
+    {
+      *data_value = value_as_long (right_val);
+
+      /* DATA_VALUE is the constant in RIGHT_VAL, but actually has
+        the same type as the memory region referenced by LEFT_VAL.  */
+      *len = TYPE_LENGTH (check_typedef (value_type (left_val)));
+    }
   else if (num_accesses_left == 0 && num_accesses_right == 1
           && VALUE_LVAL (right_val) == lval_memory
           && value_address (right_val) == watch_addr)
-    *data_value = value_as_long (left_val);
+    {
+      *data_value = value_as_long (left_val);
+
+      /* DATA_VALUE is the constant in LEFT_VAL, but actually has
+        the same type as the memory region referenced by RIGHT_VAL.  */
+      *len = TYPE_LENGTH (check_typedef (value_type (right_val)));
+    }
   else
     {
       free_value_chain (left_chain);
@@ -1873,9 +2016,60 @@ ppc_linux_can_accel_watchpoint_condition (CORE_ADDR addr, int len, int rw,
 {
   CORE_ADDR data_value;
 
-  return (have_ptrace_booke_interface ()
-         && booke_debug_info.num_condition_regs > 0
-         && check_condition (addr, cond, &data_value));
+  return (have_ptrace_hwdebug_interface ()
+         && hwdebug_info.num_condition_regs > 0
+         && check_condition (addr, cond, &data_value, &len));
+}
+
+/* Set up P with the parameters necessary to request a watchpoint covering
+   LEN bytes starting at ADDR and if possible with condition expression COND
+   evaluated by hardware.  INSERT tells if we are creating a request for
+   inserting or removing the watchpoint.  */
+
+static void
+create_watchpoint_request (struct ppc_hw_breakpoint *p, CORE_ADDR addr,
+                          int len, int rw, struct expression *cond,
+                          int insert)
+{
+  if (len == 1
+      || !(hwdebug_info.features & PPC_DEBUG_FEATURE_DATA_BP_RANGE))
+    {
+      int use_condition;
+      CORE_ADDR data_value;
+
+      use_condition = (insert? can_use_watchpoint_cond_accel ()
+                       : hwdebug_info.num_condition_regs > 0);
+      if (cond && use_condition && check_condition (addr, cond,
+                                                   &data_value, &len))
+       calculate_dvc (addr, len, data_value, &p->condition_mode,
+                      &p->condition_value);
+      else
+       {
+         p->condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
+         p->condition_value = 0;
+       }
+
+      p->addr_mode = PPC_BREAKPOINT_MODE_EXACT;
+      p->addr2 = 0;
+    }
+  else
+    {
+      p->addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
+      p->condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
+      p->condition_value = 0;
+
+      /* The watchpoint will trigger if the address of the memory access is
+        within the defined range, as follows: p->addr <= address < p->addr2.
+
+        Note that the above sentence just documents how ptrace interprets
+        its arguments; the watchpoint is set to watch the range defined by
+        the user _inclusively_, as specified by the user interface.  */
+      p->addr2 = (uint64_t) addr + len;
+    }
+
+  p->version = PPC_DEBUG_CURRENT_VERSION;
+  p->trigger_type = get_trigger_type (rw);
+  p->addr = (uint64_t) addr;
 }
 
 static int
@@ -1883,32 +2077,16 @@ ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw,
                             struct expression *cond)
 {
   struct lwp_info *lp;
-  ptid_t ptid;
   int ret = -1;
 
-  if (have_ptrace_booke_interface ())
+  if (have_ptrace_hwdebug_interface ())
     {
       struct ppc_hw_breakpoint p;
-      CORE_ADDR data_value;
-
-      if (cond && can_use_watchpoint_cond_accel ()
-         && check_condition (addr, cond, &data_value))
-       calculate_dvc (addr, len, data_value, &p.condition_mode,
-                      &p.condition_value);
-      else
-       {
-         p.condition_mode  = PPC_BREAKPOINT_CONDITION_NONE;
-         p.condition_value = 0;
-       }
 
-      p.version         = PPC_DEBUG_CURRENT_VERSION;
-      p.trigger_type    = get_trigger_type (rw);
-      p.addr_mode       = PPC_BREAKPOINT_MODE_EXACT;
-      p.addr            = (uint64_t) addr;
-      p.addr2           = 0;
+      create_watchpoint_request (&p, addr, len, rw, cond, 1);
 
-      ALL_LWPS (lp, ptid)
-       booke_insert_point (&p, TIDGET (ptid));
+      ALL_LWPS (lp)
+       hwdebug_insert_point (&p, ptid_get_lwp (lp->ptid));
 
       ret = 0;
     }
@@ -1921,14 +2099,14 @@ ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw,
        {
          /* PowerPC 440 requires only the read/write flags to be passed
             to the kernel.  */
-         read_mode  = 1;
+         read_mode = 1;
          write_mode = 2;
        }
       else
        {
          /* PowerPC 970 and other DABR-based processors are required to pass
             the Breakpoint Translation bit together with the flags.  */
-         read_mode  = 5;
+         read_mode = 5;
          write_mode = 6;
        }
 
@@ -1951,8 +2129,8 @@ ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw,
 
       saved_dabr_value = dabr_value;
 
-      ALL_LWPS (lp, ptid)
-       if (ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0,
+      ALL_LWPS (lp)
+       if (ptrace (PTRACE_SET_DEBUGREG, ptid_get_lwp (lp->ptid), 0,
                    saved_dabr_value) < 0)
          return -1;
 
@@ -1967,40 +2145,24 @@ ppc_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw,
                             struct expression *cond)
 {
   struct lwp_info *lp;
-  ptid_t ptid;
   int ret = -1;
 
-  if (have_ptrace_booke_interface ())
+  if (have_ptrace_hwdebug_interface ())
     {
       struct ppc_hw_breakpoint p;
-      CORE_ADDR data_value;
-
-      if (cond && booke_debug_info.num_condition_regs > 0
-         && check_condition (addr, cond, &data_value))
-       calculate_dvc (addr, len, data_value, &p.condition_mode,
-                      &p.condition_value);
-      else
-       {
-         p.condition_mode  = PPC_BREAKPOINT_CONDITION_NONE;
-         p.condition_value = 0;
-       }
 
-      p.version         = PPC_DEBUG_CURRENT_VERSION;
-      p.trigger_type    = get_trigger_type (rw);
-      p.addr_mode       = PPC_BREAKPOINT_MODE_EXACT;
-      p.addr            = (uint64_t) addr;
-      p.addr2           = 0;
+      create_watchpoint_request (&p, addr, len, rw, cond, 0);
 
-      ALL_LWPS (lp, ptid)
-       booke_remove_point (&p, TIDGET (ptid));
+      ALL_LWPS (lp)
+       hwdebug_remove_point (&p, ptid_get_lwp (lp->ptid));
 
       ret = 0;
     }
   else
     {
       saved_dabr_value = 0;
-      ALL_LWPS (lp, ptid)
-       if (ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0,
+      ALL_LWPS (lp)
+       if (ptrace (PTRACE_SET_DEBUGREG, ptid_get_lwp (lp->ptid), 0,
                    saved_dabr_value) < 0)
          return -1;
 
@@ -2011,11 +2173,11 @@ ppc_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw,
 }
 
 static void
-ppc_linux_new_thread (ptid_t ptid)
+ppc_linux_new_thread (struct lwp_info *lp)
 {
-  int tid = TIDGET (ptid);
+  int tid = ptid_get_lwp (lp->ptid);
 
-  if (have_ptrace_booke_interface ())
+  if (have_ptrace_hwdebug_interface ())
     {
       int i;
       struct thread_points *p;
@@ -2024,14 +2186,25 @@ ppc_linux_new_thread (ptid_t ptid)
       if (VEC_empty (thread_points_p, ppc_threads))
        return;
 
-      /* Get a list of breakpoints from any thread. */
+      /* Get a list of breakpoints from any thread.  */
       p = VEC_last (thread_points_p, ppc_threads);
       hw_breaks = p->hw_breaks;
 
-      /* Copy that thread's breakpoints and watchpoints to the new thread. */
+      /* Copy that thread's breakpoints and watchpoints to the new thread.  */
       for (i = 0; i < max_slots_number; i++)
        if (hw_breaks[i].hw_break)
-         booke_insert_point (hw_breaks[i].hw_break, tid);
+         {
+           /* Older kernels did not make new threads inherit their parent
+              thread's debug state, so we always clear the slot and replicate
+              the debug state ourselves, ensuring compatibility with all
+              kernels.  */
+
+           /* The ppc debug resource accounting is done through "slots".
+              Ask the kernel the deallocate this specific *point's slot.  */
+           ptrace (PPC_PTRACE_DELHWDEBUG, tid, 0, hw_breaks[i].slot);
+
+           hwdebug_insert_point (hw_breaks[i].hw_break, tid);
+         }
     }
   else
     ptrace (PTRACE_SET_DEBUGREG, tid, 0, saved_dabr_value);
@@ -2041,11 +2214,11 @@ static void
 ppc_linux_thread_exit (struct thread_info *tp, int silent)
 {
   int i;
-  int tid = TIDGET (tp->ptid);
+  int tid = ptid_get_lwp (tp->ptid);
   struct hw_break_tuple *hw_breaks;
   struct thread_points *t = NULL, *p;
 
-  if (!have_ptrace_booke_interface ())
+  if (!have_ptrace_hwdebug_interface ())
     return;
 
   for (i = 0; VEC_iterate (thread_points_p, ppc_threads, i, p); i++)
@@ -2073,23 +2246,24 @@ ppc_linux_thread_exit (struct thread_info *tp, int silent)
 static int
 ppc_linux_stopped_data_address (struct target_ops *target, CORE_ADDR *addr_p)
 {
-  struct siginfo *siginfo_p;
+  siginfo_t siginfo;
 
-  siginfo_p = linux_nat_get_siginfo (inferior_ptid);
+  if (!linux_nat_get_siginfo (inferior_ptid, &siginfo))
+    return 0;
 
-  if (siginfo_p->si_signo != SIGTRAP
-      || (siginfo_p->si_code & 0xffff) != 0x0004 /* TRAP_HWBKPT */)
+  if (siginfo.si_signo != SIGTRAP
+      || (siginfo.si_code & 0xffff) != 0x0004 /* TRAP_HWBKPT */)
     return 0;
 
-  if (have_ptrace_booke_interface ())
+  if (have_ptrace_hwdebug_interface ())
     {
       int i;
       struct thread_points *t;
       struct hw_break_tuple *hw_breaks;
       /* The index (or slot) of the *point is passed in the si_errno field.  */
-      int slot = siginfo_p->si_errno;
+      int slot = siginfo.si_errno;
 
-      t = booke_find_thread_points_by_tid (TIDGET (inferior_ptid), 0);
+      t = hwdebug_find_thread_points_by_tid (ptid_get_lwp (inferior_ptid), 0);
 
       /* Find out if this *point is a hardware breakpoint.
         If so, we should return 0.  */
@@ -2104,7 +2278,7 @@ ppc_linux_stopped_data_address (struct target_ops *target, CORE_ADDR *addr_p)
        }
     }
 
-  *addr_p = (CORE_ADDR) (uintptr_t) siginfo_p->si_addr;
+  *addr_p = (CORE_ADDR) (uintptr_t) siginfo.si_addr;
   return 1;
 }
 
@@ -2122,7 +2296,7 @@ ppc_linux_watchpoint_addr_within_range (struct target_ops *target,
 {
   int mask;
 
-  if (have_ptrace_booke_interface ()
+  if (have_ptrace_hwdebug_interface ()
       && ppc_linux_get_hwcap () & PPC_FEATURE_BOOKE)
     return start <= addr && start + length >= addr;
   else if (ppc_linux_get_hwcap () & PPC_FEATURE_BOOKE)
@@ -2132,20 +2306,40 @@ ppc_linux_watchpoint_addr_within_range (struct target_ops *target,
 
   addr &= ~mask;
 
-  /* Check whether [start, start+length-1] intersects [addr, addr+mask]. */
+  /* Check whether [start, start+length-1] intersects [addr, addr+mask].  */
   return start <= addr + mask && start + length - 1 >= addr;
 }
 
+/* Return the number of registers needed for a masked hardware watchpoint.  */
+
+static int
+ppc_linux_masked_watch_num_registers (struct target_ops *target,
+                                     CORE_ADDR addr, CORE_ADDR mask)
+{
+  if (!have_ptrace_hwdebug_interface ()
+          || (hwdebug_info.features & PPC_DEBUG_FEATURE_DATA_BP_MASK) == 0)
+    return -1;
+  else if ((mask & 0xC0000000) != 0xC0000000)
+    {
+      warning (_("The given mask covers kernel address space "
+                "and cannot be used.\n"));
+
+      return -2;
+    }
+  else
+    return 2;
+}
+
 static void
 ppc_linux_store_inferior_registers (struct target_ops *ops,
                                    struct regcache *regcache, int regno)
 {
-  /* Overload thread id onto process id */
-  int tid = TIDGET (inferior_ptid);
+  /* Overload thread id onto process id */
+  int tid = ptid_get_lwp (inferior_ptid);
 
-  /* No thread id, just use process id */
+  /* No thread id, just use process id */
   if (tid == 0)
-    tid = PIDGET (inferior_ptid);
+    tid = ptid_get_pid (inferior_ptid);
 
   if (regno >= 0)
     store_register (regcache, tid, regno);
@@ -2155,7 +2349,7 @@ ppc_linux_store_inferior_registers (struct target_ops *ops,
 
 /* Functions for transferring registers between a gregset_t or fpregset_t
    (see sys/ucontext.h) and gdb's regcache.  The word size is that used
-   by the ptrace interface, not the current program's ABI.  eg. If a
+   by the ptrace interface, not the current program's ABI.  Eg. if a
    powerpc64-linux gdb is being used to debug a powerpc32-linux app, we
    read or write 64-bit gregsets.  This is to suit the host libthread_db.  */
 
@@ -2207,9 +2401,9 @@ ppc_linux_target_wordsize (void)
 #ifdef __powerpc64__
   long msr;
 
-  int tid = TIDGET (inferior_ptid);
+  int tid = ptid_get_lwp (inferior_ptid);
   if (tid == 0)
-    tid = PIDGET (inferior_ptid);
+    tid = ptid_get_pid (inferior_ptid);
 
   errno = 0;
   msr = (long) ptrace (PTRACE_PEEKUSER, tid, PT_MSR * 8, 0);
@@ -2225,7 +2419,7 @@ ppc_linux_auxv_parse (struct target_ops *ops, gdb_byte **readptr,
                       gdb_byte *endptr, CORE_ADDR *typep, CORE_ADDR *valp)
 {
   int sizeof_auxv_field = ppc_linux_target_wordsize ();
-  enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch);
+  enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
   gdb_byte *ptr = *readptr;
 
   if (endptr == ptr)
@@ -2251,9 +2445,9 @@ ppc_linux_read_description (struct target_ops *ops)
   int isa205 = 0;
   int cell = 0;
 
-  int tid = TIDGET (inferior_ptid);
+  int tid = ptid_get_lwp (inferior_ptid);
   if (tid == 0)
-    tid = PIDGET (inferior_ptid);
+    tid = ptid_get_pid (inferior_ptid);
 
   if (have_ptrace_getsetevrregs)
     {
@@ -2295,7 +2489,7 @@ ppc_linux_read_description (struct target_ops *ops)
     }
 
   /* Power ISA 2.05 (implemented by Power 6 and newer processors) increases
-     the FPSCR from 32 bits to 64 bits. Even though Power 7 supports this
+     the FPSCR from 32 bits to 64 bits.  Even though Power 7 supports this
      ISA version, it doesn't have PPC_FEATURE_ARCH_2_05 set, only
      PPC_FEATURE_ARCH_2_06.  Since for now the only bits used in the higher
      half of the register are for Decimal Floating Point, we check if that
@@ -2313,7 +2507,8 @@ ppc_linux_read_description (struct target_ops *ops)
       else if (vsx)
        return isa205? tdesc_powerpc_isa205_vsx64l : tdesc_powerpc_vsx64l;
       else if (altivec)
-       return isa205? tdesc_powerpc_isa205_altivec64l : tdesc_powerpc_altivec64l;
+       return isa205
+         ? tdesc_powerpc_isa205_altivec64l : tdesc_powerpc_altivec64l;
 
       return isa205? tdesc_powerpc_isa205_64l : tdesc_powerpc_64l;
     }
@@ -2349,10 +2544,15 @@ _initialize_ppc_linux_nat (void)
   t->to_region_ok_for_hw_watchpoint = ppc_linux_region_ok_for_hw_watchpoint;
   t->to_insert_watchpoint = ppc_linux_insert_watchpoint;
   t->to_remove_watchpoint = ppc_linux_remove_watchpoint;
+  t->to_insert_mask_watchpoint = ppc_linux_insert_mask_watchpoint;
+  t->to_remove_mask_watchpoint = ppc_linux_remove_mask_watchpoint;
   t->to_stopped_by_watchpoint = ppc_linux_stopped_by_watchpoint;
   t->to_stopped_data_address = ppc_linux_stopped_data_address;
   t->to_watchpoint_addr_within_range = ppc_linux_watchpoint_addr_within_range;
-  t->to_can_accel_watchpoint_condition = ppc_linux_can_accel_watchpoint_condition;
+  t->to_can_accel_watchpoint_condition
+    = ppc_linux_can_accel_watchpoint_condition;
+  t->to_masked_watch_num_registers = ppc_linux_masked_watch_num_registers;
+  t->to_ranged_break_num_registers = ppc_linux_ranged_break_num_registers;
 
   t->to_read_description = ppc_linux_read_description;
   t->to_auxv_parse = ppc_linux_auxv_parse;
This page took 0.04687 seconds and 4 git commands to generate.