This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 2/2] Support the new PPC476 processor -- Arch Dependent


Hi,

This is the patch that implements the architecture-dependent (specific) logic 
for PowerPC, which will handle the creation/deletion of the new (and old) 
types of hardware breakpoints/watchpoints.  It also defines a bunch of new 
methods in the target_ops, so that other archs can implement them in the 
future.

Regards,

-- 
Sérgio Durigan Júnior
Linux on Power Toolchain - Software Engineer
Linux Technology Center - LTC
IBM Brazil

gdb/ChangeLog:

2009-16-12  Sergio Durigan Junior  <sergiodj@linux.vnet.ibm.com>

	* i386-nat.c (i386_region_ok_for_watchpoint): Adding `is_big_blob'
	parameter.

	* spu-multiarch.c (spu_region_ok_for_hw_watchpoint): Ditto.

	* ppc-linux-nat.c: Including `breakpoint.h'.
	(have_ptrace_new_debug_booke): New flag.
	(booke_debug_info): New variable.
	(max_slots_number): Ditto.
	(struct thread_points): New struct.
	(ppc_threads): New variable.
	(PPC_DEBUG_CURRENT_VERSION): New define.
	(ppc_linux_can_use_hw_breakpoint): Handling BookE processors.
	(ppc_linux_can_use_special_hw_point_p): New function.
	(ppc_linux_region_ok_for_hw_watchpoint): Adding the `is_big_blob'
	parameter.  Handling BookE processors.
	(booke_alloc_thread_points): New function.
	(booke_cmp_hw_point): Ditto.
	(booke_select_vector): Ditto.
	(booke_find_thread_points_by_tid): Ditto.
	(booke_find_thread_points_slot): Ditto.
	(booke_insert_point): Ditto.
	(booke_remove_point): Ditto.
	(booke_linux_insert_normal_hw_breakpoint): Ditto.
	(booke_linux_remove_normal_hw_breakpoint): Ditto.
	(booke_linux_insert_ranged_hw_breakpoint): Ditto.
	(booke_linux_remove_ranged_hw_breakpoint): Ditto.
	(booke_linux_insert_hw_breakpoint): Ditto.
	(booke_linux_remove_hw_breakpoint): Ditto.
	(ppc_linux_insert_hw_breakpoint): Ditto.
	(ppc_linux_remove_hw_breakpoint): Ditto.
	(HW_WATCH_RW_TRIGGER): New define.
	(booke_linux_insert_normal_watchpoint): New function.
	(booke_linux_remove_normal_watchpoint): Ditto.
	(booke_linux_insert_ranged_watchpoint): Ditto.
	(booke_linux_remove_ranged_watchpoint): Ditto.
	(booke_linux_insert_watchpoint): Ditto.
	(booke_linux_remove_watchpoint): Ditto.
	(booke_linux_insert_mask_watchpoint): Ditto.
	(booke_linux_remove_mask_watchpoint): Ditto.
	(booke_linux_fill_cond_mode): Ditto.
	(booke_linux_insert_cond_accel_watchpoint): Ditto.
	(booke_linux_remove_cond_accel_watchpoint): Ditto.
	(ppc_insert_watchpoint): Ditto.
	(ppc_remove_watchpoint): Ditto.
	(ppc_linux_insert_watchpoint): Handling BookE processors.
	(ppc_linux_remove_watchpoint): Handling BookE processors.
	(ppc_linux_insert_mask_watchpoint): New function.
	(ppc_linux_remove_mask_watchpoint): Ditto.
	(ppc_linux_insert_cond_accel_watchpoint): Ditto.
	(ppc_linux_remove_cond_accel_watchpoint): Ditto.
	(ppc_linux_new_thread): Handling non-BookE processors.
	(ppc_linux_stopped_data_address): Handling BookE processors.
	(ppc_linux_watchpoint_addr_within_range): Handling BookE processors
	with and without the new kernel interface.
	(booke_linux_get_watchpoint_cond_accel_addr): New function.
	(ppc_linux_get_watchpoint_cond_accel_addr): Ditto.
	(booke_linux_can_use_watchpoint_cond_accel_p): Ditto.
	(ppc_linux_can_use_watchpoint_cond_accel_p): Ditto.
	(ppc_linux_hw_point_extra_slot_count): Ditto.
	(ppc_linux_read_description): Querying the target to know if it
	supports the new kernel BookE interface.
	(_initialize_ppc_linux_nat): Initializing fields of the target
	operations.

	* target.c (default_region_ok_for_hw_watchpoint): Added `is_big_blob'
	parameter.
	(debug_to_region_ok_for_hw_watchpoint): Ditto.
	(update_current_target): Inserting the new methods.

	* target.h (struct target_ops <to_can_use_special_hw_point_p>,
	<to_can_use_watchpoint_cond_accel_p>, <to_insert_mask_watchpoint>,
	<to_remove_mask_watchpoint>, <to_insert_cond_accel_watchpoint>,
	<to_remove_cond_accel_watchpoint>,
	<to_get_watchpoint_cond_accel_addr>,
	<to_hw_point_extra_slot_count>): New callbacks.
	(TARGET_CAN_USE_SPECIAL_HW_POINT_P): New define.
	(TARGET_CAN_USE_WATCHPOINT_COND_ACCEL_P): Ditto.
	(TARGET_GET_WATCHPOINT_COND_ACCEL_ADDR): Ditto.
	(target_insert_mask_watchpoint): Ditto.
	(target_remove_mask_watchpoint): Ditto.
	(target_insert_cond_accel_watchpoint): Ditto.
	(target_remove_cond_accel_watchpoint): Ditto.
	(target_hw_point_extra_slot_count): Ditto.

diff --git a/gdb/i386-nat.c b/gdb/i386-nat.c
index edb78bf..d065c74 100644
--- a/gdb/i386-nat.c
+++ b/gdb/i386-nat.c
@@ -530,8 +530,8 @@ i386_remove_watchpoint (CORE_ADDR addr, int len, int type)
 /* Return non-zero if we can watch a memory region that starts at
    address ADDR and whose length is LEN bytes.  */
 
-static int
-i386_region_ok_for_watchpoint (CORE_ADDR addr, int len)
+int
+i386_region_ok_for_watchpoint (CORE_ADDR addr, int len, int is_big_blob)
 {
   int nregs;
 
diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c
index 47b74ad..296dfcd 100644
--- a/gdb/ppc-linux-nat.c
+++ b/gdb/ppc-linux-nat.c
@@ -28,6 +28,8 @@
 #include "target.h"
 #include "linux-nat.h"
 
+#include "breakpoint.h"
+
 #include <stdint.h>
 #include <sys/types.h>
 #include <sys/param.h>
@@ -100,7 +102,8 @@
 #define PTRACE_SETEVRREGS 21
 #endif
 
-/* Similarly for the hardware watchpoint support.  */
+/* Similarly for the hardware watchpoint support.  This request is used when
+   the BookE kernel interface is not available.  */
 #ifndef PTRACE_GET_DEBUGREG
 #define PTRACE_GET_DEBUGREG    25
 #endif
@@ -248,6 +251,10 @@ int have_ptrace_getsetregs = 1;
    them and gotten an error.  */
 int have_ptrace_getsetfpregs = 1;
 
+/* Non-zero if we support the new Kernel interface that enables
+   new BOOKE debugging resources.  */
+int have_ptrace_new_debug_booke = 1;
+
 /* *INDENT-OFF* */
 /* registers layout, as presented by the ptrace interface:
 PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5, PT_R6, PT_R7,
@@ -1270,66 +1277,751 @@ store_ppc_registers (const struct regcache *regcache, int tid)
     store_spe_register (regcache, tid, -1);
 }
 
+/* Fetch the AT_HWCAP entry from the aux vector.  */
+unsigned long ppc_linux_get_hwcap (void)
+{
+  CORE_ADDR field;
+
+  if (target_auxv_search (&current_target, AT_HWCAP, &field))
+    return (unsigned long) field;
+
+  return 0;
+}
+
+/* The cached DABR value, to install in new threads.
+   This variable is used when we are dealing with non-BookE
+   processors.  */
+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;
+
+/* Global variable that holds the maximum number of slots that the
+   kernel will use.  This is only used when the processor is BookE.  */
+static size_t max_slots_number = 0;
+
+/* This is an internal VEC created to store information about *points inserted
+   for each thread.  This is used for BookE processors.  */
+typedef struct thread_points
+  {
+    /* The TID to which this *point relates.  */
+    int tid;
+    /* Information about the *point, such as its address, type, etc.
+
+       Each element inside these vectors corresponds to a hardware
+       breakpoint or watchpoint in the thread represented by TID.  The
+       maximum size of these vectors is stored at MAX_SLOTS_NUMBER.  */
+    struct ppc_hw_breakpoint **hw_breaks;
+    struct ppc_hw_breakpoint **hw_watchs;
+  } *thread_points_p;
+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.  */
+#define PPC_DEBUG_CURRENT_VERSION 1
+
 static int
-ppc_linux_check_watch_resources (int type, int cnt, int ot)
+ppc_linux_can_use_hw_breakpoint (int type, int cnt, int ot)
 {
-  int tid;
-  ptid_t ptid = inferior_ptid;
+  int total_hw_wp, total_hw_bp;
 
-  /* DABR (data address breakpoint register) is optional for PPC variants.
-     Some variants have one DABR, others have none.  So CNT can't be larger
-     than 1.  */
-  if (cnt > 1)
-    return 0;
+  if (have_ptrace_new_debug_booke)
+    {
+      /* 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;
+    }
+  else
+    {
+      /* For PPC server processors, we accept 1 hardware watchpoint and 0
+	 hardware breakpoints.  */
+      total_hw_bp = 0;
+      total_hw_wp = 1;
+    }
 
-  /* 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);
-  if (tid == 0)
-    tid = PIDGET (ptid);
+  if (type == bp_hardware_watchpoint || type == bp_read_watchpoint
+      || type == bp_access_watchpoint || type == bp_watchpoint)
+    {
+      if (cnt > total_hw_wp)
+	return -1;
+    }
+  else if (type == bp_hardware_breakpoint)
+    {
+      if (cnt > total_hw_bp)
+	return -1;
+    }
+
+  if (!have_ptrace_new_debug_booke)
+    {
+      ptid_t ptid;
+      int tid;
+
+      /* 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);
+      if (tid == 0)
+	tid = PIDGET (ptid);
+
+      if (ptrace (PTRACE_SET_DEBUGREG, tid, 0, 0) == -1)
+	return 0;
+    }
 
-  if (ptrace (PTRACE_SET_DEBUGREG, tid, 0, 0) == -1)
-    return 0;
   return 1;
 }
 
-/* Fetch the AT_HWCAP entry from the aux vector.  */
-unsigned long ppc_linux_get_hwcap (void)
+static int
+ppc_linux_can_use_special_hw_point_p (enum hw_point_flag flag)
 {
-  CORE_ADDR field;
+  uint64_t features = booke_debug_info.features;
 
-  if (target_auxv_search (&current_target, AT_HWCAP, &field))
-    return (unsigned long) field;
+  if (!have_ptrace_new_debug_booke)
+    return 0;
+
+  switch (flag)
+    {
+    case HW_POINT_RANGED_BREAK:
+      return features & PPC_DEBUG_FEATURE_INSN_BP_RANGE;
+    case HW_POINT_RANGED_WATCH:
+      return features & PPC_DEBUG_FEATURE_DATA_BP_RANGE;
+    case HW_POINT_MASKED_WATCH:
+      return features & PPC_DEBUG_FEATURE_DATA_BP_MASK;
+    case HW_POINT_COND_HW_ACCEL:
+      return booke_debug_info.num_condition_regs > 0;
+    /* We also accept non-special *points.  */
+    case HW_POINT_NONE:
+      return 1;
+    }
 
   return 0;
 }
 
 static int
-ppc_linux_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
+ppc_linux_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len, int is_big_blob)
 {
   /* Handle sub-8-byte quantities.  */
   if (len <= 0)
     return 0;
 
+  /* DAC-based processors (i.e., embedded processors), like the PowerPC 440
+     have ranged watchpoints and can watch arbitrary lengths.  This takes
+     two hardware watchpoints though.  */
+  if (ppc_linux_can_use_special_hw_point_p (HW_POINT_RANGED_WATCH))
+    return is_big_blob ? 2 : 1;
   /* addr+len must fall in the 8 byte watchable region for DABR-based
-     processors.  DAC-based processors, like the PowerPC 440, will use
-     addresses aligned to 4-bytes due to the way the read/write flags are
-     passed at the moment.  */
-  if (((ppc_linux_get_hwcap () & PPC_FEATURE_BOOKE)
-      && (addr + len) > (addr & ~3) + 4)
-      || (addr + len) > (addr & ~7) + 8)
+     processors (i.e., server processors).  */
+  else if (addr + len > (addr & ~7) + 8)
     return 0;
 
   return 1;
 }
 
-/* The cached DABR value, to install in new threads.  */
-static long saved_dabr_value;
+/* This function allocates a thread_points that will hold information
+   about hardware *points for an specific TID.  */
+static struct thread_points *
+booke_alloc_thread_points (void)
+{
+  struct thread_points *p = xmalloc (sizeof (struct thread_points));
+  int size = max_slots_number + 1;
+
+  p->hw_breaks = xzalloc (size * sizeof (struct thread_points *));
+  p->hw_watchs = xzalloc (size * sizeof (struct thread_points *));
+
+  return p;
+}
+
+/* This function compares two ppc_hw_breakpoint structs field-by-field.  */
+static inline int
+booke_cmp_hw_point (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
+	  && a->condition_value == b->condition_value);
+}
+
+/* This function is used to select which vector (i.e., `hw_breaks' or
+   `hw_watchs') need to be used for the ppc_hw_breakpoint provided.  It
+   also sets the SIZE variable to the corresponding size of the vector.  */
+static void
+booke_select_vector (struct thread_points *p,
+		     struct ppc_hw_breakpoint *b,
+		     int *size, struct ppc_hw_breakpoint ***vector)
+{
+  *size = max_slots_number + 1;
+  if (b->trigger_type == PPC_BREAKPOINT_TRIGGER_EXECUTE)
+    /* Dealing with a hardware breakpoint.  */
+    *vector = p->hw_breaks;
+  else
+    /* Dealing with a hardware watchpoint.  */
+    *vector = p->hw_watchs;
+}
+
+/* This function can be used to retrieve a thread_points by
+   the TID of the related process/thread.  If nothing has been
+   found, it returns NULL.  */
+static struct thread_points *
+booke_find_thread_points_by_tid (int tid, int alloc_new)
+{
+  int i;
+  struct thread_points *t;
+
+  for (i = 0;
+       VEC_iterate (thread_points_p, ppc_threads, i, t);
+       i++)
+    if (t->tid == tid)
+      return t;
+
+  t = NULL;
+
+  /* Did the user request us to allocate a new point_item
+     if the wanted one does not exist?  */
+  if (alloc_new)
+    {
+      t = booke_alloc_thread_points ();
+      t->tid = tid;
+      VEC_safe_push (thread_points_p, ppc_threads, t);
+    }
+
+  return t;
+}
+
+/* This function finds the slot number where the ppc_hw_breakpoint B
+   is located inside the vector (`hw_breaks' or `hw_watchs').  It returns
+   the slot number if found, or issues an error call otherwise.  */
+static int
+booke_find_thread_points_slot (struct thread_points *p,
+			       struct ppc_hw_breakpoint *b)
+{
+  int i, size;
+  struct ppc_hw_breakpoint **t;
+
+  booke_select_vector (p, b, &size, &t);
+
+  for (i = 0; i < size; i++)
+    if (t[i] && booke_cmp_hw_point (t[i], b))
+      return i;
+
+  /* If we have reached this point, it means we were not able to
+     find the slot number for this specific *point.  It is an error,
+     and should be reported.  */
+  error (_("Could not find the slot for this specific \
+breakpoint/watchpoint (located at `0x%lx')."),
+	 (unsigned long) b->addr);
+
+  return -1;
+}
+
+/* This function is a generic wrapper that is responsible for inserting a
+   *point (i.e., calling `ptrace' in order to issue the request to the
+   kernel), and registering it internally at GDB.  */
+static void
+booke_insert_point (struct ppc_hw_breakpoint *b, int tid)
+{
+  struct ppc_hw_breakpoint *p = xmalloc (sizeof (struct ppc_hw_breakpoint));
+  struct ppc_hw_breakpoint **t;
+  struct cleanup *c = make_cleanup (xfree, p);
+  struct thread_points *h;
+  int slot, size;
+
+  memcpy (p, b, sizeof (struct ppc_hw_breakpoint));
+
+  errno = 0;
+  if ((slot = ptrace (PPC_PTRACE_SETHWDEBUG, tid, 0, p)) < 0)
+    perror_with_name (_("\n\
+Please review your watchpoints/breakpoints and make sure the mask, ranges \n\
+and addresses are within acceptable limits."));
+
+  /* Everything went fine, so we have to register this *point.  */
+  h = booke_find_thread_points_by_tid (tid, 1);
+  gdb_assert (h != NULL);
+
+  /* Registering the hardware *point.  */
+  booke_select_vector (h, p, &size, &t);
+  gdb_assert (t[slot] == NULL);
+  t[slot] = p;
+
+  discard_cleanups (c);
+}
+
+/* This function is a generic wrapper that is responsible for removing a
+   *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)
+{
+  struct ppc_hw_breakpoint **t;
+  struct thread_points *cur;
+  int slot, size;
+
+  cur = booke_find_thread_points_by_tid (tid, 0);
+  gdb_assert (cur != NULL);
+  slot = booke_find_thread_points_slot (cur, b);
+
+  errno = 0;
+  if (ptrace (PPC_PTRACE_DELHWDEBUG, tid, 0, slot) < 0)
+    perror_with_name (_("\n\
+Could not delete the breakpoint/watchpoint."));
+
+  /* Unregistering the hardware *point.  */
+  booke_select_vector (cur, b, &size, &t);
+  gdb_assert (t[slot] != NULL);
+  xfree (t[slot]);
+  t[slot] = NULL;
+}
+
+static int
+booke_linux_insert_normal_hw_breakpoint (unsigned long addr, int tid)
+{
+  struct ppc_hw_breakpoint p;
+
+  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) addr;
+  p.addr2           = 0;
+  p.condition_value = 0;
+
+  booke_insert_point (&p, tid);
+
+  return 0;
+}
+
+static int
+booke_linux_remove_normal_hw_breakpoint (unsigned long addr, int tid)
+{
+  struct ppc_hw_breakpoint p;
+
+  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) addr;
+  p.addr2           = 0;
+  p.condition_value = 0;
+
+  booke_remove_point (&p, tid);
+
+  return 0;
+}
+
+static int
+booke_linux_insert_ranged_hw_breakpoint (unsigned long begin,
+					 unsigned long end,
+					 int tid)
+{
+  struct ppc_hw_breakpoint p;
+
+  p.version         = PPC_DEBUG_CURRENT_VERSION;
+  p.trigger_type    = PPC_BREAKPOINT_TRIGGER_EXECUTE;
+  p.addr_mode       = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
+  p.condition_mode  = PPC_BREAKPOINT_CONDITION_NONE;
+  p.addr            = (uint64_t) begin;
+  p.addr2           = (uint64_t) end;
+  p.condition_value = 0;
+
+  booke_insert_point (&p, tid);
+
+  return 0;
+}
+
+static int
+booke_linux_remove_ranged_hw_breakpoint (unsigned long begin,
+					 unsigned long end,
+					 int tid)
+{
+  struct ppc_hw_breakpoint p;
+
+  p.version         = PPC_DEBUG_CURRENT_VERSION;
+  p.trigger_type    = PPC_BREAKPOINT_TRIGGER_EXECUTE;
+  p.addr_mode       = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
+  p.condition_mode  = PPC_BREAKPOINT_CONDITION_NONE;
+  p.addr            = (uint64_t) begin;
+  p.addr2           = (uint64_t) end;
+  p.condition_value = 0;
+
+  booke_remove_point (&p, tid);
+
+  return 0;
+}
+
+static int
+booke_linux_insert_hw_breakpoint (struct gdbarch *gdbarch,
+				  struct bp_target_info *bp_tgt)
+{
+  struct lwp_info *lp;
+  ptid_t ptid;
+  int ret;
+
+  if (bp_tgt->length == 0)
+    {
+      unsigned long addr = (unsigned long) bp_tgt->placed_address;
+
+      ALL_LWPS (lp, ptid)
+	ret = booke_linux_insert_normal_hw_breakpoint (addr, TIDGET (ptid));
+    }
+  else
+    {
+      unsigned long begin = (unsigned long) bp_tgt->placed_address,
+		    end = (unsigned long) bp_tgt->placed_address +
+		      (unsigned long) bp_tgt->length;
+
+      ALL_LWPS (lp, ptid)
+	ret = booke_linux_insert_ranged_hw_breakpoint (begin, end,
+						       TIDGET (ptid));
+    }
+
+  return ret;
+}
+
+static int
+booke_linux_remove_hw_breakpoint (struct gdbarch *gdbarch,
+				  struct bp_target_info *bp_tgt)
+{
+  struct lwp_info *lp;
+  ptid_t ptid;
+  int ret;
+
+  if (bp_tgt->length == 0)
+    {
+      unsigned long addr = (unsigned long) bp_tgt->placed_address;
+
+      ALL_LWPS (lp, ptid)
+	ret = booke_linux_remove_normal_hw_breakpoint (addr, TIDGET (ptid));
+    }
+  else
+    {
+      unsigned long begin = (unsigned long) bp_tgt->placed_address,
+		    end = (unsigned long) bp_tgt->placed_address +
+		      (unsigned long) bp_tgt->length;
+
+      ALL_LWPS (lp, ptid)
+	ret = booke_linux_remove_ranged_hw_breakpoint (begin, end,
+						       TIDGET (ptid));
+    }
+
+  return ret;
+}
+
+static int
+ppc_linux_insert_hw_breakpoint (struct gdbarch *gdbarch,
+				struct bp_target_info *bp_tgt)
+{
+  if (have_ptrace_new_debug_booke)
+    return booke_linux_insert_hw_breakpoint (gdbarch, bp_tgt);
+
+  return -1;
+}
+
+static int
+ppc_linux_remove_hw_breakpoint (struct gdbarch *gdbarch,
+				struct bp_target_info *bp_tgt)
+{
+  if (have_ptrace_new_debug_booke)
+    return booke_linux_remove_hw_breakpoint (gdbarch, bp_tgt);
+
+  return -1;
+}
+
+#define HW_WATCH_RW_TRIGGER(t, rw) \
+  if (rw == hw_read) \
+    t = PPC_BREAKPOINT_TRIGGER_READ; \
+  else if (rw == hw_write) \
+    t = PPC_BREAKPOINT_TRIGGER_WRITE; \
+  else \
+    t = PPC_BREAKPOINT_TRIGGER_READ | PPC_BREAKPOINT_TRIGGER_WRITE;
+
+static int
+booke_linux_insert_normal_watchpoint (unsigned long addr, int tid, int rw)
+{
+  struct ppc_hw_breakpoint p;
+  uint32_t trigger;
+
+  HW_WATCH_RW_TRIGGER (trigger, rw);
+  
+  p.version         = PPC_DEBUG_CURRENT_VERSION;
+  p.trigger_type    = trigger;
+  p.addr_mode       = PPC_BREAKPOINT_MODE_EXACT;
+  p.condition_mode  = PPC_BREAKPOINT_CONDITION_NONE;
+  p.addr            = (uint64_t) addr;
+  p.addr2           = 0;
+  p.condition_value = 0;
+
+  booke_insert_point (&p, tid);
+
+  return 0;
+}
+
+static int
+booke_linux_remove_normal_watchpoint (unsigned long addr, int tid, int rw)
+{
+  struct ppc_hw_breakpoint p;
+  uint32_t trigger;
+
+  HW_WATCH_RW_TRIGGER (trigger, rw);
+  
+  p.version         = PPC_DEBUG_CURRENT_VERSION;
+  p.trigger_type    = trigger;
+  p.addr_mode       = PPC_BREAKPOINT_MODE_EXACT;
+  p.condition_mode  = PPC_BREAKPOINT_CONDITION_NONE;
+  p.addr            = (uint64_t) addr;
+  p.addr2           = 0;
+  p.condition_value = 0;
+
+  booke_remove_point (&p, tid);
+
+  return 0;
+}
+
+static int
+booke_linux_insert_ranged_watchpoint (unsigned long begin,
+                                      unsigned long end,
+                                      int tid, int rw)
+{
+  struct ppc_hw_breakpoint p;
+  uint32_t trigger;
+
+  HW_WATCH_RW_TRIGGER (trigger, rw);
+  
+  p.version         = PPC_DEBUG_CURRENT_VERSION;
+  p.trigger_type    = trigger;
+  p.addr_mode       = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
+  p.condition_mode  = PPC_BREAKPOINT_CONDITION_NONE;
+  p.addr            = (uint64_t) begin;
+  p.addr2           = (uint64_t) end;
+  p.condition_value = 0;
+
+  booke_insert_point (&p, tid);
+
+  return 0;
+}
+
+static int
+booke_linux_remove_ranged_watchpoint (unsigned long begin,
+                                      unsigned long end,
+                                      int tid, int rw)
+{
+  struct ppc_hw_breakpoint p;
+  uint32_t trigger;
+
+  HW_WATCH_RW_TRIGGER (trigger, rw);
+  
+  p.version         = PPC_DEBUG_CURRENT_VERSION;
+  p.trigger_type    = trigger;
+  p.addr_mode       = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
+  p.condition_mode  = PPC_BREAKPOINT_CONDITION_NONE;
+  p.addr            = (uint64_t) begin;
+  p.addr2           = (uint64_t) end;
+  p.condition_value = 0;
+
+  booke_remove_point (&p, tid);
+
+  return 0;
+}
+
+static int
+booke_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw)
+{
+  struct lwp_info *lp;
+  ptid_t ptid;
+  int ret;
+
+  if (len <= 4)
+    {
+      unsigned long a = (unsigned long) addr;
+
+      ALL_LWPS (lp, ptid)
+	ret = booke_linux_insert_normal_watchpoint (a, TIDGET (ptid), rw);
+    }
+  else
+    {
+      unsigned long begin = (unsigned long) addr,
+                    end = (unsigned long) addr + (unsigned long) len;
+
+      ALL_LWPS (lp, ptid)
+	ret = booke_linux_insert_ranged_watchpoint (begin, end,
+						    TIDGET (ptid), rw);
+    }
+    return ret;
+}
+
+static int
+booke_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw)
+{
+  struct lwp_info *lp;
+  ptid_t ptid;
+  int ret;
+
+  if (len <= 4)
+    {
+      unsigned long a = (unsigned long) addr;
+
+      ALL_LWPS (lp, ptid)
+	ret = booke_linux_remove_normal_watchpoint (a, TIDGET (ptid), rw);
+    }
+  else
+    {
+      unsigned long begin = (unsigned long) addr,
+                    end = (unsigned long) addr + (unsigned long) len;
+
+      ALL_LWPS (lp, ptid)
+	ret = booke_linux_remove_ranged_watchpoint (begin, end,
+						    TIDGET (ptid), rw);
+    }
+    return ret;
+}
+
+static int
+booke_linux_insert_mask_watchpoint (CORE_ADDR addr, int len, int rw,
+				    CORE_ADDR mask)
+{
+  struct ppc_hw_breakpoint p;
+  uint32_t trigger;
+  unsigned long a = (unsigned long) addr,
+		m = (unsigned long) mask;
+  struct lwp_info *lp;
+  ptid_t ptid;
+
+  HW_WATCH_RW_TRIGGER (trigger, rw);
+  
+  p.version         = PPC_DEBUG_CURRENT_VERSION;
+  p.trigger_type    = trigger;
+  p.addr_mode       = PPC_BREAKPOINT_MODE_MASK;
+  p.condition_mode  = PPC_BREAKPOINT_CONDITION_NONE;
+  p.addr            = (uint64_t) a;
+  p.addr2           = (uint64_t) m;
+  p.condition_value = 0;
+
+  ALL_LWPS (lp, ptid)
+    booke_insert_point (&p, TIDGET (ptid));
+
+  return 0;
+}
+
+static int
+booke_linux_remove_mask_watchpoint (CORE_ADDR addr, int len, int rw,
+				    CORE_ADDR mask)
+{
+  struct ppc_hw_breakpoint p;
+  uint32_t trigger;
+  unsigned long a = (unsigned long) addr,
+		m = (unsigned long) mask;
+  struct lwp_info *lp;
+  ptid_t ptid;
+
+  HW_WATCH_RW_TRIGGER (trigger, rw);
+  
+  p.version         = PPC_DEBUG_CURRENT_VERSION;
+  p.trigger_type    = trigger;
+  p.addr_mode       = PPC_BREAKPOINT_MODE_MASK;
+  p.condition_mode  = PPC_BREAKPOINT_CONDITION_NONE;
+  p.addr            = (uint64_t) a;
+  p.addr2           = (uint64_t) m;
+  p.condition_value = 0;
+
+  ALL_LWPS (lp, ptid)
+    booke_remove_point (&p, TIDGET (ptid));
+
+  return 0;
+}
+
+static inline uint32_t
+booke_linux_fill_cond_mode (int byte_to_enable)
+{
+  uint32_t mode = PPC_BREAKPOINT_CONDITION_AND;
+
+  switch (byte_to_enable)
+    {
+    case 0:
+      mode |= PPC_BREAKPOINT_CONDITION_BE (0);
+    case 1:
+      mode |= PPC_BREAKPOINT_CONDITION_BE (1);
+    case 2:
+      mode |= PPC_BREAKPOINT_CONDITION_BE (2);
+    case 3:
+      mode |= PPC_BREAKPOINT_CONDITION_BE (3);
+      break;
+    default:
+      error (_("Wrong byte to enable for the hardware watchpoint \
+with a condition associated."));
+    }
+
+  return mode;
+}
+
+static int
+booke_linux_insert_cond_accel_watchpoint (CORE_ADDR addr, int len, int rw,
+					  CORE_ADDR cond)
+{
+  struct ppc_hw_breakpoint p;
+  uint32_t trigger;
+  unsigned long a = (unsigned long) addr,
+		c = (unsigned long) cond;
+  struct lwp_info *lp;
+  ptid_t ptid;
+  int byte_to_enable;
+
+  HW_WATCH_RW_TRIGGER (trigger, rw);
+  
+  byte_to_enable = a % 4;
+  c >>= (byte_to_enable * 8);
+
+  p.version         = PPC_DEBUG_CURRENT_VERSION;
+  p.trigger_type    = trigger;
+  p.addr_mode       = PPC_BREAKPOINT_MODE_EXACT;
+  p.condition_mode  = booke_linux_fill_cond_mode (byte_to_enable);
+  p.addr            = (uint64_t) a;
+  p.addr2           = 0;
+  p.condition_value = (uint64_t) c;
+
+  ALL_LWPS (lp, ptid)
+    booke_insert_point (&p, TIDGET (ptid));
+
+  return 0;
+}
+
+static int
+booke_linux_remove_cond_accel_watchpoint (CORE_ADDR addr, int len, int rw,
+					  CORE_ADDR cond)
+{
+  struct ppc_hw_breakpoint p;
+  uint32_t trigger;
+  unsigned long a = (unsigned long) addr,
+		c = (unsigned long) cond;
+  struct lwp_info *lp;
+  ptid_t ptid;
+  int byte_to_enable;
+
+  HW_WATCH_RW_TRIGGER (trigger, rw);
+  
+  byte_to_enable = a % 4;
+  c >>= (byte_to_enable * 8);
+
+  p.version         = PPC_DEBUG_CURRENT_VERSION;
+  p.trigger_type    = trigger;
+  p.addr_mode       = PPC_BREAKPOINT_MODE_EXACT;
+  p.condition_mode  = booke_linux_fill_cond_mode (byte_to_enable);
+  p.addr            = (uint64_t) a;
+  p.addr2           = 0;
+  p.condition_value = (uint64_t) c;
+
+  ALL_LWPS (lp, ptid)
+    booke_remove_point (&p, TIDGET (ptid));
+
+  return 0;
+}
 
 /* Set a watchpoint of type TYPE at address ADDR.  */
 static int
-ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw)
+ppc_insert_watchpoint (CORE_ADDR addr, int len, int rw)
 {
   struct lwp_info *lp;
   ptid_t ptid;
@@ -1337,19 +2029,19 @@ ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw)
   long read_mode, write_mode;
 
   if (ppc_linux_get_hwcap () & PPC_FEATURE_BOOKE)
-  {
-  /* PowerPC 440 requires only the read/write flags to be passed
-     to the kernel.  */
-    read_mode  = 1;
-    write_mode = 2;
-  }
+    {
+      /* PowerPC 440 requires only the read/write flags to be passed
+	 to the kernel.  */
+      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;
-    write_mode = 6;
-  }
+    {
+      /* PowerPC 970 and other DABR-based processors are required to pass
+	 the Breakpoint Translation bit together with the flags.  */
+      read_mode  = 5;
+      write_mode = 6;
+    }
 
   dabr_value = addr & ~(read_mode | write_mode);
   switch (rw)
@@ -1378,7 +2070,7 @@ ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw)
 }
 
 static int
-ppc_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw)
+ppc_remove_watchpoint (CORE_ADDR addr, int len, int rw)
 {
   struct lwp_info *lp;
   ptid_t ptid;
@@ -1391,10 +2083,70 @@ ppc_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw)
   return 0;
 }
 
+static int
+ppc_linux_insert_watchpoint (CORE_ADDR addr, int len,
+                             int rw)
+{
+  if (have_ptrace_new_debug_booke)
+    return booke_linux_insert_watchpoint (addr, len, rw);
+
+  return ppc_insert_watchpoint (addr, len, rw);
+}
+
+static int
+ppc_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw)
+{
+  if (have_ptrace_new_debug_booke)
+    return booke_linux_remove_watchpoint (addr, len, rw);
+
+  return ppc_remove_watchpoint (addr, len, rw);
+}
+
+static int
+ppc_linux_insert_mask_watchpoint (CORE_ADDR addr, int len, int rw,
+				  CORE_ADDR mask)
+{
+  if (have_ptrace_new_debug_booke)
+    return booke_linux_insert_mask_watchpoint (addr, len, rw, mask);
+
+  return -1;
+}
+
+static int
+ppc_linux_remove_mask_watchpoint (CORE_ADDR addr, int len, int rw,
+				  CORE_ADDR mask)
+{
+  if (have_ptrace_new_debug_booke)
+    return booke_linux_remove_mask_watchpoint (addr, len, rw, mask);
+
+  return -1;
+}
+
+static int
+ppc_linux_insert_cond_accel_watchpoint (CORE_ADDR addr, int len,
+					int rw, CORE_ADDR cond)
+{
+  if (have_ptrace_new_debug_booke)
+    return booke_linux_insert_cond_accel_watchpoint (addr, len, rw, cond);
+
+  return -1;
+}
+
+static int
+ppc_linux_remove_cond_accel_watchpoint (CORE_ADDR addr, int len,
+					int rw, CORE_ADDR cond)
+{
+  if (have_ptrace_new_debug_booke)
+    return booke_linux_remove_cond_accel_watchpoint (addr, len, rw, cond);
+
+  return -1;
+}
+
 static void
 ppc_linux_new_thread (ptid_t ptid)
 {
-  ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0, saved_dabr_value);
+  if (!have_ptrace_new_debug_booke)
+    ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0, saved_dabr_value);
 }
 
 static int
@@ -1408,6 +2160,21 @@ ppc_linux_stopped_data_address (struct target_ops *target, CORE_ADDR *addr_p)
       || (siginfo_p->si_code & 0xffff) != 0x0004 /* TRAP_HWBKPT */)
     return 0;
 
+  if (have_ptrace_new_debug_booke)
+    {
+      struct thread_points *p;
+      /* The index (or slot) of the *point is passed in the si_errno field.  */
+      int slot = siginfo_p->si_errno;
+
+      p = booke_find_thread_points_by_tid (TIDGET (inferior_ptid), 0);
+
+      /* If the SLOT position on hw_break vector is not NULL, it means
+	 that this specific *point is a hardware breakpoint.  So, we
+	 should return 0.  */
+      if (p && p->hw_breaks[slot])
+	return 0;
+    }
+
   *addr_p = (CORE_ADDR) (uintptr_t) siginfo_p->si_addr;
   return 1;
 }
@@ -1426,7 +2193,10 @@ ppc_linux_watchpoint_addr_within_range (struct target_ops *target,
 {
   int mask;
 
-  if (ppc_linux_get_hwcap () & PPC_FEATURE_BOOKE)
+  if (have_ptrace_new_debug_booke
+      && ppc_linux_get_hwcap () & PPC_FEATURE_BOOKE)
+    return start <= addr && start + length >= addr;
+  else if (ppc_linux_get_hwcap () & PPC_FEATURE_BOOKE)
     mask = 3;
   else
     mask = 7;
@@ -1437,6 +2207,88 @@ ppc_linux_watchpoint_addr_within_range (struct target_ops *target,
   return start <= addr + mask && start + length - 1 >= addr;
 }
 
+static int
+booke_linux_get_watchpoint_cond_accel_addr (struct bp_location *b,
+					    CORE_ADDR *addr)
+{
+  return (default_watch_address_if_address_equal_literal_p (b, addr)
+          || default_watch_var_if_var_equal_literal_p (b, addr)
+          || default_watch_var_if_address_equal_literal_p (b, addr)
+          || default_watch_address_if_var_equal_literal_p (b, addr));
+}
+
+static int
+ppc_linux_get_watchpoint_cond_accel_addr (struct bp_location *b,
+					  CORE_ADDR *addr)
+{
+  if (have_ptrace_new_debug_booke)
+    return booke_linux_get_watchpoint_cond_accel_addr (b, addr);
+
+  *addr = 0;
+  return 0;
+}
+
+static int
+booke_linux_can_use_watchpoint_cond_accel_p (struct bp_location *b)
+{
+  struct thread_points *p;
+  int tid = TIDGET (inferior_ptid);
+  int cnt = booke_debug_info.num_condition_regs, i;
+  CORE_ADDR tmp_value;
+
+  p = booke_find_thread_points_by_tid (tid, 0);
+
+  if (p)
+    {
+      for (i = 0; i < booke_debug_info.num_data_bps; i++)
+	if (p->hw_watchs[i]
+	    && p->hw_watchs[i]->condition_mode != PPC_BREAKPOINT_CONDITION_NONE)
+	  cnt--;
+
+      /* There are no available slots now.  */
+      if (cnt <= 0)
+	return 0;
+    }
+
+  /* We have to know if the condition associated with the bp_location
+     can be hardware-accelerated.  */
+  return (booke_linux_get_watchpoint_cond_accel_addr (b, &tmp_value));
+}
+
+static int
+ppc_linux_can_use_watchpoint_cond_accel_p (struct bp_location *b)
+{
+  if (have_ptrace_new_debug_booke)
+    return booke_linux_can_use_watchpoint_cond_accel_p (b);
+
+  return 0;
+}
+
+static int
+ppc_linux_hw_point_extra_slot_count (enum hw_point_flag flag)
+{
+  /* If this *point is a:
+     
+     - Masked hardware watchpoint,
+     - Ranged hardware watchpoint, or
+     - Ranged hardware breakpoint
+
+     then it uses 1 extra slot.  */
+  switch (flag)
+    {
+    case HW_POINT_MASKED_WATCH:
+    case HW_POINT_RANGED_WATCH:
+    case HW_POINT_RANGED_BREAK:
+      return 1;
+    default:
+      return 0;
+    }
+
+  /* Otherwise, it is a normal *point and does not use
+     extra slots.  */
+  return 0;
+}
+
 static void
 ppc_linux_store_inferior_registers (struct target_ops *ops,
 				    struct regcache *regcache, int regno)
@@ -1595,6 +2447,20 @@ ppc_linux_read_description (struct target_ops *ops)
 	perror_with_name (_("Unable to fetch AltiVec registers"));
     }
 
+  /* Check for kernel support for new BOOKE debugging registers.  */
+  if (ptrace (PPC_PTRACE_GETHWDBGINFO, tid, 0, &booke_debug_info) >= 0)
+    {
+      have_ptrace_new_debug_booke = 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 new BOOKE registers support.  */
+      have_ptrace_new_debug_booke = 0;
+      memset (&booke_debug_info, 0, sizeof (struct ppc_debug_info));
+    }
+
   /* 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
      ISA version, it doesn't have PPC_FEATURE_ARCH_2_05 set, only
@@ -1643,14 +2509,26 @@ _initialize_ppc_linux_nat (void)
   t->to_fetch_registers = ppc_linux_fetch_inferior_registers;
   t->to_store_registers = ppc_linux_store_inferior_registers;
 
-  /* Add our watchpoint methods.  */
-  t->to_can_use_hw_breakpoint = ppc_linux_check_watch_resources;
+  /* Add our breakpoint/watchpoint methods.  */
+  t->to_can_use_hw_breakpoint = ppc_linux_can_use_hw_breakpoint;
+  t->to_can_use_special_hw_point_p = ppc_linux_can_use_special_hw_point_p;
+  t->to_insert_hw_breakpoint = booke_linux_insert_hw_breakpoint;
+  t->to_remove_hw_breakpoint = booke_linux_remove_hw_breakpoint;
   t->to_region_ok_for_hw_watchpoint = ppc_linux_region_ok_for_hw_watchpoint;
+  t->to_get_watchpoint_cond_accel_addr =
+    ppc_linux_get_watchpoint_cond_accel_addr;
+  t->to_can_use_watchpoint_cond_accel_p =
+    ppc_linux_can_use_watchpoint_cond_accel_p;
   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_insert_cond_accel_watchpoint = ppc_linux_insert_cond_accel_watchpoint;
+  t->to_remove_cond_accel_watchpoint = ppc_linux_remove_cond_accel_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_hw_point_extra_slot_count = ppc_linux_hw_point_extra_slot_count;
 
   t->to_read_description = ppc_linux_read_description;
   t->to_auxv_parse = ppc_linux_auxv_parse;
diff --git a/gdb/spu-multiarch.c b/gdb/spu-multiarch.c
index b5d2ee6..0f23e07 100644
--- a/gdb/spu-multiarch.c
+++ b/gdb/spu-multiarch.c
@@ -121,7 +121,7 @@ spu_thread_architecture (struct target_ops *ops, ptid_t ptid)
 
 /* Override the to_region_ok_for_hw_watchpoint routine.  */
 static int
-spu_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
+spu_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len, int is_big_blob)
 {
   struct target_ops *ops_beneath = find_target_beneath (&spu_ops);
   while (ops_beneath && !ops_beneath->to_region_ok_for_hw_watchpoint)
@@ -132,7 +132,8 @@ spu_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
     return 0;
 
   if (ops_beneath)
-    return ops_beneath->to_region_ok_for_hw_watchpoint (addr, len);
+    return ops_beneath->to_region_ok_for_hw_watchpoint (addr, len,
+		    is_big_blob);
 
   return 0;
 }
diff --git a/gdb/target.c b/gdb/target.c
index cd1614b..9f4a3fc 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -53,7 +53,7 @@ static void default_terminal_info (char *, int);
 static int default_watchpoint_addr_within_range (struct target_ops *,
 						 CORE_ADDR, CORE_ADDR, int);
 
-static int default_region_ok_for_hw_watchpoint (CORE_ADDR, int);
+static int default_region_ok_for_hw_watchpoint (CORE_ADDR, int, int);
 
 static int nosymbol (char *, CORE_ADDR *);
 
@@ -131,7 +131,7 @@ static int debug_to_stopped_data_address (struct target_ops *, CORE_ADDR *);
 static int debug_to_watchpoint_addr_within_range (struct target_ops *,
 						  CORE_ADDR, CORE_ADDR, int);
 
-static int debug_to_region_ok_for_hw_watchpoint (CORE_ADDR, int);
+static int debug_to_region_ok_for_hw_watchpoint (CORE_ADDR, int, int);
 
 static void debug_to_terminal_init (void);
 
@@ -620,16 +620,24 @@ update_current_target (void)
       INHERIT (to_insert_breakpoint, t);
       INHERIT (to_remove_breakpoint, t);
       INHERIT (to_can_use_hw_breakpoint, t);
+      INHERIT (to_can_use_special_hw_point_p, t);
+      INHERIT (to_can_use_watchpoint_cond_accel_p, t);
       INHERIT (to_insert_hw_breakpoint, t);
       INHERIT (to_remove_hw_breakpoint, t);
       INHERIT (to_insert_watchpoint, t);
       INHERIT (to_remove_watchpoint, t);
+      INHERIT (to_insert_mask_watchpoint, t);
+      INHERIT (to_remove_mask_watchpoint, t);
+      INHERIT (to_insert_cond_accel_watchpoint, t);
+      INHERIT (to_remove_cond_accel_watchpoint, t);
+      INHERIT (to_get_watchpoint_cond_accel_addr, t);
       INHERIT (to_stopped_data_address, t);
       INHERIT (to_have_steppable_watchpoint, t);
       INHERIT (to_have_continuable_watchpoint, t);
       INHERIT (to_stopped_by_watchpoint, t);
       INHERIT (to_watchpoint_addr_within_range, t);
       INHERIT (to_region_ok_for_hw_watchpoint, t);
+      INHERIT (to_hw_point_extra_slot_count, t);
       INHERIT (to_terminal_init, t);
       INHERIT (to_terminal_inferior, t);
       INHERIT (to_terminal_ours_for_output, t);
@@ -725,6 +733,12 @@ update_current_target (void)
   de_fault (to_can_use_hw_breakpoint,
 	    (int (*) (int, int, int))
 	    return_zero);
+  de_fault (to_can_use_special_hw_point_p,
+	    (int (*) (enum hw_point_flag))
+	    return_zero);
+  de_fault (to_can_use_watchpoint_cond_accel_p,
+	    (int (*) (struct bp_location *))
+	    return_zero);
   de_fault (to_insert_hw_breakpoint,
 	    (int (*) (struct gdbarch *, struct bp_target_info *))
 	    return_minus_one);
@@ -737,6 +751,18 @@ update_current_target (void)
   de_fault (to_remove_watchpoint,
 	    (int (*) (CORE_ADDR, int, int))
 	    return_minus_one);
+  de_fault (to_insert_mask_watchpoint,
+            (int (*) (CORE_ADDR, int, int, CORE_ADDR))
+            return_minus_one);
+  de_fault (to_remove_mask_watchpoint,
+            (int (*) (CORE_ADDR, int, int, CORE_ADDR))
+            return_minus_one);
+  de_fault (to_insert_cond_accel_watchpoint,
+	    (int (*) (CORE_ADDR, int, int, CORE_ADDR))
+	    return_minus_one);
+  de_fault (to_remove_cond_accel_watchpoint,
+	    (int (*) (CORE_ADDR, int, int, CORE_ADDR))
+	    return_minus_one);
   de_fault (to_stopped_by_watchpoint,
 	    (int (*) (void))
 	    return_zero);
@@ -747,6 +773,12 @@ update_current_target (void)
 	    default_watchpoint_addr_within_range);
   de_fault (to_region_ok_for_hw_watchpoint,
 	    default_region_ok_for_hw_watchpoint);
+  de_fault (to_hw_point_extra_slot_count,
+            (int (*) (enum hw_point_flag))
+            return_zero);
+  de_fault (to_get_watchpoint_cond_accel_addr,
+	    (int (*) (struct bp_location *, CORE_ADDR *))
+	    return_zero);
   de_fault (to_terminal_init,
 	    (void (*) (void))
 	    target_ignore);
@@ -2598,7 +2630,7 @@ Can't determine the current address space of thread %s\n",
 }
 
 static int
-default_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
+default_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len, int is_big_blob)
 {
   return (len <= gdbarch_ptr_bit (target_gdbarch) / TARGET_CHAR_BIT);
 }
@@ -3128,11 +3160,11 @@ debug_to_can_use_hw_breakpoint (int type, int cnt, int from_tty)
 }
 
 static int
-debug_to_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
+debug_to_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len, int is_big_blob)
 {
   CORE_ADDR retval;
 
-  retval = debug_target.to_region_ok_for_hw_watchpoint (addr, len);
+  retval = debug_target.to_region_ok_for_hw_watchpoint (addr, len, is_big_blob);
 
   fprintf_unfiltered (gdb_stdlog,
 		      "target_region_ok_for_hw_watchpoint (%ld, %ld) = 0x%lx\n",
diff --git a/gdb/target.h b/gdb/target.h
index ebe6056..027c380 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -32,6 +32,11 @@ struct bp_target_info;
 struct regcache;
 struct target_section_table;
 
+struct bp_location;
+struct breakpoint;
+
+enum hw_point_flag;
+
 /* This include file defines the interface between the main part
    of the debugger, and the part which is target-specific, or
    specific to the communications interface between us and the
@@ -400,17 +405,26 @@ struct target_ops
     int (*to_insert_breakpoint) (struct gdbarch *, struct bp_target_info *);
     int (*to_remove_breakpoint) (struct gdbarch *, struct bp_target_info *);
     int (*to_can_use_hw_breakpoint) (int, int, int);
+    int (*to_can_use_special_hw_point_p) (enum hw_point_flag);
+    int (*to_can_use_watchpoint_cond_accel_p) (struct bp_location *);
     int (*to_insert_hw_breakpoint) (struct gdbarch *, struct bp_target_info *);
     int (*to_remove_hw_breakpoint) (struct gdbarch *, struct bp_target_info *);
     int (*to_remove_watchpoint) (CORE_ADDR, int, int);
     int (*to_insert_watchpoint) (CORE_ADDR, int, int);
+    int (*to_insert_mask_watchpoint) (CORE_ADDR, int, int, CORE_ADDR);
+    int (*to_remove_mask_watchpoint) (CORE_ADDR, int, int, CORE_ADDR);
+    int (*to_insert_cond_accel_watchpoint) (CORE_ADDR, int, int, CORE_ADDR);
+    int (*to_remove_cond_accel_watchpoint) (CORE_ADDR, int, int, CORE_ADDR);
     int (*to_stopped_by_watchpoint) (void);
     int to_have_steppable_watchpoint;
     int to_have_continuable_watchpoint;
     int (*to_stopped_data_address) (struct target_ops *, CORE_ADDR *);
     int (*to_watchpoint_addr_within_range) (struct target_ops *,
 					    CORE_ADDR, CORE_ADDR, int);
-    int (*to_region_ok_for_hw_watchpoint) (CORE_ADDR, int);
+    int (*to_get_watchpoint_cond_accel_addr) (struct bp_location *,
+						    CORE_ADDR *);
+    int (*to_region_ok_for_hw_watchpoint) (CORE_ADDR, int, int);
+    int (*to_hw_point_extra_slot_count) (enum hw_point_flag);
     void (*to_terminal_init) (void);
     void (*to_terminal_inferior) (void);
     void (*to_terminal_ours_for_output) (void);
@@ -1184,9 +1198,29 @@ extern char *normal_pid_to_str (ptid_t ptid);
 #define target_can_use_hardware_watchpoint(TYPE,CNT,OTHERTYPE) \
  (*current_target.to_can_use_hw_breakpoint) (TYPE, CNT, OTHERTYPE);
 
-#define target_region_ok_for_hw_watchpoint(addr, len) \
-    (*current_target.to_region_ok_for_hw_watchpoint) (addr, len)
-
+/* Returns non-zero if the target supports the special type of hardware
+   breakpoint/watchpoint represented by FLAG.  */
+#ifndef TARGET_CAN_USE_SPECIAL_HW_POINT_P
+#define TARGET_CAN_USE_SPECIAL_HW_POINT_P(flag) \
+  (*current_target.to_can_use_special_hw_point_p) (flag)
+#endif
+
+#ifndef TARGET_REGION_OK_FOR_HW_WATCHPOINT
+#define TARGET_REGION_OK_FOR_HW_WATCHPOINT(addr, len, is_big_blob) \
+    (*current_target.to_region_ok_for_hw_watchpoint) (addr, len, is_big_blob)
+#endif
+
+/* Returns greater than zero if the target supports hardware-accelerated
+   condition.  */
+#ifndef TARGET_CAN_USE_WATCHPOINT_COND_ACCEL_P
+#define TARGET_CAN_USE_WATCHPOINT_COND_ACCEL_P(loc) \
+  (*current_target.to_can_use_watchpoint_cond_accel_p) (loc)
+#endif
+
+#ifndef TARGET_GET_WATCHPOINT_COND_ACCEL_ADDR
+#define TARGET_GET_WATCHPOINT_COND_ACCEL_ADDR(loc, addr) \
+  (*current_target.to_get_watchpoint_cond_accel_addr) (loc, addr)
+#endif
 
 /* Set/clear a hardware watchpoint starting at ADDR, for LEN bytes.  TYPE is 0
    for write, 1 for read, and 2 for read/write accesses.  Returns 0 for
@@ -1198,6 +1232,29 @@ extern char *normal_pid_to_str (ptid_t ptid);
 #define	target_remove_watchpoint(addr, len, type)	\
      (*current_target.to_remove_watchpoint) (addr, len, type)
 
+/* Hardware watchpoints with a mask associated.  */
+#ifndef target_insert_mask_watchpoint
+#define target_insert_mask_watchpoint(addr, len, type, mask) \
+  (*current_target.to_insert_mask_watchpoint) (addr, len, type, mask)
+#endif
+
+#ifndef target_remove_mask_watchpoint
+#define target_remove_mask_watchpoint(addr, len, type, mask) \
+  (*current_target.to_remove_mask_watchpoint) (addr, len, type, mask)
+#endif
+
+/* Hardware watchpoint with a condition associated (to be
+   hardware-accelerated).  */
+#ifndef target_insert_cond_accel_watchpoint
+#define target_insert_cond_accel_watchpoint(addr, len, type, cond) \
+  (*current_target.to_insert_cond_accel_watchpoint) (addr, len, type, cond)
+#endif
+
+#ifndef target_remove_cond_accel_watchpoint
+#define target_remove_cond_accel_watchpoint(addr, len, type, cond) \
+  (*current_target.to_remove_cond_accel_watchpoint) (addr, len, type, cond)
+#endif
+
 #define target_insert_hw_breakpoint(gdbarch, bp_tgt) \
      (*current_target.to_insert_hw_breakpoint) (gdbarch, bp_tgt)
 
@@ -1213,6 +1270,11 @@ extern char *normal_pid_to_str (ptid_t ptid);
 #define target_watchpoint_addr_within_range(target, addr, start, length) \
   (*target.to_watchpoint_addr_within_range) (target, addr, start, length)
 
+#ifndef target_hw_point_extra_slot_count
+#define target_hw_point_extra_slot_count(flag) \
+  (*current_target.to_hw_point_extra_slot_count) (flag)
+#endif
+
 /* Target can execute in reverse?  */
 #define target_can_execute_reverse \
      (current_target.to_can_execute_reverse ? \

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]