public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* Re: [PATCH 2/4] Hardware accelerated watchpoint conditions
       [not found] <200912232231.01798.bauerman@br.ibm.com>
@ 2010-01-04 17:33 ` Thiago Jung Bauermann
  2010-01-12 10:51   ` Joel Brobecker
  0 siblings, 1 reply; 17+ messages in thread
From: Thiago Jung Bauermann @ 2010-01-04 17:33 UTC (permalink / raw)
  To: gdb-patches; +Cc: Luis Machado, Matt Tyrlik

[-- Attachment #1: Type: Text/Plain, Size: 3415 bytes --]

On Wed 23 Dec 2009 22:31:01 Thiago Jung Bauermann wrote:
> This patch teaches GDB the concept of hardware accelerated watchpoint
> conditions, and enables the target to say when a condition can be
> accelerated or not.
> 
> In the case of BookE processors, the condition will be accelerated
> when the user types "watch A if A == B", where A and B are either
> address (e.g. "*0x12345678") or variables.

This version incorporates all the feedback received so far.
-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center


2009-12-31  Sergio Durigan Junior  <sergiodj@linux.vnet.ibm.com>
	    Thiago Jung Bauermann  <bauerman@br.ibm.com>

	* breakpoint.c (update_watchpoint): Handle the case when the hardware
	supports the acceleration of the watchpoint's condition evaluation.
	(insert_bp_location): Call the correct insertion method according
	to the type of the hardware watchpoint.
	(remove_breakpoint_1): Call the correct deletion method according
	to the type of the hardware watchpoint.
	(set_raw_breakpoint_without_location): Set hw_point_flag to zero.
	(watch_command_1): Mention when a hardware-accelerated
	condition watchpoint will be used.
	(update_breakpoint_locations):  Handle the case of a hardware
	watchpoint with a condition begin hardware-accelerated.
	(exp_is_address_p): New function.
	(exp_is_var_p): Ditto.
	(cond_is_address_equal_literal_p): Ditto.
	(cond_is_var_equal_literal_p): Ditto.
	(get_var_address): Ditto.
	(default_watch_address_if_var_equal_literal_p): Ditto.
	(default_watch_var_if_address_equal_literal_p): Ditto.
	(default_watch_var_if_var_equal_literal_p): Ditto.
	(default_watch_address_if_address_equal_literal_p): Ditto.
	* breakpoint.h (struct bp_target_info) <length>: New field.
	(struct bp_location) <cond_hw_accel>, <cond_hw_addr>: New
	fields.
	(enum hw_point_flag): New.
	(struct breakpoint) <hw_point_flag>: New field.
	(default_watch_address_if_address_equal_literal_p): Declare.
	(default_watch_var_if_var_equal_literal_p): Ditto.
	(default_watch_address_if_var_equal_literal_p): Ditto.
	(default_watch_var_if_address_equal_literal_p): Ditto.
	* ppc-linux-nat.c (ppc_linux_can_use_special_hw_point_p): New function.
	(ppc_linux_insert_cond_accel_watchpoint): Ditto.
	(ppc_linux_remove_cond_accel_watchpoint): Ditto.
	(ppc_linux_get_watchpoint_cond_accel_addr): Ditto.
	(ppc_linux_can_use_watchpoint_cond_accel_p): Ditto.
	(_initialize_ppc_linux_nat): Initialize to_can_use_special_hw_point_p,
	to_get_watchpoint_cond_accel_addr, to_can_use_watchpoint_cond_accel_p,
	to_insert_cond_accel_watchpoint and to_remove_cond_accel_watchpoint.
	* target.c (update_current_target): Add to_can_use_special_hw_point_p,
	to_get_watchpoint_cond_accel_addr, to_can_use_watchpoint_cond_accel_p,
	to_insert_cond_accel_watchpoint and to_remove_cond_accel_watchpoint.
	* target.h: Add opaque declarations for bp_location, breakpoint and
	hw_point_flag.
	(struct target_ops) <to_can_use_special_hw_point_p>,
	<to_can_use_watchpoint_cond_accel_p>, 
	<to_insert_cond_accel_watchpoint>,
	<to_remove_cond_accel_watchpoint>,
	<to_get_watchpoint_cond_accel_addr>: New callbacks.
	(target_region_ok_for_hw_watchpoint): Surround with ifndef.
	(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_cond_accel_watchpoint): Ditto.
	(target_remove_cond_accel_watchpoint): Ditto.

[-- Attachment #2: ppc476-condition.diff --]
[-- Type: text/x-patch, Size: 25846 bytes --]

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 94ae19b..cdd2997 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -1236,6 +1236,17 @@ update_watchpoint (struct breakpoint *b, int reparse)
 	{
 	  char *s = b->cond_string;
 	  b->loc->cond = parse_exp_1 (&s, b->exp_valid_block, 0);
+
+	  if (b->type == bp_hardware_watchpoint
+	      && target_can_use_special_hw_point_p (HW_POINT_COND_HW_ACCEL)
+	      && target_can_use_watchpoint_cond_accel_p (b->loc))
+	    {
+	      target_get_watchpoint_cond_accel_addr (b->loc,
+						     &b->loc->cond_hw_addr);
+	      b->hw_point_flag = HW_POINT_COND_HW_ACCEL;
+	    }
+	  else
+	    b->hw_point_flag = HW_POINT_NONE;
 	}
     }
   else if (!within_current_scope)
@@ -1479,9 +1490,15 @@ Note: automatically using hardware breakpoints for read-only addresses.\n"));
 	      watchpoints.  It's not clear that it's necessary... */
 	   && bpt->owner->disposition != disp_del_at_next_stop)
     {
-      val = target_insert_watchpoint (bpt->address, 
-				      bpt->length,
-				      bpt->watchpoint_type);
+      if (bpt->owner->hw_point_flag == HW_POINT_COND_HW_ACCEL)
+	val = target_insert_cond_accel_watchpoint (bpt->address,
+						   bpt->length,
+						   bpt->watchpoint_type,
+						   bpt->cond_hw_addr);
+      else
+	val = target_insert_watchpoint (bpt->address,
+					bpt->length,
+					bpt->watchpoint_type);
       bpt->inserted = (val != -1);
     }
 
@@ -2107,8 +2124,13 @@ remove_breakpoint_1 (struct bp_location *b, insertion_state_t is)
       struct value *n;
 
       b->inserted = (is == mark_inserted);
-      val = target_remove_watchpoint (b->address, b->length, 
-				      b->watchpoint_type);
+      if (b->owner->hw_point_flag == HW_POINT_COND_HW_ACCEL)
+	val = target_remove_cond_accel_watchpoint (b->address, b->length,
+						   b->watchpoint_type,
+						   b->cond_hw_addr);
+      else
+	val = target_remove_watchpoint (b->address, b->length,
+					b->watchpoint_type);
 
       /* Failure to remove any of the hardware watchpoints comes here.  */
       if ((is == mark_uninserted) && (b->inserted))
@@ -4877,6 +4899,7 @@ set_raw_breakpoint_without_location (struct gdbarch *gdbarch,
   b->syscalls_to_be_caught = NULL;
   b->ops = NULL;
   b->condition_not_parsed = 0;
+  b->hw_point_flag = HW_POINT_NONE;
 
   /* Add this breakpoint to the end of the chain
      so that a list of breakpoints will come out in order
@@ -7327,6 +7350,10 @@ watch_command_1 (char *arg, int accessflag, int from_tty)
      that should be inserted.  */
   update_watchpoint (b, 1);
 
+  if (b->hw_point_flag == HW_POINT_COND_HW_ACCEL)
+    printf_filtered (_("This watchpoint will have its condition evaluation \
+assisted by hardware.\n"));
+
   mention (b);
   update_global_location_list (1);
 }
@@ -8881,6 +8908,18 @@ update_breakpoint_locations (struct breakpoint *b,
 		       b->number, e.message);
 	      new_loc->enabled = 0;
 	    }
+
+	  if (b->type == bp_hardware_watchpoint
+	      && new_loc->cond
+	      && target_can_use_special_hw_point_p (HW_POINT_COND_HW_ACCEL)
+	      && target_can_use_watchpoint_cond_accel_p (new_loc))
+	    {
+	      target_get_watchpoint_cond_accel_addr (new_loc,
+						     &new_loc->cond_hw_addr);
+	      new_loc->owner->hw_point_flag = HW_POINT_COND_HW_ACCEL;
+	    }
+	  else
+	    new_loc->owner->hw_point_flag = HW_POINT_NONE;
 	}
 
       if (b->source_file != NULL)
@@ -10046,6 +10085,250 @@ tracepoint_save_command (char *args, int from_tty)
   return;
 }
 
+/* This function checks if the expression associated
+   with the breakpoint `b' is of the form "*<address>".
+   It returns 1 if it is, 0 otherwise.  */
+static int
+exp_is_address_p (struct breakpoint *b)
+{
+  /* Check that the associated tree corresponds to that expression,
+     that is 5 elements, first a UNOP_IND, and then an OP_LONG.  */
+  if (b->exp->nelts != 5
+      || b->exp->elts[0].opcode != UNOP_IND
+      || b->exp->elts[1].opcode != OP_LONG)
+      return 0;
+  return 1;
+}
+
+/* This function checks if the expression associated
+   with the breakpoint `b' is of the form "<var>".
+   It returns 1 if it is, 0 otherwise.  */
+static int
+exp_is_var_p (struct breakpoint *b)
+{
+  /* Check that the associated tree corresponds to that expression,
+     that is 4 elements, first a OP_VAR_VALUE.  */
+  if (b->exp->nelts != 4
+      || b->exp->elts[0].opcode != OP_VAR_VALUE)
+      return 0;
+  return 1;
+}
+
+/* This function checks if the condition associated
+   with the bp_location `b' is of the form "*<address> == LITERAL".
+   It returns 1 if it is, 0 otherwise.  */
+static int
+cond_is_address_equal_literal_p (struct bp_location *b)
+{
+  /* Check the watchpoint condition expression.  It should be
+     of the form "*<address> EQUAL <litteral>", where EQUAL is the
+     equality binary operator.  */
+  if (b->cond->nelts == 10
+      && b->cond->elts[0].opcode == BINOP_EQUAL
+      && b->cond->elts[1].opcode == UNOP_IND
+      && b->cond->elts[2].opcode == OP_LONG
+      && b->cond->elts[6].opcode == OP_LONG)
+      return 1;
+  else if (b->cond->nelts == 11
+      && b->cond->elts[0].opcode == BINOP_EQUAL
+      && b->cond->elts[1].opcode == UNOP_IND
+      && b->cond->elts[2].opcode == OP_LONG
+      && b->cond->elts[6].opcode == UNOP_NEG
+      && b->cond->elts[7].opcode == OP_LONG)
+      return 1;
+
+  return 0;
+}
+
+/* This function checks if the condition associated
+   with the bp_location `b' is of the form "<var> == LITERAL".
+   It returns 1 if it is, 0 otherwise.  */
+static int
+cond_is_var_equal_literal_p (struct bp_location *b)
+{
+  /* Check the watchpoint condition expression.  It should be
+     of the form "<variable> EQUAL <literal>", where EQUAL is the
+     equality binary operator.  */
+  if (b->cond->nelts == 9
+      && b->cond->elts[0].opcode == BINOP_EQUAL
+      && b->cond->elts[1].opcode == OP_VAR_VALUE
+      && b->cond->elts[5].opcode == OP_LONG)
+      return 1;
+  else if (b->cond->nelts == 10
+      && b->cond->elts[0].opcode == BINOP_EQUAL
+      && b->cond->elts[1].opcode == OP_VAR_VALUE
+      && b->cond->elts[5].opcode == UNOP_NEG
+      && b->cond->elts[6].opcode == OP_LONG)
+      return 1;
+
+  return 0;
+}
+
+/* This function is used to determine whether the condition associated
+   with bp_location B is of the form:
+
+   watch *<ADDRESS> if <VAR> == <LITERAL>
+
+   If it is, then it sets DATA_VALUE to LITERAL and returns 1.
+   Otherwise, it returns 0.  */
+int
+default_watch_address_if_var_equal_literal_p (struct bp_location *b,
+					      CORE_ADDR *data_value)
+{
+  int pc;
+  CORE_ADDR exp_address,
+	    cond_address;
+  struct breakpoint *bp = b->owner;
+
+  if (!exp_is_address_p (bp)
+      || !cond_is_var_equal_literal_p (b))
+    return 0;
+
+  exp_address = bp->exp->elts[3].longconst;
+  cond_address = value_as_address (address_of_variable (b->cond->elts[3].symbol,
+							b->cond->elts[2].block));
+
+  /* Make sure that the two addresses are the same.  */
+  if (exp_address != cond_address)
+    {
+      printf_filtered (_("\
+Memory location for the watchpoint expression and its condition need\n\
+to be the same.\n"));
+      return 0;
+    }
+
+  /* At this point, all verifications were positive, so we can use
+     hardware-assisted data-matching.  Set the data value, and return
+     non-zero.  */
+  pc = 5;
+  *data_value = value_as_long (evaluate_subexp (NULL_TYPE, b->cond, &pc, EVAL_NORMAL));
+
+  return 1;
+}
+
+/* This function is used to determine whether the condition associated
+   with bp_location B is of the form:
+
+   watch <VAR> if *<ADDRESS> == <LITERAL>
+
+   If it is, then it sets DATA_VALUE to LITERAL and returns 1.
+   Otherwise, it returns 0.  */
+int
+default_watch_var_if_address_equal_literal_p (struct bp_location *b,
+					      CORE_ADDR *data_value)
+{
+  int pc;
+  CORE_ADDR exp_address,
+	    cond_address;
+  struct breakpoint *bp = b->owner;
+
+  if (!exp_is_var_p (bp)
+      || !cond_is_address_equal_literal_p (b))
+    return 0;
+
+  exp_address = value_as_address (address_of_variable (bp->exp->elts[2].symbol,
+						       bp->exp->elts[1].block));
+  cond_address = b->cond->elts[4].longconst;
+
+  /* Make sure that the two addresses are the same.  */
+  if (exp_address != cond_address)
+    {
+      printf_filtered (_("\
+Memory location for the watchpoint expression and its condition need\n\
+to be the same.\n"));
+      return 0;
+    }
+
+  /* At this point, all verifications were positive, so we can use
+     hardware-assisted data-matching.  Set the data value, and return
+     non-zero.  */
+  pc = 6;
+  *data_value = value_as_long (evaluate_subexp (NULL_TYPE, b->cond, &pc, EVAL_NORMAL));
+
+  return 1;
+}
+
+/* This function is used to determine whether the condition associated
+   with bp_location B is of the form:
+
+   watch <VAR> if <VAR> == <LITERAL>
+
+   If it is, then it sets DATA_VALUE to LITERAL and returns 1.
+   Otherwise, it returns 0.  */
+int
+default_watch_var_if_var_equal_literal_p (struct bp_location *b,
+					  CORE_ADDR *data_value)
+{
+  int pc;
+  char *name_exp, *name_cond;
+  struct breakpoint *bp = b->owner;
+
+  if (!exp_is_var_p (bp)
+      || !cond_is_var_equal_literal_p (b))
+    return 0;
+
+  name_exp = bp->exp->elts[2].symbol->ginfo.name;
+  name_cond = b->cond->elts[3].symbol->ginfo.name;
+
+  /* Make sure that the two variables' names are the same.  */
+  if (strcmp (name_cond, name_exp) != 0)
+    {
+      printf_filtered (_("\
+Memory location for the watchpoint expression and its condition need\n\
+to be the same.\n"));
+      return 0;
+    }
+
+  /* At this point, all verifications were positive, so we can use
+     hardware-assisted data-matching.  Set the data value, and return
+     non-zero.  */
+  pc = 5;
+  *data_value = value_as_long (evaluate_subexp (NULL_TYPE, b->cond, &pc, EVAL_NORMAL));
+
+  return 1;
+}
+
+/* This function is used to determine whether the condition associated
+   with bp_location B is of the form:
+
+   watch *<ADDRESS> if *<ADDRESS> == <LITERAL>
+
+   If it is, then it sets DATA_VALUE to LITERAL and returns 1.
+   Otherwise, it returns 0.  */
+int
+default_watch_address_if_address_equal_literal_p (struct bp_location *b,
+						  CORE_ADDR *data_value)
+{
+  int pc;
+  CORE_ADDR exp_address,
+	    cond_address;
+  struct breakpoint *bp = b->owner;
+
+  if (!exp_is_address_p (bp)
+      || !cond_is_address_equal_literal_p (b))
+    return 0;
+
+  exp_address = bp->exp->elts[3].longconst;
+  cond_address = b->cond->elts[4].longconst;
+
+  /* Make sure that the two addresses are the same.  */
+  if (exp_address != cond_address)
+    {
+      printf_filtered (_("\
+Memory location for the watchpoint expression and its condition need\n\
+to be the same.\n"));
+      return 0;
+    }
+
+  /* At this point, all verifications were positive, so we can use
+     hardware-assisted data-matching.  Set the data value, and return
+     non-zero.  */
+  pc = 6;
+  *data_value = value_as_long (evaluate_subexp (NULL_TYPE, b->cond, &pc, EVAL_NORMAL));
+
+  return 1;
+}
+
 /* Create a vector of all tracepoints.  */
 
 VEC(breakpoint_p) *
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 5ebd36c..d0c52a9 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -186,6 +186,11 @@ struct bp_target_info
      is used to determine the type of breakpoint to insert.  */
   CORE_ADDR placed_address;
 
+  /* If this is a ranged hardware breakpoint, then we can use this
+     field in order to store the length of the range that will be
+     watched for execution.  */
+  ULONGEST length;
+
   /* If the breakpoint lives in memory and reading that memory would
      give back the breakpoint, instead of the original contents, then
      the original contents are cached here.  Only SHADOW_LEN bytes of
@@ -246,6 +251,17 @@ struct bp_location
      different locations.  */
   struct expression *cond;
 
+  /* Flag to indicate if the condition is going to be accelerated
+     by hardware.  If its value is non-zero, then GDB checks the
+     condition using hardware acceleration; otherwise it uses the
+     regular software-based checking.  */
+  int cond_hw_accel : 1;
+
+  /* If the condition can be hardware-accelerated, then we must
+     get the condition's variable address so that GDB can
+     properly set the evaluation via hardware.  */
+  CORE_ADDR cond_hw_addr;
+
   /* This location's address is in an unloaded solib, and so this
      location should not be inserted.  It will be automatically
      enabled when that solib is loaded.  */
@@ -373,6 +389,13 @@ DEF_VEC_I(int);
 typedef struct bp_location *bp_location_p;
 DEF_VEC_P(bp_location_p);
 
+/* Special flags for hardware breakpoints/watchpoints.  */
+enum hw_point_flag {
+	HW_POINT_NONE = 0,
+	HW_POINT_COND_HW_ACCEL,   /* Hardware watchpoint with condition
+				  hardware-accelerated.  */
+};
+
 /* Note that the ->silent field is not currently used by any commands
    (though the code is in there if it was to be, and set_raw_breakpoint
    does set it to 0).  I implemented it because I thought it would be
@@ -512,6 +535,9 @@ struct breakpoint
 
     /* Chain of action lines to execute when this tracepoint is hit.  */
     struct action_line *actions;
+
+    /* Special flags.  */
+    enum hw_point_flag hw_point_flag;
   };
 
 typedef struct breakpoint *breakpoint_p;
@@ -992,4 +1018,20 @@ extern struct breakpoint *get_tracepoint_by_number (char **arg, int multi_p,
    is newly allocated; the caller should free when done with it.  */
 extern VEC(breakpoint_p) *all_tracepoints (void);
 
+/* Return greater than zero if the condition associated with
+   the watchpoint `b' can be treated by the hardware; zero otherwise.
+
+   Also stores the data value in `data_value'.  */
+extern int default_watch_address_if_address_equal_literal_p (struct bp_location *b,
+                                                             CORE_ADDR *data_value);
+
+extern int default_watch_var_if_var_equal_literal_p (struct bp_location *b,
+                                                     CORE_ADDR *data_value);
+
+extern int default_watch_address_if_var_equal_literal_p (struct bp_location *b,
+                                                         CORE_ADDR *data_value);
+
+extern int default_watch_var_if_address_equal_literal_p (struct bp_location *b,
+                                                         CORE_ADDR *data_value);
+
 #endif /* !defined (BREAKPOINT_H) */
diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c
index 2c930c9..4697164 100644
--- a/gdb/ppc-linux-nat.c
+++ b/gdb/ppc-linux-nat.c
@@ -1445,6 +1445,26 @@ ppc_linux_can_use_hw_breakpoint (int type, int cnt, int ot)
 }
 
 static int
+ppc_linux_can_use_special_hw_point_p (enum hw_point_flag flag)
+{
+  uint64_t features = booke_debug_info.features;
+
+  if (!have_ptrace_new_debug_booke)
+    return 0;
+
+  switch (flag)
+    {
+    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)
 {
   /* Handle sub-8-byte quantities.  */
@@ -1655,6 +1675,70 @@ static int get_trigger_type (int rw)
 }
 
 static int
+ppc_linux_insert_cond_accel_watchpoint (CORE_ADDR addr, int len, int rw,
+					  CORE_ADDR cond)
+{
+  struct ppc_hw_breakpoint p;
+  unsigned long a = (unsigned long) addr,
+		c = (unsigned long) cond;
+  struct lwp_info *lp;
+  ptid_t ptid;
+  int byte_to_enable;
+
+  if (!have_ptrace_new_debug_booke)
+    return -1;
+
+  byte_to_enable = a % 4;
+  c >>= (byte_to_enable * 8);
+
+  p.version         = PPC_DEBUG_CURRENT_VERSION;
+  p.trigger_type    = get_trigger_type (rw);
+  p.addr_mode       = PPC_BREAKPOINT_MODE_EXACT;
+  p.condition_mode  = PPC_BREAKPOINT_CONDITION_AND
+  		      | PPC_BREAKPOINT_CONDITION_BE (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
+ppc_linux_remove_cond_accel_watchpoint (CORE_ADDR addr, int len, int rw,
+					  CORE_ADDR cond)
+{
+  struct ppc_hw_breakpoint p;
+  unsigned long a = (unsigned long) addr,
+		c = (unsigned long) cond;
+  struct lwp_info *lp;
+  ptid_t ptid;
+  int byte_to_enable;
+
+  if (!have_ptrace_new_debug_booke)
+    return -1;
+
+  byte_to_enable = a % 4;
+  c >>= (byte_to_enable * 8);
+
+  p.version         = PPC_DEBUG_CURRENT_VERSION;
+  p.trigger_type    = get_trigger_type (rw);
+  p.addr_mode       = PPC_BREAKPOINT_MODE_EXACT;
+  p.condition_mode  = PPC_BREAKPOINT_CONDITION_AND
+  		      | PPC_BREAKPOINT_CONDITION_BE (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;
+}
+
+static int
 ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw)
 {
   struct lwp_info *lp;
@@ -1854,6 +1938,52 @@ ppc_linux_watchpoint_addr_within_range (struct target_ops *target,
   return start <= addr + mask && start + length - 1 >= addr;
 }
 
+static int
+ppc_linux_get_watchpoint_cond_accel_addr (struct bp_location *b,
+					  CORE_ADDR *addr)
+{
+  if (have_ptrace_new_debug_booke)
+    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);
+
+  *addr = 0;
+
+  return 0;
+}
+
+static int
+ppc_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;
+
+  if (!have_ptrace_new_debug_booke)
+    return 0;
+
+  p = booke_find_thread_points_by_tid (tid, 0);
+
+  if (p)
+    {
+      for (i = 0; i < max_slots_number; i++)
+	if (p->hw_breaks[i].hw_break != NULL
+	    && p->hw_breaks[i].hw_break->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 ppc_linux_get_watchpoint_cond_accel_addr (b, &tmp_value);
+}
+
 static void
 ppc_linux_store_inferior_registers (struct target_ops *ops,
 				    struct regcache *regcache, int regno)
@@ -2076,11 +2206,18 @@ _initialize_ppc_linux_nat (void)
 
   /* 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 = ppc_linux_insert_hw_breakpoint;
   t->to_remove_hw_breakpoint = ppc_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_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;
diff --git a/gdb/target.c b/gdb/target.c
index cd1614b..3b1476d 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -619,11 +619,16 @@ update_current_target (void)
       INHERIT (to_files_info, t);
       INHERIT (to_insert_breakpoint, t);
       INHERIT (to_remove_breakpoint, t);
+      INHERIT (to_can_use_special_hw_point_p, t);
+      INHERIT (to_can_use_watchpoint_cond_accel_p, t);
       INHERIT (to_can_use_hw_breakpoint, 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_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);
@@ -725,6 +730,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 +748,12 @@ update_current_target (void)
   de_fault (to_remove_watchpoint,
 	    (int (*) (CORE_ADDR, int, int))
 	    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 +764,9 @@ 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_get_watchpoint_cond_accel_addr,
+	    (int (*) (struct bp_location *, CORE_ADDR *))
+	    return_zero);
   de_fault (to_terminal_init,
 	    (void (*) (void))
 	    target_ignore);
diff --git a/gdb/target.h b/gdb/target.h
index ebe6056..c604846 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,16 +405,22 @@ 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_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_get_watchpoint_cond_accel_addr) (struct bp_location *,
+						    CORE_ADDR *);
     int (*to_region_ok_for_hw_watchpoint) (CORE_ADDR, int);
     void (*to_terminal_init) (void);
     void (*to_terminal_inferior) (void);
@@ -1184,9 +1195,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);
 
+#ifndef target_region_ok_for_hw_watchpoint
 #define target_region_ok_for_hw_watchpoint(addr, len) \
     (*current_target.to_region_ok_for_hw_watchpoint) (addr, len)
-
+#endif
+
+/* 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
+
+/* 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 +1229,18 @@ 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 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)
 

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 2/4] Hardware accelerated watchpoint conditions
  2010-01-04 17:33 ` [PATCH 2/4] Hardware accelerated watchpoint conditions Thiago Jung Bauermann
@ 2010-01-12 10:51   ` Joel Brobecker
  2010-02-04 21:48     ` Thiago Jung Bauermann
  0 siblings, 1 reply; 17+ messages in thread
From: Joel Brobecker @ 2010-01-12 10:51 UTC (permalink / raw)
  To: Thiago Jung Bauermann; +Cc: gdb-patches, Luis Machado, Matt Tyrlik

Global Maintainers:

This is touching an area of the target vector that I think could be
improved. Eli actually mentioned some of the issues in this area, a few
days ago.  I don't think that we should stall this patch pending
a rework of the watchpoint support, but I would like to see an
implementation that does not make the long term cleanup more difficult
than it already is.  So, feedback and ideas would be welcome.

Thiago, Luis,

Sorry for the delay looking into this; I needed a little bit of time
to let this brew a little...

> > In the case of BookE processors, the condition will be accelerated
> > when the user types "watch A if A == B", where A and B are either
> > address (e.g. "*0x12345678") or variables.

I like the principle that detection of the situations where h/w
acceleration of the condition can be done, so that the user does not
have to do anything to get access to this feature.

I think, from your patch, that GDB will still evaluate the condition
once after the watchpoint and its condition trigger. I think that
we might want to fix that eventually, but I am actually more than
happy to ignore this minor issue for now.  I like baby steps :).
In fact, let's worry about functionality only, even if it means
writing inefficient code. We can implement caches and optimizations
later, if it helps getting this in faster.

My first general observation is that this patch introduces new
target_ops routine in an area that, IMO, could use some simplification
(refer to the first comment above). I think we can avoid that.

Conceptually, I think that the target now needs to be able to look
at the watchpoint expression, and the watchpoint condition, in order
to determine whether the condition evaluation can be evaluated
by hardware. I propose that we expand the insert_watchpoint routine
to pass this data, as 2 extra parameters; and let these routines
decide whether to use hardware acceleration or not for the condition.

One of the downsides of this approach is that GDB will no longer
be able to print that the condition will be hardware-accelerated
when the user creates the watchpoint. I think that's OK for now.

The upside is that the code will not have to worry about this
aspect of the watchpoint when inserting/removing it. Thus,
the following hunk would be simplified:

> -				      bpt->watchpoint_type);
> +      if (bpt->owner->hw_point_flag == HW_POINT_COND_HW_ACCEL)
> +	val = target_insert_cond_accel_watchpoint (bpt->address,
> +						   bpt->length,
> +						   bpt->watchpoint_type,
> +						   bpt->cond_hw_addr);
> +      else
> +	val = target_insert_watchpoint (bpt->address,
> +					bpt->length,
> +					bpt->watchpoint_type);

I am also a bit suspicious of adding the following bits to the bp_location
structure directly:

> +  /* Flag to indicate if the condition is going to be accelerated
> +     by hardware.  If its value is non-zero, then GDB checks the
> +     condition using hardware acceleration; otherwise it uses the
> +     regular software-based checking.  */
> +  int cond_hw_accel : 1;
> +
> +  /* If the condition can be hardware-accelerated, then we must
> +     get the condition's variable address so that GDB can
> +     properly set the evaluation via hardware.  */
> +  CORE_ADDR cond_hw_addr;

I think that they are too target specific. Initially, we can do without,
with our not-so-efficient approach, by recomputing these address every
time we insert the watchpoint.   I think that'd still be an interesting
first step.   Then we can look at storing that info as a private data
structure, allocated by the target.  I think that this would be doable
without too many changes to the current framework - we just need to
be a little careful as watchpoint expressions and conditions get
re-evaluated sometimes.

> +static int
> +exp_is_address_p (struct breakpoint *b)

If you want, you can drop the _p prefix in this type of situation.
I think the use of the verb _is_ in the names makes it obvious that
this function is a predicate.

> +int
> +default_watch_address_if_var_equal_literal_p (struct bp_location *b,
> +					      CORE_ADDR *data_value)

This is nitpicking on function names, but I don't understand the
"default" here. Would there be some non-default implementations
of the same routine? Perhaps: watch_address_if_var_equal_literal_p
is just going to be sufficient?

> +  /* Make sure that the two addresses are the same.  */
> +  if (exp_address != cond_address)
> +    {
> +      printf_filtered (_("\
> +Memory location for the watchpoint expression and its condition need\n\
> +to be the same.\n"));
> +      return 0;
> +    }

Not sure whether you really meant to keep this message. It sounds like
an error, when in fact this could occur in a perfectly legitimate
situation, no? For instance, if the user entered:

    (gdb) watch A if B == 3

The message could be kept as a debug trace, but it should be more
neutral, IMO, something like:

   address of variable in condition does not match expression being watched.

would provide all the information without suggesting that something
might have gone wrong.

Let me know what you think. I realize that I'm significantly reducing
the scope of the first attempt at getting h/w-accelerated watchpoint
conditions, but I'm hoping it'll help focusing on each issue separately.
I'm perfectly happy to make this feature another patch series on its own,
in parallel to the other hardware-breakpoint patches. We can also take it
one patch at a time. Whatever works best for you.

BTW:

> @@ -186,6 +186,11 @@ struct bp_target_info
>       is used to determine the type of breakpoint to insert.  */
>    CORE_ADDR placed_address;
> 
> +  /* If this is a ranged hardware breakpoint, then we can use this
> +     field in order to store the length of the range that will be
> +     watched for execution.  */
> +  ULONGEST length;
> +

Oops! This should be part of another patch ;-).

-- 
Joel

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 2/4] Hardware accelerated watchpoint conditions
  2010-01-12 10:51   ` Joel Brobecker
@ 2010-02-04 21:48     ` Thiago Jung Bauermann
  2010-02-05  5:16       ` Joel Brobecker
  0 siblings, 1 reply; 17+ messages in thread
From: Thiago Jung Bauermann @ 2010-02-04 21:48 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: gdb-patches, Luis Machado, Matt Tyrlik

[-- Attachment #1: Type: Text/Plain, Size: 7131 bytes --]

On Tue 12 Jan 2010 08:50:45 Joel Brobecker wrote:
> Sorry for the delay looking into this; I needed a little bit of time
> to let this brew a little...

On my part, sorry for the delay in taking this long to rework the patch
and send it back. I was on vacation...

Thanks for the in-depth review!
 
> I think, from your patch, that GDB will still evaluate the condition
> once after the watchpoint and its condition trigger. I think that
> we might want to fix that eventually, but I am actually more than
> happy to ignore this minor issue for now.  I like baby steps :).

If I'm following your thought here, I added that on purpose. Before
letting GDB evaluate the condition one more time, GDB wouldn't know
which watchpoint triggered if there were two at the same location,
with different conditions.

> Conceptually, I think that the target now needs to be able to look
> at the watchpoint expression, and the watchpoint condition, in order
> to determine whether the condition evaluation can be evaluated
> by hardware. I propose that we expand the insert_watchpoint routine
> to pass this data, as 2 extra parameters; and let these routines
> decide whether to use hardware acceleration or not for the condition.

I liked the idea. This patches implements that approach.

> One of the downsides of this approach is that GDB will no longer
> be able to print that the condition will be hardware-accelerated
> when the user creates the watchpoint. I think that's OK for now.

Yeah, I would like to have that message printed though. Wil have
to think about it.
 
> I am also a bit suspicious of adding the following bits to the bp_location
> 
> structure directly:
> > +  /* Flag to indicate if the condition is going to be accelerated
> > +     by hardware.  If its value is non-zero, then GDB checks the
> > +     condition using hardware acceleration; otherwise it uses the
> > +     regular software-based checking.  */
> > +  int cond_hw_accel : 1;
> > +
> > +  /* If the condition can be hardware-accelerated, then we must
> > +     get the condition's variable address so that GDB can
> > +     properly set the evaluation via hardware.  */
> > +  CORE_ADDR cond_hw_addr;
> 
> I think that they are too target specific. Initially, we can do without,
> with our not-so-efficient approach, by recomputing these address every
> time we insert the watchpoint.   I think that'd still be an interesting
> first step.   Then we can look at storing that info as a private data
> structure, allocated by the target.  I think that this would be doable
> without too many changes to the current framework - we just need to
> be a little careful as watchpoint expressions and conditions get
> re-evaluated sometimes.

Those are gone. I don't think recomputing the address everytime
GDB stops will get in our way at this point. Parsing the condition
expression should be a quick enough operation I think.

> > +static int
> > +exp_is_address_p (struct breakpoint *b)
> 
> If you want, you can drop the _p prefix in this type of situation.
> I think the use of the verb _is_ in the names makes it obvious that
> this function is a predicate.

I didn't like those _p suffixes much either. They're all gone.
 
> > +int
> > +default_watch_address_if_var_equal_literal_p (struct bp_location *b,
> > +					      CORE_ADDR *data_value)
> 
> This is nitpicking on function names, but I don't understand the
> "default" here. Would there be some non-default implementations
> of the same routine? Perhaps: watch_address_if_var_equal_literal_p
> is just going to be sufficient?

Not sure either. I removed the default_ prefix from those function names.
 
> > +  /* Make sure that the two addresses are the same.  */
> > +  if (exp_address != cond_address)
> > +    {
> > +      printf_filtered (_("\
> > +Memory location for the watchpoint expression and its condition need\n\
> > +to be the same.\n"));
> > +      return 0;
> > +    }
> 
> Not sure whether you really meant to keep this message. It sounds like
> an error, when in fact this could occur in a perfectly legitimate
> situation, no? For instance, if the user entered:
> 
>     (gdb) watch A if B == 3
> 
> The message could be kept as a debug trace, but it should be more
> neutral, IMO, something like:
> 
>    address of variable in condition does not match expression being
>  watched.
> 
> would provide all the information without suggesting that something
> might have gone wrong.

I agree. In this version GDB silently uses software condition checking.
But there should be a way to let the user know that the watchpoint
he created is having hardware-accelerated condition checking or not
(hence my comment up there that I'd like some message to be shown
when the watchpoint is created).

> Let me know what you think. I realize that I'm significantly reducing
> the scope of the first attempt at getting h/w-accelerated watchpoint
> conditions, but I'm hoping it'll help focusing on each issue separately.
> I'm perfectly happy to make this feature another patch series on its own,
> in parallel to the other hardware-breakpoint patches. We can also take it
> one patch at a time. Whatever works best for you.

Mmm.... perhaps I'm too thick today, but I don't see how you are
significantly reducing the scope here, except for the hardware-accelerated
message not being shown at watchpoint creation time.
 
> BTW:
> > @@ -186,6 +186,11 @@ struct bp_target_info
> >       is used to determine the type of breakpoint to insert.  */
> >    CORE_ADDR placed_address;
> >
> > +  /* If this is a ranged hardware breakpoint, then we can use this
> > +     field in order to store the length of the range that will be
> > +     watched for execution.  */
> > +  ULONGEST length;
> > +
> 
> Oops! This should be part of another patch ;-).
 
Ooops. Gone.
-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center


2010-02-04  Sergio Durigan Junior  <sergiodj@linux.vnet.ibm.com>
	    Thiago Jung Bauermann  <bauerman@br.ibm.com>

	* target.h: Add opaque declarations for bp_location, breakpoint and
	expression.
	(struct target_ops) <to_insert_watchpoint>,
	<to_remove_watchpoint>: Add new arguments to pass the watchpoint
	expression and its condition.  Update all callers and implementations.
	(target_region_ok_for_hw_watchpoint): Surround with ifndef.
	* breakpoint.c (exp_is_address): New function.
	(exp_is_var): Ditto.
	(exp_is_address_equal_literal): Ditto.
	(exp_is_var_equal_literal): Ditto.
	(watch_address_if_var_equal_literal): Ditto.
	(watch_var_if_address_equal_literal): Ditto.
	(watch_var_if_var_equal_literal): Ditto.
	(watch_address_if_address_equal_literal): Ditto.
	* breakpoint.h (watch_address_if_address_equal_literal): Declare.
	(watch_var_if_var_equal_literal): Ditto.
	(watch_address_if_var_equal_literal): Ditto.
	(watch_var_if_address_equal_literal): Ditto.
	* ppc-linux-nat.c (ppc_linux_can_use_watchpoint_cond_accel): New
	function.
	(ppc_linux_insert_watchpoint): Check if it is possible to use
	hardware-accelerated condition checking.
	(ppc_linux_remove_watchpoint): Check if the watchpoint to delete
	has hardware-accelerated condition checking.


[-- Attachment #2: ppc476-condition.diff --]
[-- Type: text/x-patch, Size: 26868 bytes --]

commit cfa17ed01a406be5668f81c0374f34256eb61ec2
Author: Thiago Jung Bauermann <bauermann@hactar.cps.virtua.com.br>
Date:   Mon Dec 28 14:25:01 2009 -0200

    Hardware accelerated watchpoint conditions.

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 0d55862..13013ca 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -1485,9 +1485,10 @@ Note: automatically using hardware breakpoints for read-only addresses.\n"));
 	      watchpoints.  It's not clear that it's necessary... */
 	   && bpt->owner->disposition != disp_del_at_next_stop)
     {
-      val = target_insert_watchpoint (bpt->address, 
+      val = target_insert_watchpoint (bpt->address,
 				      bpt->length,
-				      bpt->watchpoint_type);
+				      bpt->watchpoint_type,
+				      bpt->owner->exp, bpt->cond);
       bpt->inserted = (val != -1);
     }
 
@@ -2109,12 +2110,10 @@ remove_breakpoint_1 (struct bp_location *b, insertion_state_t is)
     }
   else if (b->loc_type == bp_loc_hardware_watchpoint)
     {
-      struct value *v;
-      struct value *n;
-
       b->inserted = (is == mark_inserted);
-      val = target_remove_watchpoint (b->address, b->length, 
-				      b->watchpoint_type);
+      val = target_remove_watchpoint (b->address, b->length,
+				      b->watchpoint_type,
+				      b->owner->exp, b->cond);
 
       /* Failure to remove any of the hardware watchpoints comes here.  */
       if ((is == mark_uninserted) && (b->inserted))
@@ -10156,6 +10155,218 @@ tracepoint_save_command (char *args, int from_tty)
   return;
 }
 
+/* This function checks if the expression is of the form "*<address>".
+   It returns 1 if it is, 0 otherwise.  */
+static int
+exp_is_address (struct expression *exp)
+{
+  if (exp->nelts != 5
+      || exp->elts[0].opcode != UNOP_IND
+      || exp->elts[1].opcode != OP_LONG)
+      return 0;
+  return 1;
+}
+
+/* This function checks if the expression is of the form "<var>".
+   It returns 1 if it is, 0 otherwise.  */
+static int
+exp_is_var (struct expression *exp)
+{
+  if (exp->nelts != 4
+      || exp->elts[0].opcode != OP_VAR_VALUE)
+      return 0;
+  return 1;
+}
+
+/* This function checks if the expression is of the form
+   "*<address> == LITERAL".  It returns 1 if it is, 0 otherwise.  */
+static int
+exp_is_address_equal_literal (struct expression *exp)
+{
+  if (exp->nelts == 10
+      && exp->elts[0].opcode == BINOP_EQUAL
+      && exp->elts[1].opcode == UNOP_IND
+      && exp->elts[2].opcode == OP_LONG
+      && exp->elts[6].opcode == OP_LONG)
+      return 1;
+  else if (exp->nelts == 11
+      && exp->elts[0].opcode == BINOP_EQUAL
+      && exp->elts[1].opcode == UNOP_IND
+      && exp->elts[2].opcode == OP_LONG
+      && exp->elts[6].opcode == UNOP_NEG
+      && exp->elts[7].opcode == OP_LONG)
+      return 1;
+
+  return 0;
+}
+
+/* This function checks if the expression is of the form "<var> == LITERAL".
+   It returns 1 if it is, 0 otherwise.  */
+static int
+exp_is_var_equal_literal (struct expression *exp)
+{
+  if (exp->nelts == 9
+      && exp->elts[0].opcode == BINOP_EQUAL
+      && exp->elts[1].opcode == OP_VAR_VALUE
+      && exp->elts[5].opcode == OP_LONG)
+      return 1;
+  else if (exp->nelts == 10
+      && exp->elts[0].opcode == BINOP_EQUAL
+      && exp->elts[1].opcode == OP_VAR_VALUE
+      && exp->elts[5].opcode == UNOP_NEG
+      && exp->elts[6].opcode == OP_LONG)
+      return 1;
+
+  return 0;
+}
+
+/* This function is used to determine whether the condition associated
+   with bp_location B is of the form:
+
+   watch *<ADDRESS> if <VAR> == <LITERAL>
+
+   If it is, then it sets DATA_VALUE to LITERAL and returns 1.
+   Otherwise, it returns 0.  */
+int
+watch_address_if_var_equal_literal (struct expression *exp,
+				    struct expression *cond,
+				    CORE_ADDR *data_value)
+{
+  int pc;
+  CORE_ADDR exp_address, cond_address;
+
+  if (!exp_is_address (exp)
+      || !exp_is_var_equal_literal (cond))
+    return 0;
+
+  exp_address = exp->elts[3].longconst;
+  cond_address = value_as_address (address_of_variable (cond->elts[3].symbol,
+							cond->elts[2].block));
+
+  /* Make sure that the two addresses are the same.  */
+  if (exp_address != cond_address)
+    return 0;
+
+  /* At this point, all verifications were positive, so we can use
+     hardware-assisted data-matching.  Set the data value, and return
+     non-zero.  */
+  pc = 5;
+  *data_value = value_as_long (evaluate_subexp (NULL_TYPE, cond, &pc,
+						EVAL_NORMAL));
+
+  return 1;
+}
+
+/* This function is used to determine whether the condition associated
+   with bp_location B is of the form:
+
+   watch <VAR> if *<ADDRESS> == <LITERAL>
+
+   If it is, then it sets DATA_VALUE to LITERAL and returns 1.
+   Otherwise, it returns 0.  */
+int
+watch_var_if_address_equal_literal (struct expression *exp,
+				    struct expression *cond,
+				    CORE_ADDR *data_value)
+{
+  int pc;
+  CORE_ADDR exp_address, cond_address;
+
+  if (!exp_is_var (exp)
+      || !exp_is_address_equal_literal (cond))
+    return 0;
+
+  exp_address = value_as_address (address_of_variable (exp->elts[2].symbol,
+						       exp->elts[1].block));
+  cond_address = cond->elts[4].longconst;
+
+  /* Make sure that the two addresses are the same.  */
+  if (exp_address != cond_address)
+    return 0;
+
+  /* At this point, all verifications were positive, so we can use
+     hardware-assisted data-matching.  Set the data value, and return
+     non-zero.  */
+  pc = 6;
+  *data_value = value_as_long (evaluate_subexp (NULL_TYPE, cond, &pc,
+						EVAL_NORMAL));
+
+  return 1;
+}
+
+/* This function is used to determine whether the condition associated
+   with bp_location B is of the form:
+
+   watch <VAR> if <VAR> == <LITERAL>
+
+   If it is, then it sets DATA_VALUE to LITERAL and returns 1.
+   Otherwise, it returns 0.  */
+int
+watch_var_if_var_equal_literal (struct expression *exp,
+				struct expression *cond,
+				CORE_ADDR *data_value)
+{
+  int pc;
+  CORE_ADDR exp_address, cond_address;
+
+  if (!exp_is_var (exp)
+      || !exp_is_var_equal_literal (cond))
+    return 0;
+
+  exp_address = value_as_address (address_of_variable (exp->elts[2].symbol,
+						       exp->elts[1].block));
+  cond_address = value_as_address (address_of_variable (cond->elts[3].symbol,
+							cond->elts[2].block));
+
+  if (exp_address != cond_address)
+    return 0;
+
+  /* At this point, all verifications were positive, so we can use
+     hardware-assisted data-matching.  Set the data value, and return
+     non-zero.  */
+  pc = 5;
+  *data_value = value_as_long (evaluate_subexp (NULL_TYPE, cond, &pc,
+						EVAL_NORMAL));
+
+  return 1;
+}
+
+/* This function is used to determine whether the condition associated
+   with bp_location B is of the form:
+
+   watch *<ADDRESS> if *<ADDRESS> == <LITERAL>
+
+   If it is, then it sets DATA_VALUE to LITERAL and returns 1.
+   Otherwise, it returns 0.  */
+int
+watch_address_if_address_equal_literal (struct expression *exp,
+					struct expression *cond,
+					CORE_ADDR *data_value)
+{
+  int pc;
+  CORE_ADDR exp_address, cond_address;
+
+  if (!exp_is_address (exp)
+      || !exp_is_address_equal_literal (cond))
+    return 0;
+
+  exp_address = exp->elts[3].longconst;
+  cond_address = cond->elts[4].longconst;
+
+  /* Make sure that the two addresses are the same.  */
+  if (exp_address != cond_address)
+    return 0;
+
+  /* At this point, all verifications were positive, so we can use
+     hardware-assisted data-matching.  Set the data value, and return
+     non-zero.  */
+  pc = 6;
+  *data_value = value_as_long (evaluate_subexp (NULL_TYPE, cond, &pc,
+						EVAL_NORMAL));
+
+  return 1;
+}
+
 /* Create a vector of all tracepoints.  */
 
 VEC(breakpoint_p) *
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 6b373a3..23d49c4 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -998,4 +998,24 @@ extern struct breakpoint *get_tracepoint_by_number (char **arg, int multi_p,
    is newly allocated; the caller should free when done with it.  */
 extern VEC(breakpoint_p) *all_tracepoints (void);
 
+/* Return greater than zero if the condition associated with
+   the watchpoint `b' can be treated by the hardware; zero otherwise.
+
+   Also stores the data value in `data_value'.  */
+extern int watch_address_if_address_equal_literal (struct expression *exp,
+						     struct expression *cond,
+						     CORE_ADDR *data_value);
+
+extern int watch_var_if_var_equal_literal (struct expression *exp,
+					     struct expression *cond,
+					     CORE_ADDR *data_value);
+
+extern int watch_address_if_var_equal_literal (struct expression *exp,
+						 struct expression *cond,
+						 CORE_ADDR *data_value);
+
+extern int watch_var_if_address_equal_literal (struct expression *exp,
+					     struct expression *cond,
+					     CORE_ADDR *data_value);
+
 #endif /* !defined (BREAKPOINT_H) */
diff --git a/gdb/i386-nat.c b/gdb/i386-nat.c
index fa0cce6..1062b74 100644
--- a/gdb/i386-nat.c
+++ b/gdb/i386-nat.c
@@ -483,7 +483,8 @@ Invalid value %d of operation in i386_handle_nonaligned_watchpoint.\n"),
    of the type TYPE.  Return 0 on success, -1 on failure.  */
 
 static int
-i386_insert_watchpoint (CORE_ADDR addr, int len, int type)
+i386_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *exp, struct expression *cond)
 {
   int retval;
 
@@ -507,7 +508,8 @@ i386_insert_watchpoint (CORE_ADDR addr, int len, int type)
    address ADDR, whose length is LEN bytes, and for accesses of the
    type TYPE.  Return 0 on success, -1 on failure.  */
 static int
-i386_remove_watchpoint (CORE_ADDR addr, int len, int type)
+i386_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *exp, struct expression *cond)
 {
   int retval;
 
diff --git a/gdb/ia64-linux-nat.c b/gdb/ia64-linux-nat.c
index e6a7077..f68f77a 100644
--- a/gdb/ia64-linux-nat.c
+++ b/gdb/ia64-linux-nat.c
@@ -530,7 +530,8 @@ is_power_of_2 (int val)
 }
 
 static int
-ia64_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw)
+ia64_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw,
+			      struct expression *exp, struct expression *cond)
 {
   struct lwp_info *lp;
   ptid_t ptid;
@@ -584,7 +585,8 @@ ia64_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw)
 }
 
 static int
-ia64_linux_remove_watchpoint (CORE_ADDR addr, int len, int type)
+ia64_linux_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			      struct expression *exp, struct expression *cond)
 {
   int idx;
   long dbr_addr, dbr_mask;
diff --git a/gdb/inf-ttrace.c b/gdb/inf-ttrace.c
index c9ab548..dab9065 100644
--- a/gdb/inf-ttrace.c
+++ b/gdb/inf-ttrace.c
@@ -314,7 +314,8 @@ inf_ttrace_disable_page_protections (pid_t pid)
    type TYPE.  */
 
 static int
-inf_ttrace_insert_watchpoint (CORE_ADDR addr, int len, int type)
+inf_ttrace_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			      struct expression *exp, struct expression *cond)
 {
   const int pagesize = inf_ttrace_page_dict.pagesize;
   pid_t pid = ptid_get_pid (inferior_ptid);
@@ -337,7 +338,8 @@ inf_ttrace_insert_watchpoint (CORE_ADDR addr, int len, int type)
    type TYPE.  */
 
 static int
-inf_ttrace_remove_watchpoint (CORE_ADDR addr, int len, int type)
+inf_ttrace_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			      struct expression *exp, struct expression *cond)
 {
   const int pagesize = inf_ttrace_page_dict.pagesize;
   pid_t pid = ptid_get_pid (inferior_ptid);
diff --git a/gdb/mips-linux-nat.c b/gdb/mips-linux-nat.c
index fe05192..9d36a39 100644
--- a/gdb/mips-linux-nat.c
+++ b/gdb/mips-linux-nat.c
@@ -926,7 +926,8 @@ populate_regs_from_watches (struct pt_watch_regs *regs)
    watch.  Return zero on success.  */
 
 static int
-mips_linux_insert_watchpoint (CORE_ADDR addr, int len, int type)
+mips_linux_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			      struct expression *exp, struct expression *cond)
 {
   struct pt_watch_regs regs;
   struct mips_watchpoint *new_watch;
@@ -975,7 +976,8 @@ mips_linux_insert_watchpoint (CORE_ADDR addr, int len, int type)
    Return zero on success.  */
 
 static int
-mips_linux_remove_watchpoint (CORE_ADDR addr, int len, int type)
+mips_linux_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			      struct expression *exp, struct expression *cond)
 {
   int retval;
   int deleted_one;
diff --git a/gdb/nto-procfs.c b/gdb/nto-procfs.c
index d8f3c91..d37f259 100644
--- a/gdb/nto-procfs.c
+++ b/gdb/nto-procfs.c
@@ -1509,13 +1509,15 @@ procfs_can_use_hw_breakpoint (int type, int cnt, int othertype)
 }
 
 static int
-procfs_remove_hw_watchpoint (CORE_ADDR addr, int len, int type)
+procfs_remove_hw_watchpoint (CORE_ADDR addr, int len, int type,
+			     struct expression *exp, struct expression *cond)
 {
   return procfs_hw_watchpoint (addr, -1, type);
 }
 
 static int
-procfs_insert_hw_watchpoint (CORE_ADDR addr, int len, int type)
+procfs_insert_hw_watchpoint (CORE_ADDR addr, int len, int type,
+			     struct expression *exp, struct expression *cond)
 {
   return procfs_hw_watchpoint (addr, len, type);
 }
diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c
index 9c76387..83f0c3f 100644
--- a/gdb/ppc-linux-nat.c
+++ b/gdb/ppc-linux-nat.c
@@ -1517,6 +1517,35 @@ booke_find_thread_points_by_tid (int tid, int alloc_new)
   return t;
 }
 
+static int
+ppc_linux_can_use_watchpoint_cond_accel (void)
+{
+  struct thread_points *p;
+  int tid = TIDGET (inferior_ptid);
+  int cnt = booke_debug_info.num_condition_regs, i;
+  CORE_ADDR tmp_value;
+
+  if (!have_ptrace_new_debug_booke)
+    return 0;
+
+  p = booke_find_thread_points_by_tid (tid, 0);
+
+  if (p)
+    {
+      for (i = 0; i < max_slots_number; i++)
+	if (p->hw_breaks[i].hw_break != NULL
+	    && p->hw_breaks[i].hw_break->condition_mode
+		    != PPC_BREAKPOINT_CONDITION_NONE)
+	  cnt--;
+
+      /* There are no available slots now.  */
+      if (cnt <= 0)
+	return 0;
+    }
+
+  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 in GDB.  */
@@ -1658,7 +1687,8 @@ get_trigger_type (int rw)
 }
 
 static int
-ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw)
+ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw,
+			     struct expression *exp, struct expression *cond)
 {
   struct lwp_info *lp;
   ptid_t ptid;
@@ -1666,15 +1696,30 @@ ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw)
 
   if (have_ptrace_new_debug_booke)
     {
+      int byte_to_enable;
       struct ppc_hw_breakpoint p;
+      CORE_ADDR cond_addr;
+
+      if (cond && ppc_linux_can_use_watchpoint_cond_accel ()
+	  && (watch_address_if_address_equal_literal (exp, cond, &cond_addr)
+	      || watch_var_if_var_equal_literal (exp, cond, &cond_addr)
+	      || watch_var_if_address_equal_literal (exp, cond, &cond_addr)
+	      || watch_address_if_var_equal_literal (exp, cond, &cond_addr))) {
+	byte_to_enable = addr % 4;
+	cond_addr >>= (byte_to_enable * 8);
+	p.condition_mode  = PPC_BREAKPOINT_CONDITION_AND
+			    | PPC_BREAKPOINT_CONDITION_BE (byte_to_enable);
+	p.condition_value = (uint64_t) cond_addr;
+      } 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.condition_mode  = PPC_BREAKPOINT_CONDITION_NONE;
       p.addr            = (uint64_t) addr;
       p.addr2           = 0;
-      p.condition_value = 0;
 
       ALL_LWPS (lp, ptid)
 	booke_insert_point (&p, TIDGET (ptid));
@@ -1721,7 +1766,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, saved_dabr_value) < 0)
+	if (ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0,
+		    saved_dabr_value) < 0)
 	  return -1;
 
       ret = 0;
@@ -1731,7 +1777,8 @@ 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_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw,
+			     struct expression *exp, struct expression *cond)
 {
   struct lwp_info *lp;
   ptid_t ptid;
@@ -1739,15 +1786,30 @@ ppc_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw)
 
   if (have_ptrace_new_debug_booke)
     {
+      int byte_to_enable;
       struct ppc_hw_breakpoint p;
+      CORE_ADDR cond_addr;
+
+      if (cond && ppc_linux_can_use_watchpoint_cond_accel ()
+	  && (watch_address_if_address_equal_literal (exp, cond, &cond_addr)
+	      || watch_var_if_var_equal_literal (exp, cond, &cond_addr)
+	      || watch_var_if_address_equal_literal (exp, cond, &cond_addr)
+	      || watch_address_if_var_equal_literal (exp, cond, &cond_addr))) {
+	byte_to_enable = addr % 4;
+	cond_addr >>= (byte_to_enable * 8);
+	p.condition_mode  = PPC_BREAKPOINT_CONDITION_AND
+			    | PPC_BREAKPOINT_CONDITION_BE (byte_to_enable);
+	p.condition_value = (uint64_t) cond_addr;
+      } 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.condition_mode  = PPC_BREAKPOINT_CONDITION_NONE;
       p.addr            = (uint64_t) addr;
       p.addr2           = 0;
-      p.condition_value = 0;
 
       ALL_LWPS (lp, ptid)
 	booke_remove_point (&p, TIDGET (ptid));
@@ -1758,7 +1820,8 @@ ppc_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw)
     {
       saved_dabr_value = 0;
       ALL_LWPS (lp, ptid)
-	if (ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0, saved_dabr_value) < 0)
+	if (ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0,
+		    saved_dabr_value) < 0)
 	  return -1;
 
       ret = 0;
diff --git a/gdb/procfs.c b/gdb/procfs.c
index 1dd39b2..f373511 100644
--- a/gdb/procfs.c
+++ b/gdb/procfs.c
@@ -5502,7 +5502,8 @@ procfs_stopped_by_watchpoint (void)
 }
 
 static int
-procfs_insert_watchpoint (CORE_ADDR addr, int len, int type)
+procfs_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			  struct expression *exp, struct expression *cond)
 {
   if (!target_have_steppable_watchpoint
       && !gdbarch_have_nonsteppable_watchpoint (target_gdbarch))
@@ -5523,7 +5524,8 @@ procfs_insert_watchpoint (CORE_ADDR addr, int len, int type)
 }
 
 static int
-procfs_remove_watchpoint (CORE_ADDR addr, int len, int type)
+procfs_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			  struct expression *exp, struct expression *cond)
 {
   return procfs_set_watchpoint (inferior_ptid, addr, 0, 0, 0);
 }
diff --git a/gdb/remote-m32r-sdi.c b/gdb/remote-m32r-sdi.c
index be6a564..675bf15 100644
--- a/gdb/remote-m32r-sdi.c
+++ b/gdb/remote-m32r-sdi.c
@@ -1415,7 +1415,8 @@ m32r_can_use_hw_watchpoint (int type, int cnt, int othertype)
    watchpoint. */
 
 static int
-m32r_insert_watchpoint (CORE_ADDR addr, int len, int type)
+m32r_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *exp, struct expression *cond)
 {
   int i;
 
@@ -1439,7 +1440,8 @@ m32r_insert_watchpoint (CORE_ADDR addr, int len, int type)
 }
 
 static int
-m32r_remove_watchpoint (CORE_ADDR addr, int len, int type)
+m32r_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *exp, struct expression *cond)
 {
   int i;
 
diff --git a/gdb/remote-mips.c b/gdb/remote-mips.c
index f2fb8f3..cc4d9f8 100644
--- a/gdb/remote-mips.c
+++ b/gdb/remote-mips.c
@@ -2296,7 +2296,8 @@ calculate_mask (CORE_ADDR addr, int len)
    watchpoint. */
 
 int
-mips_insert_watchpoint (CORE_ADDR addr, int len, int type)
+mips_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *exp, struct expression *cond)
 {
   if (mips_set_breakpoint (addr, len, type))
     return -1;
@@ -2305,7 +2306,8 @@ mips_insert_watchpoint (CORE_ADDR addr, int len, int type)
 }
 
 int
-mips_remove_watchpoint (CORE_ADDR addr, int len, int type)
+mips_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *exp, struct expression *cond)
 {
   if (mips_clear_breakpoint (addr, len, type))
     return -1;
diff --git a/gdb/remote.c b/gdb/remote.c
index 709e424..c8a8906 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -7339,7 +7339,8 @@ watchpoint_to_Z_packet (int type)
 }
 
 static int
-remote_insert_watchpoint (CORE_ADDR addr, int len, int type)
+remote_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			  struct expression *watch_exp, struct expression *cond)
 {
   struct remote_state *rs = get_remote_state ();
   char *p;
@@ -7371,7 +7372,8 @@ remote_insert_watchpoint (CORE_ADDR addr, int len, int type)
 
 
 static int
-remote_remove_watchpoint (CORE_ADDR addr, int len, int type)
+remote_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			  struct expression *watch_exp, struct expression *cond)
 {
   struct remote_state *rs = get_remote_state ();
   char *p;
diff --git a/gdb/s390-nat.c b/gdb/s390-nat.c
index 3af42ff..41ebf9b 100644
--- a/gdb/s390-nat.c
+++ b/gdb/s390-nat.c
@@ -335,7 +335,8 @@ s390_fix_watch_points (ptid_t ptid)
 }
 
 static int
-s390_insert_watchpoint (CORE_ADDR addr, int len, int type)
+s390_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *exp, struct expression *cond)
 {
   struct lwp_info *lp;
   ptid_t ptid;
@@ -356,7 +357,8 @@ s390_insert_watchpoint (CORE_ADDR addr, int len, int type)
 }
 
 static int
-s390_remove_watchpoint (CORE_ADDR addr, int len, int type)
+s390_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *exp, struct expression *cond)
 {
   struct lwp_info *lp;
   ptid_t ptid;
diff --git a/gdb/target.c b/gdb/target.c
index e6659c9..7adc96e 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -44,6 +44,8 @@
 #include "exec.h"
 #include "inline-frame.h"
 
+struct expression;
+
 static void target_info (char *, int);
 
 static void default_terminal_info (char *, int);
@@ -116,9 +118,13 @@ static int debug_to_insert_hw_breakpoint (struct gdbarch *,
 static int debug_to_remove_hw_breakpoint (struct gdbarch *,
 					  struct bp_target_info *);
 
-static int debug_to_insert_watchpoint (CORE_ADDR, int, int);
+static int debug_to_insert_watchpoint (CORE_ADDR, int, int,
+				       struct expression *,
+				       struct expression *);
 
-static int debug_to_remove_watchpoint (CORE_ADDR, int, int);
+static int debug_to_remove_watchpoint (CORE_ADDR, int, int,
+				       struct expression *,
+				       struct expression *);
 
 static int debug_to_stopped_by_watchpoint (void);
 
@@ -705,10 +711,12 @@ update_current_target (void)
 	    (int (*) (struct gdbarch *, struct bp_target_info *))
 	    return_minus_one);
   de_fault (to_insert_watchpoint,
-	    (int (*) (CORE_ADDR, int, int))
+	    (int (*) (CORE_ADDR, int, int, struct expression *,
+		      struct expression *))
 	    return_minus_one);
   de_fault (to_remove_watchpoint,
-	    (int (*) (CORE_ADDR, int, int))
+	    (int (*) (CORE_ADDR, int, int, struct expression *,
+		      struct expression *))
 	    return_minus_one);
   de_fault (to_stopped_by_watchpoint,
 	    (int (*) (void))
@@ -3252,11 +3260,13 @@ debug_to_remove_hw_breakpoint (struct gdbarch *gdbarch,
 }
 
 static int
-debug_to_insert_watchpoint (CORE_ADDR addr, int len, int type)
+debug_to_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			    struct expression *watch_exp,
+			    struct expression *cond)
 {
   int retval;
 
-  retval = debug_target.to_insert_watchpoint (addr, len, type);
+  retval = debug_target.to_insert_watchpoint (addr, len, type, watch_exp, cond);
 
   fprintf_unfiltered (gdb_stdlog,
 		      "target_insert_watchpoint (0x%lx, %d, %d) = %ld\n",
@@ -3265,11 +3275,13 @@ debug_to_insert_watchpoint (CORE_ADDR addr, int len, int type)
 }
 
 static int
-debug_to_remove_watchpoint (CORE_ADDR addr, int len, int type)
+debug_to_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			    struct expression *watch_exp,
+			    struct expression *cond)
 {
   int retval;
 
-  retval = debug_target.to_remove_watchpoint (addr, len, type);
+  retval = debug_target.to_remove_watchpoint (addr, len, type, watch_exp, cond);
 
   fprintf_unfiltered (gdb_stdlog,
 		      "target_remove_watchpoint (0x%lx, %d, %d) = %ld\n",
diff --git a/gdb/target.h b/gdb/target.h
index 7103ab2..a65e900 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -36,6 +36,10 @@ struct trace_status;
 struct uploaded_tsv;
 struct uploaded_tp;
 
+struct bp_location;
+struct breakpoint;
+struct expression;
+
 /* 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
@@ -420,8 +424,10 @@ struct target_ops
     int (*to_can_use_hw_breakpoint) (int, int, int);
     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_remove_watchpoint) (CORE_ADDR, int, int, struct expression *,
+						      struct expression *);
+    int (*to_insert_watchpoint) (CORE_ADDR, int, int, struct expression *,
+						      struct expression *);
     int (*to_stopped_by_watchpoint) (void);
     int to_have_steppable_watchpoint;
     int to_have_continuable_watchpoint;
@@ -1260,19 +1266,20 @@ 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);
 
+#ifndef target_region_ok_for_hw_watchpoint
 #define target_region_ok_for_hw_watchpoint(addr, len) \
     (*current_target.to_region_ok_for_hw_watchpoint) (addr, len)
-
+#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
    success, non-zero for failure.  */
 
-#define	target_insert_watchpoint(addr, len, type)	\
-     (*current_target.to_insert_watchpoint) (addr, len, type)
+#define	target_insert_watchpoint(addr, len, type, watch_exp, cond) \
+     (*current_target.to_insert_watchpoint) (addr, len, type, watch_exp, cond)
 
-#define	target_remove_watchpoint(addr, len, type)	\
-     (*current_target.to_remove_watchpoint) (addr, len, type)
+#define	target_remove_watchpoint(addr, len, type, watch_exp, cond) \
+     (*current_target.to_remove_watchpoint) (addr, len, type, watch_exp, cond)
 
 #define target_insert_hw_breakpoint(gdbarch, bp_tgt) \
      (*current_target.to_insert_hw_breakpoint) (gdbarch, bp_tgt)

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 2/4] Hardware accelerated watchpoint conditions
  2010-02-04 21:48     ` Thiago Jung Bauermann
@ 2010-02-05  5:16       ` Joel Brobecker
  2010-02-08 20:01         ` Thiago Jung Bauermann
  0 siblings, 1 reply; 17+ messages in thread
From: Joel Brobecker @ 2010-02-05  5:16 UTC (permalink / raw)
  To: Thiago Jung Bauermann; +Cc: gdb-patches, Luis Machado, Matt Tyrlik

Good news (see below).

> > I think, from your patch, that GDB will still evaluate the condition
> > once after the watchpoint and its condition trigger. I think that
> > we might want to fix that eventually, but I am actually more than
> > happy to ignore this minor issue for now.  I like baby steps :).
> 
> If I'm following your thought here, I added that on purpose. Before
> letting GDB evaluate the condition one more time, GDB wouldn't know
> which watchpoint triggered if there were two at the same location,
> with different conditions.

I knew that! (if the name DiNozzo comes to mind, then I don't
know what you're talking about ;-) )

> > One of the downsides of this approach is that GDB will no longer
> > be able to print that the condition will be hardware-accelerated
> > when the user creates the watchpoint. I think that's OK for now.
> 
> Yeah, I would like to have that message printed though. Wil have
> to think about it.

Me too. I think we're touching at a larger issue, there (already
pre-discussed with Eli). We'd need to talk to the target sooner,
rather than at insertion time.   I think that's a desirable change
anyway, but I'm unsure of the consequences...

> 2010-02-04  Sergio Durigan Junior  <sergiodj@linux.vnet.ibm.com>
> 	    Thiago Jung Bauermann  <bauerman@br.ibm.com>
> 
> 	* target.h: Add opaque declarations for bp_location, breakpoint and
> 	expression.
> 	(struct target_ops) <to_insert_watchpoint>,
> 	<to_remove_watchpoint>: Add new arguments to pass the watchpoint
> 	expression and its condition.  Update all callers and implementations.
> 	(target_region_ok_for_hw_watchpoint): Surround with ifndef.
> 	* breakpoint.c (exp_is_address): New function.
> 	(exp_is_var): Ditto.
> 	(exp_is_address_equal_literal): Ditto.
> 	(exp_is_var_equal_literal): Ditto.
> 	(watch_address_if_var_equal_literal): Ditto.
> 	(watch_var_if_address_equal_literal): Ditto.
> 	(watch_var_if_var_equal_literal): Ditto.
> 	(watch_address_if_address_equal_literal): Ditto.
> 	* breakpoint.h (watch_address_if_address_equal_literal): Declare.
> 	(watch_var_if_var_equal_literal): Ditto.
> 	(watch_address_if_var_equal_literal): Ditto.
> 	(watch_var_if_address_equal_literal): Ditto.
> 	* ppc-linux-nat.c (ppc_linux_can_use_watchpoint_cond_accel): New
> 	function.
> 	(ppc_linux_insert_watchpoint): Check if it is possible to use
> 	hardware-accelerated condition checking.
> 	(ppc_linux_remove_watchpoint): Check if the watchpoint to delete
> 	has hardware-accelerated condition checking.

Just a few minor nits - pre-approved after the comments are addressed.

> +/* This function is used to determine whether the condition associated
> +   with bp_location B is of the form:
> +
> +   watch *<ADDRESS> if <VAR> == <LITERAL>
> +
> +   If it is, then it sets DATA_VALUE to LITERAL and returns 1.
> +   Otherwise, it returns 0.  */

Can you add a note that VAR must be stored at ADDRESS too?  Same for
similar functions...

> +  /* At this point, all verifications were positive, so we can use
> +     hardware-assisted data-matching.  Set the data value, and return
> +     non-zero.  */

The comment here is a bit too purpose-specific. It betrays its origin :),
but I think we should either drop it (I think that the function description
is sufficently clear), or change it to something more neutral.  Again,
same for all other functions that used the same kind of comment.

> +/* Return greater than zero if the condition associated with
> +   the watchpoint `b' can be treated by the hardware; zero otherwise.
> +
> +   Also stores the data value in `data_value'.  */

I'd drop this comment in breakpoint.h. It duplicates the descriptions
in breakpoint.c...

> +static int
> +ppc_linux_can_use_watchpoint_cond_accel (void)

This function now needs a short description. It's kind of obvious,
what this function does, I agree, but we're trying to be consistent
in our style, and provide always function descriptions unless the
function implements a routine (function pointer) that's already
documented (eg a gdbarch method, or a target_ops routine).


> +	if (p->hw_breaks[i].hw_break != NULL
> +	    && p->hw_breaks[i].hw_break->condition_mode
> +		    != PPC_BREAKPOINT_CONDITION_NONE)

I'm not quite sure, here, but I think that the GNU Coding Style asks
us to parenthesize your not-equal condition, purely for the benefit of
GNU indent:

     if (p->hw_breaks[i].hw_break != NULL
         && (p->hw_breaks[i].hw_break->condition_mode
             != PPC_BREAKPOINT_CONDITION_NONE))

Can you double-check for me?

> +      if (cond && ppc_linux_can_use_watchpoint_cond_accel ()
> +	  && (watch_address_if_address_equal_literal (exp, cond, &cond_addr)
> +	      || watch_var_if_var_equal_literal (exp, cond, &cond_addr)
> +	      || watch_var_if_address_equal_literal (exp, cond, &cond_addr)
> +	      || watch_address_if_var_equal_literal (exp, cond, &cond_addr))) {

Formatting nit: The curly brace should be on the next line.  There are
a few instances where this needs to be fixed.

> +	p.condition_mode  = PPC_BREAKPOINT_CONDITION_AND
> +			    | PPC_BREAKPOINT_CONDITION_BE (byte_to_enable);

Similar to above, I think you'll need to parenthesize the rhs.

    p.condition_mode  = (PPC_BREAKPOINT_CONDITION_AND
                         | PPC_BREAKPOINT_CONDITION_BE (byte_to_enable));

> +	p.condition_value = (uint64_t) cond_addr;
> +      } else {

(curly braces)

> +	      || watch_address_if_var_equal_literal (exp, cond, &cond_addr))) {

(curly brace)

> +	p.condition_mode  = PPC_BREAKPOINT_CONDITION_AND
> +			    | PPC_BREAKPOINT_CONDITION_BE (byte_to_enable);

parenthesize.

> +	p.condition_value = (uint64_t) cond_addr;
> +      } else {

curly braces

> diff --git a/gdb/target.c b/gdb/target.c
> index e6659c9..7adc96e 100644
> --- a/gdb/target.c
> +++ b/gdb/target.c
> @@ -44,6 +44,8 @@
>  #include "exec.h"
>  #include "inline-frame.h"
>  
> +struct expression;
> +

This change is unnecessary (already declared in target.h)...


> diff --git a/gdb/target.h b/gdb/target.h
> index 7103ab2..a65e900 100644
> --- a/gdb/target.h
> +++ b/gdb/target.h
> @@ -36,6 +36,10 @@ struct trace_status;
>  struct uploaded_tsv;
>  struct uploaded_tp;
>  
> +struct bp_location;
> +struct breakpoint;
> +struct expression;

I don't think that declaring struct bp_location is necessary.
I just see that struct breakpoint should probably have been declared
before your patch - so OK.

> +    int (*to_remove_watchpoint) (CORE_ADDR, int, int, struct expression *,
> +						      struct expression *);
> +    int (*to_insert_watchpoint) (CORE_ADDR, int, int, struct expression *,
> +						      struct expression *);

Would you mind adding a comment explaining that documentation of what
these routines are expected to do is provided with the corresponding
target_* macros? I personally think that the complete description
of what these routines are supposed to do should be right there rather
than with the target_ macros, but that's only a very minor matter and
nothing to do with your patch.

> +#ifndef target_region_ok_for_hw_watchpoint
>  #define target_region_ok_for_hw_watchpoint(addr, len) \
>      (*current_target.to_region_ok_for_hw_watchpoint) (addr, len)
> -
> +#endif

This is not right - we no longer allow a macro to be overridden.

>  /* 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
>     success, non-zero for failure.  */
>  
> -#define	target_insert_watchpoint(addr, len, type)	\
> -     (*current_target.to_insert_watchpoint) (addr, len, type)
> +#define	target_insert_watchpoint(addr, len, type, watch_exp, cond) \
> +     (*current_target.to_insert_watchpoint) (addr, len, type, watch_exp, cond)

The macro description needs to be updated (to mention the two new
parameters).

> -#define	target_remove_watchpoint(addr, len, type)	\
> -     (*current_target.to_remove_watchpoint) (addr, len, type)
> +#define	target_remove_watchpoint(addr, len, type, watch_exp, cond) \
> +     (*current_target.to_remove_watchpoint) (addr, len, type, watch_exp, cond)

Can you add a short documentation for this macro?

-- 
Joel

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 2/4] Hardware accelerated watchpoint conditions
  2010-02-05  5:16       ` Joel Brobecker
@ 2010-02-08 20:01         ` Thiago Jung Bauermann
  2010-02-11 18:24           ` Ulrich Weigand
  0 siblings, 1 reply; 17+ messages in thread
From: Thiago Jung Bauermann @ 2010-02-08 20:01 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: gdb-patches, Luis Machado, Matt Tyrlik

[-- Attachment #1: Type: Text/Plain, Size: 8726 bytes --]

On Fri 05 Feb 2010 03:15:55 Joel Brobecker wrote:
> Good news (see below).

Great. :-)
 
> > > I think, from your patch, that GDB will still evaluate the condition
> > > once after the watchpoint and its condition trigger. I think that
> > > we might want to fix that eventually, but I am actually more than
> > > happy to ignore this minor issue for now.  I like baby steps :).
> >
> > If I'm following your thought here, I added that on purpose. Before
> > letting GDB evaluate the condition one more time, GDB wouldn't know
> > which watchpoint triggered if there were two at the same location,
> > with different conditions.
> 
> I knew that! (if the name DiNozzo comes to mind, then I don't
> know what you're talking about ;-) )

Oh, sorry then!
 
> Just a few minor nits - pre-approved after the comments are addressed.

I addressed your comments. I won't commit the patch yet because the kernel patch enabling this code to 
work hasn't been committed upstream yet. I expect it will be accepted soon, so I hope to get this in in 
time for 7.1.

The same applies to the first patch in this series (adapting ppc-linux-nat.c to the new ptrace interface), 
which you approved a while ago...
 
> > +/* This function is used to determine whether the condition associated
> > +   with bp_location B is of the form:
> > +
> > +   watch *<ADDRESS> if <VAR> == <LITERAL>
> > +
> > +   If it is, then it sets DATA_VALUE to LITERAL and returns 1.
> > +   Otherwise, it returns 0.  */
> 
> Can you add a note that VAR must be stored at ADDRESS too?  Same for
> similar functions...

Done.
 
> > +  /* At this point, all verifications were positive, so we can use
> > +     hardware-assisted data-matching.  Set the data value, and return
> > +     non-zero.  */
> 
> The comment here is a bit too purpose-specific. It betrays its origin :),
> but I think we should either drop it (I think that the function description
> is sufficently clear), or change it to something more neutral.  Again,
> same for all other functions that used the same kind of comment.

Dropped.

> > +/* Return greater than zero if the condition associated with
> > +   the watchpoint `b' can be treated by the hardware; zero otherwise.
> > +
> > +   Also stores the data value in `data_value'.  */
> 
> I'd drop this comment in breakpoint.h. It duplicates the descriptions
> in breakpoint.c...

Dropped.
 
> > +static int
> > +ppc_linux_can_use_watchpoint_cond_accel (void)
> 
> This function now needs a short description. It's kind of obvious,
> what this function does, I agree, but we're trying to be consistent
> in our style, and provide always function descriptions unless the
> function implements a routine (function pointer) that's already
> documented (eg a gdbarch method, or a target_ops routine).

I added this concise description:

/* Check whether we have at least one free DVC register.  */
 
> > +	if (p->hw_breaks[i].hw_break != NULL
> > +	    && p->hw_breaks[i].hw_break->condition_mode
> > +		    != PPC_BREAKPOINT_CONDITION_NONE)
> 
> I'm not quite sure, here, but I think that the GNU Coding Style asks
> us to parenthesize your not-equal condition, purely for the benefit of
> GNU indent:
> 
>      if (p->hw_breaks[i].hw_break != NULL
>          && (p->hw_breaks[i].hw_break->condition_mode
>              != PPC_BREAKPOINT_CONDITION_NONE))
> 
> Can you double-check for me?

It does mention that. Changed.
 
> > +      if (cond && ppc_linux_can_use_watchpoint_cond_accel ()
> > +	  && (watch_address_if_address_equal_literal (exp, cond, &cond_addr)
> > +	      || watch_var_if_var_equal_literal (exp, cond, &cond_addr)
> > +	      || watch_var_if_address_equal_literal (exp, cond, &cond_addr)
> > +	      || watch_address_if_var_equal_literal (exp, cond, &cond_addr))) {
> 
> Formatting nit: The curly brace should be on the next line.  There are
> a few instances where this needs to be fixed.

Fixed this and the other instances.
 
> > +	p.condition_mode  = PPC_BREAKPOINT_CONDITION_AND
> > +			    | PPC_BREAKPOINT_CONDITION_BE (byte_to_enable);
> 
> Similar to above, I think you'll need to parenthesize the rhs.
> 

Fixed this and the other instance.

> > diff --git a/gdb/target.c b/gdb/target.c
> > index e6659c9..7adc96e 100644
> > --- a/gdb/target.c
> > +++ b/gdb/target.c
> > @@ -44,6 +44,8 @@
> >  #include "exec.h"
> >  #include "inline-frame.h"
> >
> > +struct expression;
> > +
> 
> This change is unnecessary (already declared in target.h)...

Dropped.
 
> > diff --git a/gdb/target.h b/gdb/target.h
> > index 7103ab2..a65e900 100644
> > --- a/gdb/target.h
> > +++ b/gdb/target.h
> > @@ -36,6 +36,10 @@ struct trace_status;
> >  struct uploaded_tsv;
> >  struct uploaded_tp;
> >
> > +struct bp_location;
> > +struct breakpoint;
> > +struct expression;
> 
> I don't think that declaring struct bp_location is necessary.
> I just see that struct breakpoint should probably have been declared
> before your patch - so OK.

Dropped struct bp_location, kept the other two.
 
> > +    int (*to_remove_watchpoint) (CORE_ADDR, int, int, struct expression
> > *, +						      struct expression *);
> > +    int (*to_insert_watchpoint) (CORE_ADDR, int, int, struct expression
> > *, +						      struct expression *);
> 
> Would you mind adding a comment explaining that documentation of what
> these routines are expected to do is provided with the corresponding
> target_* macros? I personally think that the complete description
> of what these routines are supposed to do should be right there rather
> than with the target_ macros, but that's only a very minor matter and
> nothing to do with your patch.

Added:

   /* Documentation of what the two routines below are expected to do is
       provided with the corresponding target_* macros.  */

> > +#ifndef target_region_ok_for_hw_watchpoint
> >  #define target_region_ok_for_hw_watchpoint(addr, len) \
> >      (*current_target.to_region_ok_for_hw_watchpoint) (addr, len)
> > -
> > +#endif
> 
> This is not right - we no longer allow a macro to be overridden.

Ok, dropped.
 
> >  /* 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 success, non-zero for failure.  */
> >
> > -#define	target_insert_watchpoint(addr, len, type)	\
> > -     (*current_target.to_insert_watchpoint) (addr, len, type)
> > +#define	target_insert_watchpoint(addr, len, type, watch_exp, cond) \
> > +     (*current_target.to_insert_watchpoint) (addr, len, type, watch_exp,
> > cond)
> 
> The macro description needs to be updated (to mention the two new
> parameters).

Updated.
 
> > -#define	target_remove_watchpoint(addr, len, type)	\
> > -     (*current_target.to_remove_watchpoint) (addr, len, type)
> > +#define	target_remove_watchpoint(addr, len, type, watch_exp, cond) \
> > +     (*current_target.to_remove_watchpoint) (addr, len, type, watch_exp,
> > cond)
> 
> Can you add a short documentation for this macro?
 
It is already documented, in a comment above target_insert_watchpoint (which
is defined right before target_remove_watchpoint):

/* 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.  WATCH_EXP is the
   watchpoint's expression and COND is the expression for its condition,
   or NULL if there's none.  Returns 0 for success, non-zero for failure.  */

-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center


2010-02-08  Sergio Durigan Junior  <sergiodj@linux.vnet.ibm.com>
	    Thiago Jung Bauermann  <bauerman@br.ibm.com>

	* target.h: Add opaque declarations for bp_location, breakpoint and
	expression.
	(struct target_ops) <to_insert_watchpoint>,
	<to_remove_watchpoint>: Add new arguments to pass the watchpoint
	expression and its condition.  Update all callers and implementations.
	(target_region_ok_for_hw_watchpoint): Surround with ifndef.
	* breakpoint.c (exp_is_address): New function.
	(exp_is_var): Ditto.
	(exp_is_address_equal_literal): Ditto.
	(exp_is_var_equal_literal): Ditto.
	(watch_address_if_var_equal_literal): Ditto.
	(watch_var_if_address_equal_literal): Ditto.
	(watch_var_if_var_equal_literal): Ditto.
	(watch_address_if_address_equal_literal): Ditto.
	* breakpoint.h (watch_address_if_address_equal_literal): Declare.
	(watch_var_if_var_equal_literal): Ditto.
	(watch_address_if_var_equal_literal): Ditto.
	(watch_var_if_address_equal_literal): Ditto.
	* ppc-linux-nat.c (ppc_linux_can_use_watchpoint_cond_accel): New
	function.
	(ppc_linux_insert_watchpoint): Check if it is possible to use
	hardware-accelerated condition checking.
	(ppc_linux_remove_watchpoint): Check if the watchpoint to delete
	has hardware-accelerated condition checking.

[-- Attachment #2: ppc476-condition.diff --]
[-- Type: text/x-patch, Size: 26461 bytes --]

commit f29957ec421daceca6e557d16549e0efc0358ff8
Author: Thiago Jung Bauermann <bauermann@hactar.cps.virtua.com.br>
Date:   Mon Dec 28 14:25:01 2009 -0200

    Hardware accelerated watchpoint conditions.

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 0d55862..98f1cd1 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -1485,9 +1485,10 @@ Note: automatically using hardware breakpoints for read-only addresses.\n"));
 	      watchpoints.  It's not clear that it's necessary... */
 	   && bpt->owner->disposition != disp_del_at_next_stop)
     {
-      val = target_insert_watchpoint (bpt->address, 
+      val = target_insert_watchpoint (bpt->address,
 				      bpt->length,
-				      bpt->watchpoint_type);
+				      bpt->watchpoint_type,
+				      bpt->owner->exp, bpt->cond);
       bpt->inserted = (val != -1);
     }
 
@@ -2109,12 +2110,10 @@ remove_breakpoint_1 (struct bp_location *b, insertion_state_t is)
     }
   else if (b->loc_type == bp_loc_hardware_watchpoint)
     {
-      struct value *v;
-      struct value *n;
-
       b->inserted = (is == mark_inserted);
-      val = target_remove_watchpoint (b->address, b->length, 
-				      b->watchpoint_type);
+      val = target_remove_watchpoint (b->address, b->length,
+				      b->watchpoint_type,
+				      b->owner->exp, b->cond);
 
       /* Failure to remove any of the hardware watchpoints comes here.  */
       if ((is == mark_uninserted) && (b->inserted))
@@ -10156,6 +10155,210 @@ tracepoint_save_command (char *args, int from_tty)
   return;
 }
 
+/* This function checks if the expression is of the form "*<address>".
+   It returns 1 if it is, 0 otherwise.  */
+static int
+exp_is_address (struct expression *exp)
+{
+  if (exp->nelts != 5
+      || exp->elts[0].opcode != UNOP_IND
+      || exp->elts[1].opcode != OP_LONG)
+      return 0;
+  return 1;
+}
+
+/* This function checks if the expression is of the form "<var>".
+   It returns 1 if it is, 0 otherwise.  */
+static int
+exp_is_var (struct expression *exp)
+{
+  if (exp->nelts != 4
+      || exp->elts[0].opcode != OP_VAR_VALUE)
+      return 0;
+  return 1;
+}
+
+/* This function checks if the expression is of the form
+   "*<address> == LITERAL".  It returns 1 if it is, 0 otherwise.  */
+static int
+exp_is_address_equal_literal (struct expression *exp)
+{
+  if (exp->nelts == 10
+      && exp->elts[0].opcode == BINOP_EQUAL
+      && exp->elts[1].opcode == UNOP_IND
+      && exp->elts[2].opcode == OP_LONG
+      && exp->elts[6].opcode == OP_LONG)
+      return 1;
+  else if (exp->nelts == 11
+      && exp->elts[0].opcode == BINOP_EQUAL
+      && exp->elts[1].opcode == UNOP_IND
+      && exp->elts[2].opcode == OP_LONG
+      && exp->elts[6].opcode == UNOP_NEG
+      && exp->elts[7].opcode == OP_LONG)
+      return 1;
+
+  return 0;
+}
+
+/* This function checks if the expression is of the form "<var> == LITERAL".
+   It returns 1 if it is, 0 otherwise.  */
+static int
+exp_is_var_equal_literal (struct expression *exp)
+{
+  if (exp->nelts == 9
+      && exp->elts[0].opcode == BINOP_EQUAL
+      && exp->elts[1].opcode == OP_VAR_VALUE
+      && exp->elts[5].opcode == OP_LONG)
+      return 1;
+  else if (exp->nelts == 10
+      && exp->elts[0].opcode == BINOP_EQUAL
+      && exp->elts[1].opcode == OP_VAR_VALUE
+      && exp->elts[5].opcode == UNOP_NEG
+      && exp->elts[6].opcode == OP_LONG)
+      return 1;
+
+  return 0;
+}
+
+/* This function is used to determine whether the condition associated
+   with bp_location B is of the form:
+
+   watch *<ADDRESS> if <VAR> == <LITERAL>
+
+   It also checks whether <VAR> is stored at <ADDRESS>.  If these
+   conditions are met, then it sets DATA_VALUE to LITERAL and returns 1.
+   Otherwise, it returns 0.  */
+int
+watch_address_if_var_equal_literal (struct expression *exp,
+				    struct expression *cond,
+				    CORE_ADDR *data_value)
+{
+  int pc;
+  CORE_ADDR exp_address, cond_address;
+
+  if (!exp_is_address (exp)
+      || !exp_is_var_equal_literal (cond))
+    return 0;
+
+  exp_address = exp->elts[3].longconst;
+  cond_address = value_as_address (address_of_variable (cond->elts[3].symbol,
+							cond->elts[2].block));
+
+  /* Make sure that the two addresses are the same.  */
+  if (exp_address != cond_address)
+    return 0;
+
+  pc = 5;
+  *data_value = value_as_long (evaluate_subexp (NULL_TYPE, cond, &pc,
+						EVAL_NORMAL));
+
+  return 1;
+}
+
+/* This function is used to determine whether the condition associated
+   with bp_location B is of the form:
+
+   watch <VAR> if *<ADDRESS> == <LITERAL>
+
+   It also checks whether <VAR> is stored at <ADDRESS>.  If these
+   conditions are met, then it sets DATA_VALUE to LITERAL and returns 1.
+   Otherwise, it returns 0.  */
+int
+watch_var_if_address_equal_literal (struct expression *exp,
+				    struct expression *cond,
+				    CORE_ADDR *data_value)
+{
+  int pc;
+  CORE_ADDR exp_address, cond_address;
+
+  if (!exp_is_var (exp)
+      || !exp_is_address_equal_literal (cond))
+    return 0;
+
+  exp_address = value_as_address (address_of_variable (exp->elts[2].symbol,
+						       exp->elts[1].block));
+  cond_address = cond->elts[4].longconst;
+
+  /* Make sure that the two addresses are the same.  */
+  if (exp_address != cond_address)
+    return 0;
+
+  pc = 6;
+  *data_value = value_as_long (evaluate_subexp (NULL_TYPE, cond, &pc,
+						EVAL_NORMAL));
+
+  return 1;
+}
+
+/* This function is used to determine whether the condition associated
+   with bp_location B is of the form:
+
+   watch <VAR1> if <VAR2> == <LITERAL>
+
+   It also checks whether <VAR1> and <VAR2> are stored at the same address.
+   If these conditions are met, then it sets DATA_VALUE to LITERAL and
+   returns 1.  Otherwise, it returns 0.  */
+int
+watch_var_if_var_equal_literal (struct expression *exp,
+				struct expression *cond,
+				CORE_ADDR *data_value)
+{
+  int pc;
+  CORE_ADDR exp_address, cond_address;
+
+  if (!exp_is_var (exp)
+      || !exp_is_var_equal_literal (cond))
+    return 0;
+
+  exp_address = value_as_address (address_of_variable (exp->elts[2].symbol,
+						       exp->elts[1].block));
+  cond_address = value_as_address (address_of_variable (cond->elts[3].symbol,
+							cond->elts[2].block));
+
+  if (exp_address != cond_address)
+    return 0;
+
+  pc = 5;
+  *data_value = value_as_long (evaluate_subexp (NULL_TYPE, cond, &pc,
+						EVAL_NORMAL));
+
+  return 1;
+}
+
+/* This function is used to determine whether the condition associated
+   with bp_location B is of the form:
+
+   watch *<ADDRESS1> if *<ADDRESS2> == <LITERAL>
+
+   It also checks whether <ADDRESS1> AND <ADDRESS2> are the same.  If these
+   conditions are met, then it sets DATA_VALUE to LITERAL and returns 1.
+   Otherwise, it returns 0.  */
+int
+watch_address_if_address_equal_literal (struct expression *exp,
+					struct expression *cond,
+					CORE_ADDR *data_value)
+{
+  int pc;
+  CORE_ADDR exp_address, cond_address;
+
+  if (!exp_is_address (exp)
+      || !exp_is_address_equal_literal (cond))
+    return 0;
+
+  exp_address = exp->elts[3].longconst;
+  cond_address = cond->elts[4].longconst;
+
+  /* Make sure that the two addresses are the same.  */
+  if (exp_address != cond_address)
+    return 0;
+
+  pc = 6;
+  *data_value = value_as_long (evaluate_subexp (NULL_TYPE, cond, &pc,
+						EVAL_NORMAL));
+
+  return 1;
+}
+
 /* Create a vector of all tracepoints.  */
 
 VEC(breakpoint_p) *
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 6b373a3..1864a84 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -998,4 +998,20 @@ extern struct breakpoint *get_tracepoint_by_number (char **arg, int multi_p,
    is newly allocated; the caller should free when done with it.  */
 extern VEC(breakpoint_p) *all_tracepoints (void);
 
+extern int watch_address_if_address_equal_literal (struct expression *exp,
+						     struct expression *cond,
+						     CORE_ADDR *data_value);
+
+extern int watch_var_if_var_equal_literal (struct expression *exp,
+					     struct expression *cond,
+					     CORE_ADDR *data_value);
+
+extern int watch_address_if_var_equal_literal (struct expression *exp,
+						 struct expression *cond,
+						 CORE_ADDR *data_value);
+
+extern int watch_var_if_address_equal_literal (struct expression *exp,
+					     struct expression *cond,
+					     CORE_ADDR *data_value);
+
 #endif /* !defined (BREAKPOINT_H) */
diff --git a/gdb/i386-nat.c b/gdb/i386-nat.c
index fa0cce6..1062b74 100644
--- a/gdb/i386-nat.c
+++ b/gdb/i386-nat.c
@@ -483,7 +483,8 @@ Invalid value %d of operation in i386_handle_nonaligned_watchpoint.\n"),
    of the type TYPE.  Return 0 on success, -1 on failure.  */
 
 static int
-i386_insert_watchpoint (CORE_ADDR addr, int len, int type)
+i386_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *exp, struct expression *cond)
 {
   int retval;
 
@@ -507,7 +508,8 @@ i386_insert_watchpoint (CORE_ADDR addr, int len, int type)
    address ADDR, whose length is LEN bytes, and for accesses of the
    type TYPE.  Return 0 on success, -1 on failure.  */
 static int
-i386_remove_watchpoint (CORE_ADDR addr, int len, int type)
+i386_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *exp, struct expression *cond)
 {
   int retval;
 
diff --git a/gdb/ia64-linux-nat.c b/gdb/ia64-linux-nat.c
index e6a7077..f68f77a 100644
--- a/gdb/ia64-linux-nat.c
+++ b/gdb/ia64-linux-nat.c
@@ -530,7 +530,8 @@ is_power_of_2 (int val)
 }
 
 static int
-ia64_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw)
+ia64_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw,
+			      struct expression *exp, struct expression *cond)
 {
   struct lwp_info *lp;
   ptid_t ptid;
@@ -584,7 +585,8 @@ ia64_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw)
 }
 
 static int
-ia64_linux_remove_watchpoint (CORE_ADDR addr, int len, int type)
+ia64_linux_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			      struct expression *exp, struct expression *cond)
 {
   int idx;
   long dbr_addr, dbr_mask;
diff --git a/gdb/inf-ttrace.c b/gdb/inf-ttrace.c
index c9ab548..dab9065 100644
--- a/gdb/inf-ttrace.c
+++ b/gdb/inf-ttrace.c
@@ -314,7 +314,8 @@ inf_ttrace_disable_page_protections (pid_t pid)
    type TYPE.  */
 
 static int
-inf_ttrace_insert_watchpoint (CORE_ADDR addr, int len, int type)
+inf_ttrace_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			      struct expression *exp, struct expression *cond)
 {
   const int pagesize = inf_ttrace_page_dict.pagesize;
   pid_t pid = ptid_get_pid (inferior_ptid);
@@ -337,7 +338,8 @@ inf_ttrace_insert_watchpoint (CORE_ADDR addr, int len, int type)
    type TYPE.  */
 
 static int
-inf_ttrace_remove_watchpoint (CORE_ADDR addr, int len, int type)
+inf_ttrace_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			      struct expression *exp, struct expression *cond)
 {
   const int pagesize = inf_ttrace_page_dict.pagesize;
   pid_t pid = ptid_get_pid (inferior_ptid);
diff --git a/gdb/mips-linux-nat.c b/gdb/mips-linux-nat.c
index fe05192..9d36a39 100644
--- a/gdb/mips-linux-nat.c
+++ b/gdb/mips-linux-nat.c
@@ -926,7 +926,8 @@ populate_regs_from_watches (struct pt_watch_regs *regs)
    watch.  Return zero on success.  */
 
 static int
-mips_linux_insert_watchpoint (CORE_ADDR addr, int len, int type)
+mips_linux_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			      struct expression *exp, struct expression *cond)
 {
   struct pt_watch_regs regs;
   struct mips_watchpoint *new_watch;
@@ -975,7 +976,8 @@ mips_linux_insert_watchpoint (CORE_ADDR addr, int len, int type)
    Return zero on success.  */
 
 static int
-mips_linux_remove_watchpoint (CORE_ADDR addr, int len, int type)
+mips_linux_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			      struct expression *exp, struct expression *cond)
 {
   int retval;
   int deleted_one;
diff --git a/gdb/nto-procfs.c b/gdb/nto-procfs.c
index d8f3c91..d37f259 100644
--- a/gdb/nto-procfs.c
+++ b/gdb/nto-procfs.c
@@ -1509,13 +1509,15 @@ procfs_can_use_hw_breakpoint (int type, int cnt, int othertype)
 }
 
 static int
-procfs_remove_hw_watchpoint (CORE_ADDR addr, int len, int type)
+procfs_remove_hw_watchpoint (CORE_ADDR addr, int len, int type,
+			     struct expression *exp, struct expression *cond)
 {
   return procfs_hw_watchpoint (addr, -1, type);
 }
 
 static int
-procfs_insert_hw_watchpoint (CORE_ADDR addr, int len, int type)
+procfs_insert_hw_watchpoint (CORE_ADDR addr, int len, int type,
+			     struct expression *exp, struct expression *cond)
 {
   return procfs_hw_watchpoint (addr, len, type);
 }
diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c
index 9c76387..56c5aa7 100644
--- a/gdb/ppc-linux-nat.c
+++ b/gdb/ppc-linux-nat.c
@@ -1517,6 +1517,36 @@ booke_find_thread_points_by_tid (int tid, int alloc_new)
   return t;
 }
 
+/* Check whether we have at least one free DVC register.  */
+static int
+ppc_linux_can_use_watchpoint_cond_accel (void)
+{
+  struct thread_points *p;
+  int tid = TIDGET (inferior_ptid);
+  int cnt = booke_debug_info.num_condition_regs, i;
+  CORE_ADDR tmp_value;
+
+  if (!have_ptrace_new_debug_booke)
+    return 0;
+
+  p = booke_find_thread_points_by_tid (tid, 0);
+
+  if (p)
+    {
+      for (i = 0; i < max_slots_number; i++)
+	if (p->hw_breaks[i].hw_break != NULL
+	    && (p->hw_breaks[i].hw_break->condition_mode
+		!= PPC_BREAKPOINT_CONDITION_NONE))
+	  cnt--;
+
+      /* There are no available slots now.  */
+      if (cnt <= 0)
+	return 0;
+    }
+
+  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 in GDB.  */
@@ -1658,7 +1688,8 @@ get_trigger_type (int rw)
 }
 
 static int
-ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw)
+ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw,
+			     struct expression *exp, struct expression *cond)
 {
   struct lwp_info *lp;
   ptid_t ptid;
@@ -1666,15 +1697,33 @@ ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw)
 
   if (have_ptrace_new_debug_booke)
     {
+      int byte_to_enable;
       struct ppc_hw_breakpoint p;
+      CORE_ADDR cond_addr;
+
+      if (cond && ppc_linux_can_use_watchpoint_cond_accel ()
+	  && (watch_address_if_address_equal_literal (exp, cond, &cond_addr)
+	      || watch_var_if_var_equal_literal (exp, cond, &cond_addr)
+	      || watch_var_if_address_equal_literal (exp, cond, &cond_addr)
+	      || watch_address_if_var_equal_literal (exp, cond, &cond_addr)))
+	{
+	  byte_to_enable = addr % 4;
+	  cond_addr >>= (byte_to_enable * 8);
+	  p.condition_mode  = (PPC_BREAKPOINT_CONDITION_AND
+			       | PPC_BREAKPOINT_CONDITION_BE (byte_to_enable));
+	  p.condition_value = (uint64_t) cond_addr;
+	}
+      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.condition_mode  = PPC_BREAKPOINT_CONDITION_NONE;
       p.addr            = (uint64_t) addr;
       p.addr2           = 0;
-      p.condition_value = 0;
 
       ALL_LWPS (lp, ptid)
 	booke_insert_point (&p, TIDGET (ptid));
@@ -1721,7 +1770,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, saved_dabr_value) < 0)
+	if (ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0,
+		    saved_dabr_value) < 0)
 	  return -1;
 
       ret = 0;
@@ -1731,7 +1781,8 @@ 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_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw,
+			     struct expression *exp, struct expression *cond)
 {
   struct lwp_info *lp;
   ptid_t ptid;
@@ -1739,15 +1790,33 @@ ppc_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw)
 
   if (have_ptrace_new_debug_booke)
     {
+      int byte_to_enable;
       struct ppc_hw_breakpoint p;
+      CORE_ADDR cond_addr;
+
+      if (cond && ppc_linux_can_use_watchpoint_cond_accel ()
+	  && (watch_address_if_address_equal_literal (exp, cond, &cond_addr)
+	      || watch_var_if_var_equal_literal (exp, cond, &cond_addr)
+	      || watch_var_if_address_equal_literal (exp, cond, &cond_addr)
+	      || watch_address_if_var_equal_literal (exp, cond, &cond_addr)))
+	{
+	  byte_to_enable = addr % 4;
+	  cond_addr >>= (byte_to_enable * 8);
+	  p.condition_mode  = (PPC_BREAKPOINT_CONDITION_AND
+			       | PPC_BREAKPOINT_CONDITION_BE (byte_to_enable));
+	  p.condition_value = (uint64_t) cond_addr;
+	}
+      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.condition_mode  = PPC_BREAKPOINT_CONDITION_NONE;
       p.addr            = (uint64_t) addr;
       p.addr2           = 0;
-      p.condition_value = 0;
 
       ALL_LWPS (lp, ptid)
 	booke_remove_point (&p, TIDGET (ptid));
@@ -1758,7 +1827,8 @@ ppc_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw)
     {
       saved_dabr_value = 0;
       ALL_LWPS (lp, ptid)
-	if (ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0, saved_dabr_value) < 0)
+	if (ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0,
+		    saved_dabr_value) < 0)
 	  return -1;
 
       ret = 0;
diff --git a/gdb/procfs.c b/gdb/procfs.c
index 1dd39b2..f373511 100644
--- a/gdb/procfs.c
+++ b/gdb/procfs.c
@@ -5502,7 +5502,8 @@ procfs_stopped_by_watchpoint (void)
 }
 
 static int
-procfs_insert_watchpoint (CORE_ADDR addr, int len, int type)
+procfs_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			  struct expression *exp, struct expression *cond)
 {
   if (!target_have_steppable_watchpoint
       && !gdbarch_have_nonsteppable_watchpoint (target_gdbarch))
@@ -5523,7 +5524,8 @@ procfs_insert_watchpoint (CORE_ADDR addr, int len, int type)
 }
 
 static int
-procfs_remove_watchpoint (CORE_ADDR addr, int len, int type)
+procfs_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			  struct expression *exp, struct expression *cond)
 {
   return procfs_set_watchpoint (inferior_ptid, addr, 0, 0, 0);
 }
diff --git a/gdb/remote-m32r-sdi.c b/gdb/remote-m32r-sdi.c
index be6a564..675bf15 100644
--- a/gdb/remote-m32r-sdi.c
+++ b/gdb/remote-m32r-sdi.c
@@ -1415,7 +1415,8 @@ m32r_can_use_hw_watchpoint (int type, int cnt, int othertype)
    watchpoint. */
 
 static int
-m32r_insert_watchpoint (CORE_ADDR addr, int len, int type)
+m32r_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *exp, struct expression *cond)
 {
   int i;
 
@@ -1439,7 +1440,8 @@ m32r_insert_watchpoint (CORE_ADDR addr, int len, int type)
 }
 
 static int
-m32r_remove_watchpoint (CORE_ADDR addr, int len, int type)
+m32r_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *exp, struct expression *cond)
 {
   int i;
 
diff --git a/gdb/remote-mips.c b/gdb/remote-mips.c
index f2fb8f3..cc4d9f8 100644
--- a/gdb/remote-mips.c
+++ b/gdb/remote-mips.c
@@ -2296,7 +2296,8 @@ calculate_mask (CORE_ADDR addr, int len)
    watchpoint. */
 
 int
-mips_insert_watchpoint (CORE_ADDR addr, int len, int type)
+mips_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *exp, struct expression *cond)
 {
   if (mips_set_breakpoint (addr, len, type))
     return -1;
@@ -2305,7 +2306,8 @@ mips_insert_watchpoint (CORE_ADDR addr, int len, int type)
 }
 
 int
-mips_remove_watchpoint (CORE_ADDR addr, int len, int type)
+mips_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *exp, struct expression *cond)
 {
   if (mips_clear_breakpoint (addr, len, type))
     return -1;
diff --git a/gdb/remote.c b/gdb/remote.c
index 709e424..c8a8906 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -7339,7 +7339,8 @@ watchpoint_to_Z_packet (int type)
 }
 
 static int
-remote_insert_watchpoint (CORE_ADDR addr, int len, int type)
+remote_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			  struct expression *watch_exp, struct expression *cond)
 {
   struct remote_state *rs = get_remote_state ();
   char *p;
@@ -7371,7 +7372,8 @@ remote_insert_watchpoint (CORE_ADDR addr, int len, int type)
 
 
 static int
-remote_remove_watchpoint (CORE_ADDR addr, int len, int type)
+remote_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			  struct expression *watch_exp, struct expression *cond)
 {
   struct remote_state *rs = get_remote_state ();
   char *p;
diff --git a/gdb/s390-nat.c b/gdb/s390-nat.c
index 3af42ff..41ebf9b 100644
--- a/gdb/s390-nat.c
+++ b/gdb/s390-nat.c
@@ -335,7 +335,8 @@ s390_fix_watch_points (ptid_t ptid)
 }
 
 static int
-s390_insert_watchpoint (CORE_ADDR addr, int len, int type)
+s390_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *exp, struct expression *cond)
 {
   struct lwp_info *lp;
   ptid_t ptid;
@@ -356,7 +357,8 @@ s390_insert_watchpoint (CORE_ADDR addr, int len, int type)
 }
 
 static int
-s390_remove_watchpoint (CORE_ADDR addr, int len, int type)
+s390_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *exp, struct expression *cond)
 {
   struct lwp_info *lp;
   ptid_t ptid;
diff --git a/gdb/target.c b/gdb/target.c
index e6659c9..95ab2fc 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -116,9 +116,13 @@ static int debug_to_insert_hw_breakpoint (struct gdbarch *,
 static int debug_to_remove_hw_breakpoint (struct gdbarch *,
 					  struct bp_target_info *);
 
-static int debug_to_insert_watchpoint (CORE_ADDR, int, int);
+static int debug_to_insert_watchpoint (CORE_ADDR, int, int,
+				       struct expression *,
+				       struct expression *);
 
-static int debug_to_remove_watchpoint (CORE_ADDR, int, int);
+static int debug_to_remove_watchpoint (CORE_ADDR, int, int,
+				       struct expression *,
+				       struct expression *);
 
 static int debug_to_stopped_by_watchpoint (void);
 
@@ -705,10 +709,12 @@ update_current_target (void)
 	    (int (*) (struct gdbarch *, struct bp_target_info *))
 	    return_minus_one);
   de_fault (to_insert_watchpoint,
-	    (int (*) (CORE_ADDR, int, int))
+	    (int (*) (CORE_ADDR, int, int, struct expression *,
+		      struct expression *))
 	    return_minus_one);
   de_fault (to_remove_watchpoint,
-	    (int (*) (CORE_ADDR, int, int))
+	    (int (*) (CORE_ADDR, int, int, struct expression *,
+		      struct expression *))
 	    return_minus_one);
   de_fault (to_stopped_by_watchpoint,
 	    (int (*) (void))
@@ -3252,11 +3258,13 @@ debug_to_remove_hw_breakpoint (struct gdbarch *gdbarch,
 }
 
 static int
-debug_to_insert_watchpoint (CORE_ADDR addr, int len, int type)
+debug_to_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			    struct expression *watch_exp,
+			    struct expression *cond)
 {
   int retval;
 
-  retval = debug_target.to_insert_watchpoint (addr, len, type);
+  retval = debug_target.to_insert_watchpoint (addr, len, type, watch_exp, cond);
 
   fprintf_unfiltered (gdb_stdlog,
 		      "target_insert_watchpoint (0x%lx, %d, %d) = %ld\n",
@@ -3265,11 +3273,13 @@ debug_to_insert_watchpoint (CORE_ADDR addr, int len, int type)
 }
 
 static int
-debug_to_remove_watchpoint (CORE_ADDR addr, int len, int type)
+debug_to_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			    struct expression *watch_exp,
+			    struct expression *cond)
 {
   int retval;
 
-  retval = debug_target.to_remove_watchpoint (addr, len, type);
+  retval = debug_target.to_remove_watchpoint (addr, len, type, watch_exp, cond);
 
   fprintf_unfiltered (gdb_stdlog,
 		      "target_remove_watchpoint (0x%lx, %d, %d) = %ld\n",
diff --git a/gdb/target.h b/gdb/target.h
index 7103ab2..4f747c5 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -36,6 +36,9 @@ struct trace_status;
 struct uploaded_tsv;
 struct uploaded_tp;
 
+struct breakpoint;
+struct expression;
+
 /* 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
@@ -420,8 +423,14 @@ struct target_ops
     int (*to_can_use_hw_breakpoint) (int, int, int);
     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);
+
+    /* Documentation of what the two routines below are expected to do is
+       provided with the corresponding target_* macros.  */
+    int (*to_remove_watchpoint) (CORE_ADDR, int, int, struct expression *,
+						      struct expression *);
+    int (*to_insert_watchpoint) (CORE_ADDR, int, int, struct expression *,
+						      struct expression *);
+
     int (*to_stopped_by_watchpoint) (void);
     int to_have_steppable_watchpoint;
     int to_have_continuable_watchpoint;
@@ -1263,16 +1272,16 @@ extern char *normal_pid_to_str (ptid_t ptid);
 #define target_region_ok_for_hw_watchpoint(addr, len) \
     (*current_target.to_region_ok_for_hw_watchpoint) (addr, len)
 
-
 /* 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
-   success, non-zero for failure.  */
+   for write, 1 for read, and 2 for read/write accesses.  WATCH_EXP is the
+   watchpoint's expression and COND is the expression for its condition,
+   or NULL if there's none.  Returns 0 for success, non-zero for failure.  */
 
-#define	target_insert_watchpoint(addr, len, type)	\
-     (*current_target.to_insert_watchpoint) (addr, len, type)
+#define	target_insert_watchpoint(addr, len, type, watch_exp, cond) \
+     (*current_target.to_insert_watchpoint) (addr, len, type, watch_exp, cond)
 
-#define	target_remove_watchpoint(addr, len, type)	\
-     (*current_target.to_remove_watchpoint) (addr, len, type)
+#define	target_remove_watchpoint(addr, len, type, watch_exp, cond) \
+     (*current_target.to_remove_watchpoint) (addr, len, type, watch_exp, cond)
 
 #define target_insert_hw_breakpoint(gdbarch, bp_tgt) \
      (*current_target.to_insert_hw_breakpoint) (gdbarch, bp_tgt)

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 2/4] Hardware accelerated watchpoint conditions
  2010-02-08 20:01         ` Thiago Jung Bauermann
@ 2010-02-11 18:24           ` Ulrich Weigand
  2010-06-09  4:02             ` Thiago Jung Bauermann
  0 siblings, 1 reply; 17+ messages in thread
From: Ulrich Weigand @ 2010-02-11 18:24 UTC (permalink / raw)
  To: Thiago Jung Bauermann
  Cc: Joel Brobecker, gdb-patches, Luis Machado, Matt Tyrlik

Thiago Jung Bauermann wrote:

> @@ -1666,15 +1697,33 @@ ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw)
>  
>    if (have_ptrace_new_debug_booke)
>      {
> +      int byte_to_enable;
>        struct ppc_hw_breakpoint p;
> +      CORE_ADDR cond_addr;

The naming confused me as cond_addr turns out to hold the *data* value
to be compared against, not any address ;-)

> +
> +      if (cond && ppc_linux_can_use_watchpoint_cond_accel ()
> +	  && (watch_address_if_address_equal_literal (exp, cond, &cond_addr)
> +	      || watch_var_if_var_equal_literal (exp, cond, &cond_addr)
> +	      || watch_var_if_address_equal_literal (exp, cond, &cond_addr)
> +	      || watch_address_if_var_equal_literal (exp, cond, &cond_addr)))

This logic, together with the variety of special-purpose subroutines,
strikes me as overly restrictive on the syntactical format of the
condition expression, for example:
- why shouldn't "if VAR.MEMBER == LITERAL" be allowed?
- why shouldn't "if VAR == <constant expression>" be allowed?

What we really need here is a variant of expression evaluation that
is "extremely lazy" and stops as soon as any reference to target
memory or register contents would be made.  If we run both sides
of the BINOP_EQUAL through this new evaluator, and one side can
be fully evaluated, and the other can be evaluated to a lazy
lval_memory value, we should be in business.

This new evaluator might possibly take the form of a new "enum noside"
value as argument to evaluate_subexp, or might be a completely separate
routine (like e.g. gen_eval_for_expr).  [ Or maybe even the regular
evaluator after temporarily resetting current_target to a target that
throws an exception on every memory / register access?  That may be
a bit ugly though ... ]

(If this is too much effort for now, I'd at least ask to put the
special-purpose helpers into a ppc-private file so as not to advertise
their reuse elsewhere ...)


Also, why do we need to evaluate the expression (as opposed to the
condition) again here?  We know we're going to set the hardware
watchpoint at ADDRESS.  As long as the memory access implied in COND
happens at that address, it does not matter at all how the expression
was formulated, right?

In fact, I'm not sure why we're passing the expression into the
insert/remove watchpoint routine in the first place, as we already
get the address/length.

> +	  byte_to_enable = addr % 4;
> +	  cond_addr >>= (byte_to_enable * 8);
> +	  p.condition_mode  = (PPC_BREAKPOINT_CONDITION_AND
> +			       | PPC_BREAKPOINT_CONDITION_BE (byte_to_enable));
> +	  p.condition_value = (uint64_t) cond_addr;

I'm not really familiar with the details of the hardware here, but
is the byte-enable stuff really correct?  You always set just one
single bit in the mask; shouldn't we have one bit for every byte
that is to be enabled?

Also, don't we at some point need to consider the length; e.g. if
we have a byte-sized variable that happens to start at an address
that is a multiple of 4?

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 2/4] Hardware accelerated watchpoint conditions
  2010-02-11 18:24           ` Ulrich Weigand
@ 2010-06-09  4:02             ` Thiago Jung Bauermann
  2010-06-09 13:28               ` Ulrich Weigand
  0 siblings, 1 reply; 17+ messages in thread
From: Thiago Jung Bauermann @ 2010-06-09  4:02 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: Joel Brobecker, gdb-patches, Luis Machado, Matt Tyrlik

[-- Attachment #1: Type: text/plain, Size: 5958 bytes --]

Hi,

On Thu, 2010-02-11 at 19:23 +0100, Ulrich Weigand wrote:
> Thiago Jung Bauermann wrote:
> 
> > @@ -1666,15 +1697,33 @@ ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw)
> >  
> >    if (have_ptrace_new_debug_booke)
> >      {
> > +      int byte_to_enable;
> >        struct ppc_hw_breakpoint p;
> > +      CORE_ADDR cond_addr;
> 
> The naming confused me as cond_addr turns out to hold the *data* value
> to be compared against, not any address ;-)

Indeed. Changed name to data_value.

> > +
> > +      if (cond && ppc_linux_can_use_watchpoint_cond_accel ()
> > +	  && (watch_address_if_address_equal_literal (exp, cond, &cond_addr)
> > +	      || watch_var_if_var_equal_literal (exp, cond, &cond_addr)
> > +	      || watch_var_if_address_equal_literal (exp, cond, &cond_addr)
> > +	      || watch_address_if_var_equal_literal (exp, cond, &cond_addr)))
> 
> This logic, together with the variety of special-purpose subroutines,
> strikes me as overly restrictive on the syntactical format of the
> condition expression, for example:
> - why shouldn't "if VAR.MEMBER == LITERAL" be allowed?
> - why shouldn't "if VAR == <constant expression>" be allowed?
> 
> What we really need here is a variant of expression evaluation that
> is "extremely lazy" and stops as soon as any reference to target
> memory or register contents would be made.  If we run both sides
> of the BINOP_EQUAL through this new evaluator, and one side can
> be fully evaluated, and the other can be evaluated to a lazy
> lval_memory value, we should be in business.
> 
> This new evaluator might possibly take the form of a new "enum noside"
> value as argument to evaluate_subexp, or might be a completely separate
> routine (like e.g. gen_eval_for_expr).  [ Or maybe even the regular
> evaluator after temporarily resetting current_target to a target that
> throws an exception on every memory / register access?  That may be
> a bit ugly though ... ]

I ended up doing the following to validate the watchpoint condition:

- verify whether the expression is an equality
- evaluate each side with evaluate_subexp (with EVAL_NORMAL, i.e., with 
  side-effects)
- one of the resulting values should be not_lval, and the other should 
  be lval_memory

I don't think fully evaluating the expression is a problem because GDB
already evaluates it each time the watchpoint triggers, so it should be
harmless to do the same here.

What do you think?

> Also, why do we need to evaluate the expression (as opposed to the
> condition) again here?  We know we're going to set the hardware
> watchpoint at ADDRESS.  As long as the memory access implied in COND
> happens at that address, it does not matter at all how the expression
> was formulated, right?
> 
> In fact, I'm not sure why we're passing the expression into the
> insert/remove watchpoint routine in the first place, as we already
> get the address/length.

Indeed. I changed the patch to pass only the condition expression.

> > +	  byte_to_enable = addr % 4;
> > +	  cond_addr >>= (byte_to_enable * 8);
> > +	  p.condition_mode  = (PPC_BREAKPOINT_CONDITION_AND
> > +			       | PPC_BREAKPOINT_CONDITION_BE (byte_to_enable));
> > +	  p.condition_value = (uint64_t) cond_addr;
> 
> I'm not really familiar with the details of the hardware here, but
> is the byte-enable stuff really correct?  You always set just one
> single bit in the mask; shouldn't we have one bit for every byte
> that is to be enabled?
> 
> Also, don't we at some point need to consider the length; e.g. if
> we have a byte-sized variable that happens to start at an address
> that is a multiple of 4?

The logic above is indeed very simplified, but works for the scenarios
we tested (watchpoints on various lengths of data types (char, short,
int, long...).

For completeness, I changed the code to calculate the DVC taking all
aspects in consideration. It became a bit complicated, so I put many
comments to explain what it is doing.

One important thing about this patch is that I had to add a new target
method: target_can_accel_watchpoint_condition. It is called in
watchpoint_locations_match to avoid making GDB insert only one of two
bp_locations which are at the same address but with different
conditions. When the target supports evaluating the watchpoint
expression in hardware, GDB needs to insert both hardware watchpoints
even if they are at the same address, so that their different conditions
have a chance to trigger.

Ok?


2010-06-08  Sergio Durigan Junior  <sergiodj@linux.vnet.ibm.com>
	    Thiago Jung Bauermann  <bauerman@br.ibm.com>

	* breakpoint.c (insert_bp_location): Pass watchpoint condition in
	target_insert_watchpoint.
	(remove_breakpoint_1) Pass watchpoint condition in
	target_remove_watchpoint.
	(watchpoint_locations_match): Call
	target_can_accel_watchpoint_condition.
	* ppc-linux-nat.c (ppc_linux_region_ok_for_hw_watchpoint): Formatting
	fix.
	(can_use_watchpoint_cond_accel): New function.
	(calculate_dvc): Likewise.
	(check_condition): Likewise.
	(ppc_linux_can_accel_watchpoint_condition): Likewise
	(ppc_linux_insert_watchpoint): Call can_use_watchpoint_cond_accel,
	check_condition and calculate_dvc.
	(ppc_linux_remove_watchpoint): Likewise.
	(_initialize_ppc_linux_nat): Set to_can_accel_watchpoint_condition to
	ppc_linux_can_accel_watchpoint_condition
	* target.c (debug_to_insert_watchpoint): Add argument for watchpoint
	condition.
	(debug_to_remove_watchpoint): Likewise.
	(debug_to_can_accel_watchpoint_condition): New function.
	(update_current_target): Set to_can_accel_watchpoint_condition.
	(setup_target_debug): Set to_can_accel_watchpoint_condition.
	* target.h: Add opaque declarations for struct expression.
	(struct target_ops) <to_insert_watchpoint>,
	<to_remove_watchpoint>: Add new arguments to pass the watchpoint
	<to_can_accel_watchpoint_condition>: New member.
	condition.  Update all callers and implementations.
	(target_can_accel_watchpoint_condition): New macro.



[-- Attachment #2: condition.diff --]
[-- Type: text/x-patch, Size: 28782 bytes --]

Index: gdb.git/gdb/breakpoint.c
===================================================================
--- gdb.git.orig/gdb/breakpoint.c	2010-06-05 00:27:58.000000000 -0300
+++ gdb.git/gdb/breakpoint.c	2010-06-06 12:14:22.000000000 -0300
@@ -1789,7 +1789,8 @@ Note: automatically using hardware break
     {
       val = target_insert_watchpoint (bpt->address,
 				      bpt->length,
-				      bpt->watchpoint_type);
+				      bpt->watchpoint_type,
+				      bpt->owner->cond_exp);
 
       /* If trying to set a read-watchpoint, and it turns out it's not
 	 supported, try emulating one with an access watchpoint.  */
@@ -1817,7 +1818,8 @@ Note: automatically using hardware break
 	    {
 	      val = target_insert_watchpoint (bpt->address,
 					      bpt->length,
-					      hw_access);
+					      hw_access,
+					      bpt->owner->cond_exp);
 	      if (val == 0)
 		bpt->watchpoint_type = hw_access;
 	    }
@@ -2477,8 +2479,8 @@ remove_breakpoint_1 (struct bp_location
   else if (b->loc_type == bp_loc_hardware_watchpoint)
     {
       b->inserted = (is == mark_inserted);
-      val = target_remove_watchpoint (b->address, b->length, 
-				      b->watchpoint_type);
+      val = target_remove_watchpoint (b->address, b->length,
+				      b->watchpoint_type, b->owner->cond_exp);
 
       /* Failure to remove any of the hardware watchpoints comes here.  */
       if ((is == mark_uninserted) && (b->inserted))
@@ -5211,6 +5213,21 @@ breakpoint_address_is_meaningful (struct
 static int
 watchpoint_locations_match (struct bp_location *loc1, struct bp_location *loc2)
 {
+  /* If the target can evaluate the condition expression in hardware, then we
+     we need to insert both watchpoints even if they are at the same place.
+     Otherwise the watchpoint will only trigger when the condition of whichever
+     watchpoint was inserted evaluates to true, not giving a chance for GDB to
+     check the condition of the other watchpoint.  */
+  if ((loc1->owner->cond_exp
+       && target_can_accel_watchpoint_condition (loc1->address, loc1->length,
+						 loc1->watchpoint_type,
+						 loc1->owner->cond_exp))
+      || (loc2->owner->cond_exp
+	  && target_can_accel_watchpoint_condition (loc2->address, loc2->length,
+						    loc2->watchpoint_type,
+						    loc2->owner->cond_exp)))
+    return 0;
+
   /* Note that this checks the owner's type, not the location's.  In
      case the target does not support read watchpoints, but does
      support access watchpoints, we'll have bp_read_watchpoint
Index: gdb.git/gdb/i386-nat.c
===================================================================
--- gdb.git.orig/gdb/i386-nat.c	2010-06-05 00:27:58.000000000 -0300
+++ gdb.git/gdb/i386-nat.c	2010-06-06 12:14:22.000000000 -0300
@@ -484,7 +484,8 @@ Invalid value %d of operation in i386_ha
    of the type TYPE.  Return 0 on success, -1 on failure.  */
 
 static int
-i386_insert_watchpoint (CORE_ADDR addr, int len, int type)
+i386_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *cond)
 {
   int retval;
 
@@ -511,7 +512,8 @@ i386_insert_watchpoint (CORE_ADDR addr,
    address ADDR, whose length is LEN bytes, and for accesses of the
    type TYPE.  Return 0 on success, -1 on failure.  */
 static int
-i386_remove_watchpoint (CORE_ADDR addr, int len, int type)
+i386_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *cond)
 {
   int retval;
 
Index: gdb.git/gdb/ia64-linux-nat.c
===================================================================
--- gdb.git.orig/gdb/ia64-linux-nat.c	2010-06-05 00:27:58.000000000 -0300
+++ gdb.git/gdb/ia64-linux-nat.c	2010-06-06 12:14:22.000000000 -0300
@@ -530,7 +530,8 @@ is_power_of_2 (int val)
 }
 
 static int
-ia64_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw)
+ia64_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw,
+			      struct expression *cond)
 {
   struct lwp_info *lp;
   ptid_t ptid;
@@ -584,7 +585,8 @@ ia64_linux_insert_watchpoint (CORE_ADDR
 }
 
 static int
-ia64_linux_remove_watchpoint (CORE_ADDR addr, int len, int type)
+ia64_linux_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			      struct expression *cond)
 {
   int idx;
   long dbr_addr, dbr_mask;
Index: gdb.git/gdb/inf-ttrace.c
===================================================================
--- gdb.git.orig/gdb/inf-ttrace.c	2010-06-05 00:27:58.000000000 -0300
+++ gdb.git/gdb/inf-ttrace.c	2010-06-06 12:14:22.000000000 -0300
@@ -314,7 +314,8 @@ inf_ttrace_disable_page_protections (pid
    type TYPE.  */
 
 static int
-inf_ttrace_insert_watchpoint (CORE_ADDR addr, int len, int type)
+inf_ttrace_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			      struct expression *cond)
 {
   const int pagesize = inf_ttrace_page_dict.pagesize;
   pid_t pid = ptid_get_pid (inferior_ptid);
@@ -337,7 +338,8 @@ inf_ttrace_insert_watchpoint (CORE_ADDR
    type TYPE.  */
 
 static int
-inf_ttrace_remove_watchpoint (CORE_ADDR addr, int len, int type)
+inf_ttrace_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			      struct expression *cond)
 {
   const int pagesize = inf_ttrace_page_dict.pagesize;
   pid_t pid = ptid_get_pid (inferior_ptid);
Index: gdb.git/gdb/mips-linux-nat.c
===================================================================
--- gdb.git.orig/gdb/mips-linux-nat.c	2010-06-05 00:27:58.000000000 -0300
+++ gdb.git/gdb/mips-linux-nat.c	2010-06-06 12:14:22.000000000 -0300
@@ -926,7 +926,8 @@ populate_regs_from_watches (struct pt_wa
    watch.  Return zero on success.  */
 
 static int
-mips_linux_insert_watchpoint (CORE_ADDR addr, int len, int type)
+mips_linux_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			      struct expression *cond)
 {
   struct pt_watch_regs regs;
   struct mips_watchpoint *new_watch;
@@ -975,7 +976,8 @@ mips_linux_insert_watchpoint (CORE_ADDR
    Return zero on success.  */
 
 static int
-mips_linux_remove_watchpoint (CORE_ADDR addr, int len, int type)
+mips_linux_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			      struct expression *cond)
 {
   int retval;
   int deleted_one;
Index: gdb.git/gdb/nto-procfs.c
===================================================================
--- gdb.git.orig/gdb/nto-procfs.c	2010-06-05 00:27:58.000000000 -0300
+++ gdb.git/gdb/nto-procfs.c	2010-06-06 12:14:22.000000000 -0300
@@ -1506,13 +1506,15 @@ procfs_can_use_hw_breakpoint (int type,
 }
 
 static int
-procfs_remove_hw_watchpoint (CORE_ADDR addr, int len, int type)
+procfs_remove_hw_watchpoint (CORE_ADDR addr, int len, int type,
+			     struct expression *cond)
 {
   return procfs_hw_watchpoint (addr, -1, type);
 }
 
 static int
-procfs_insert_hw_watchpoint (CORE_ADDR addr, int len, int type)
+procfs_insert_hw_watchpoint (CORE_ADDR addr, int len, int type,
+			     struct expression *cond)
 {
   return procfs_hw_watchpoint (addr, len, type);
 }
Index: gdb.git/gdb/ppc-linux-nat.c
===================================================================
--- gdb.git.orig/gdb/ppc-linux-nat.c	2010-06-05 00:27:58.000000000 -0300
+++ gdb.git/gdb/ppc-linux-nat.c	2010-06-08 22:25:39.000000000 -0300
@@ -1492,7 +1492,7 @@ ppc_linux_region_ok_for_hw_watchpoint (C
       if (booke_debug_info.data_bp_alignment
 	  && (addr + len > (addr & ~(booke_debug_info.data_bp_alignment - 1))
 	      + booke_debug_info.data_bp_alignment))
-	  return 0;
+	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
@@ -1685,8 +1685,149 @@ get_trigger_type (int rw)
   return t;
 }
 
+/* Check whether we have at least one free DVC register.  */
 static int
-ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw)
+can_use_watchpoint_cond_accel (void)
+{
+  struct thread_points *p;
+  int tid = TIDGET (inferior_ptid);
+  int cnt = booke_debug_info.num_condition_regs, i;
+  CORE_ADDR tmp_value;
+
+  if (!have_ptrace_booke_interface () || cnt == 0)
+    return 0;
+
+  p = booke_find_thread_points_by_tid (tid, 0);
+
+  if (p)
+    {
+      for (i = 0; i < max_slots_number; i++)
+	if (p->hw_breaks[i].hw_break != NULL
+	    && (p->hw_breaks[i].hw_break->condition_mode
+		!= PPC_BREAKPOINT_CONDITION_NONE))
+	  cnt--;
+
+      /* There are no available slots now.  */
+      if (cnt <= 0)
+	return 0;
+    }
+
+  return 1;
+}
+
+/* Calculate the enable bits and the contents of the Data Value Compare
+   debug register present in BookE processors.
+
+   ADDR is the address to be watched, LEN is the length of watched data
+   and DATA_VALUE is the value which will trigger the watchpoint.  On exit,
+   CONDITION_MODE will hold the enable bits for the DVC, and CONDITION_VALUE
+   will hold the value which should be put in the DVC register.  */
+static void
+calculate_dvc (CORE_ADDR addr, int len, CORE_ADDR data_value,
+	       int data_value_len, uint32_t *condition_mode,
+	       uint64_t *condition_value)
+{
+  int i, num_byte_enable, align_offset, num_bytes_off_dvc,
+      rightmost_enabled_byte;
+  CORE_ADDR addr_end_data, addr_end_dvc;
+
+  /* The DVC register compares bytes within fixed-length windows which
+     are word-aligned, with length equal to that of the DVC register.
+     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;
+  addr_end_data = addr + len;
+  addr_end_dvc = (addr - align_offset
+		  + booke_debug_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;
+  /* Here, bytes are numbered from right to left.  */
+  rightmost_enabled_byte = (addr_end_data < addr_end_dvc)?
+			      addr_end_dvc - addr_end_data : 0;
+
+  *condition_mode = PPC_BREAKPOINT_CONDITION_AND;
+  for (i = 0; i < num_byte_enable; i++)
+    *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
+     (i.e., the ALIGN_OFFSET).  */
+
+  /* The size of the user-provided data value matters because the value is
+     "left-aligned" within DATA_VALUE, e.g: a 1-byte data type will occupy the
+     first byte of DATA_VALUE, a two-byte data type the first two, and so on.
+     This means that we need to adjust the user-provided value within
+     DATA_VALUE when copying it to CONDITION_VALUE.  */
+
+  if (data_value_len - len > align_offset)
+    /* The user-provided value type is larger than the watched value type,
+       and it is also to the right of the offset within the DVC register
+       where it should be.  */
+    *condition_value = (uint64_t) data_value << (data_value_len - len
+						 - align_offset) * 8;
+  else
+    /* The user-provided value type is either smaller than the watched
+       value type, or else it is equal or larger than the watched value
+       type but to the left of the offset within the DVC register where
+       it should be.  */
+    *condition_value = (uint64_t) data_value >> (align_offset
+						 - (data_value_len - len)) * 8;
+}
+
+/* Verifies whether the expression COND can be implemented using the
+   DVC (Data Value Compare) register in BookE processors.  The expression
+   must test the watch value for equality with a constant expression.  */
+static int
+check_condition (CORE_ADDR watch_addr, struct expression *cond,
+		 CORE_ADDR *data_value, int *data_value_len)
+{
+  int pc = 1, copy_len;
+  struct value *v_left, *v_right, *val;
+
+  if (cond->elts[0].opcode != BINOP_EQUAL)
+    return 0;
+
+  v_left = evaluate_subexp (NULL_TYPE, cond, &pc, EVAL_NORMAL);
+  v_right = evaluate_subexp (NULL_TYPE, cond, &pc, EVAL_NORMAL);
+
+  if (VALUE_LVAL (v_left) == lval_memory && VALUE_LVAL (v_right) == not_lval
+      && value_address (v_left) == watch_addr)
+    val = v_right;
+  else if (VALUE_LVAL (v_left) == not_lval && VALUE_LVAL (v_right) == lval_memory
+	   && value_address (v_right) == watch_addr)
+    val = v_left;
+  else
+    return 0;
+
+  *data_value = 0;
+  *data_value_len = TYPE_LENGTH (value_type (val));
+  copy_len = *data_value_len > sizeof (CORE_ADDR)?
+               sizeof (CORE_ADDR) : *data_value_len;
+  memcpy (data_value, value_contents (val), copy_len);
+
+  return 1;
+}
+
+/* Return non-zero if the target is capable of using hardware to evaluate
+   the condition expression, thus only triggering the watchpoint when it is
+   true.  */
+static int
+ppc_linux_can_accel_watchpoint_condition (CORE_ADDR addr, int len, int rw,
+					  struct expression *cond)
+{
+  int data_value_len;
+  CORE_ADDR data_value;
+
+  return (have_ptrace_booke_interface ()
+	  && booke_debug_info.num_condition_regs > 0
+	  && check_condition (addr, cond, &data_value, &data_value_len));
+}
+
+static int
+ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw,
+			     struct expression *cond)
 {
   struct lwp_info *lp;
   ptid_t ptid;
@@ -1694,15 +1835,25 @@ ppc_linux_insert_watchpoint (CORE_ADDR a
 
   if (have_ptrace_booke_interface ())
     {
+      int data_value_len;
       struct ppc_hw_breakpoint p;
+      CORE_ADDR data_value;
+
+      if (cond && can_use_watchpoint_cond_accel ()
+	  && check_condition (addr, cond, &data_value, &data_value_len))
+	calculate_dvc (addr, len, data_value, data_value_len,
+		       &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.condition_mode  = PPC_BREAKPOINT_CONDITION_NONE;
       p.addr            = (uint64_t) addr;
       p.addr2           = 0;
-      p.condition_value = 0;
 
       ALL_LWPS (lp, ptid)
 	booke_insert_point (&p, TIDGET (ptid));
@@ -1749,7 +1900,8 @@ ppc_linux_insert_watchpoint (CORE_ADDR a
       saved_dabr_value = dabr_value;
 
       ALL_LWPS (lp, ptid)
-	if (ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0, saved_dabr_value) < 0)
+	if (ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0,
+		    saved_dabr_value) < 0)
 	  return -1;
 
       ret = 0;
@@ -1759,7 +1911,8 @@ ppc_linux_insert_watchpoint (CORE_ADDR a
 }
 
 static int
-ppc_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw)
+ppc_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw,
+			     struct expression *cond)
 {
   struct lwp_info *lp;
   ptid_t ptid;
@@ -1767,15 +1920,25 @@ ppc_linux_remove_watchpoint (CORE_ADDR a
 
   if (have_ptrace_booke_interface ())
     {
+      int data_value_len;
       struct ppc_hw_breakpoint p;
+      CORE_ADDR data_value;
+
+      if (cond && booke_debug_info.num_condition_regs > 0
+	  && check_condition (addr, cond, &data_value, &data_value_len))
+	calculate_dvc (addr, len, data_value, data_value_len,
+		       &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.condition_mode  = PPC_BREAKPOINT_CONDITION_NONE;
       p.addr            = (uint64_t) addr;
       p.addr2           = 0;
-      p.condition_value = 0;
 
       ALL_LWPS (lp, ptid)
 	booke_remove_point (&p, TIDGET (ptid));
@@ -1786,7 +1949,8 @@ ppc_linux_remove_watchpoint (CORE_ADDR a
     {
       saved_dabr_value = 0;
       ALL_LWPS (lp, ptid)
-	if (ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0, saved_dabr_value) < 0)
+	if (ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0,
+		    saved_dabr_value) < 0)
 	  return -1;
 
       ret = 0;
@@ -2137,6 +2301,7 @@ _initialize_ppc_linux_nat (void)
   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_read_description = ppc_linux_read_description;
   t->to_auxv_parse = ppc_linux_auxv_parse;
Index: gdb.git/gdb/procfs.c
===================================================================
--- gdb.git.orig/gdb/procfs.c	2010-06-05 00:27:58.000000000 -0300
+++ gdb.git/gdb/procfs.c	2010-06-06 12:14:22.000000000 -0300
@@ -5161,7 +5161,8 @@ procfs_stopped_data_address (struct targ
 }
 
 static int
-procfs_insert_watchpoint (CORE_ADDR addr, int len, int type)
+procfs_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			  struct expression *cond)
 {
   if (!target_have_steppable_watchpoint
       && !gdbarch_have_nonsteppable_watchpoint (target_gdbarch))
@@ -5182,7 +5183,8 @@ procfs_insert_watchpoint (CORE_ADDR addr
 }
 
 static int
-procfs_remove_watchpoint (CORE_ADDR addr, int len, int type)
+procfs_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			  struct expression *cond)
 {
   return procfs_set_watchpoint (inferior_ptid, addr, 0, 0, 0);
 }
Index: gdb.git/gdb/remote-m32r-sdi.c
===================================================================
--- gdb.git.orig/gdb/remote-m32r-sdi.c	2010-06-05 00:27:58.000000000 -0300
+++ gdb.git/gdb/remote-m32r-sdi.c	2010-06-06 12:14:22.000000000 -0300
@@ -1421,7 +1421,8 @@ m32r_can_use_hw_watchpoint (int type, in
    watchpoint. */
 
 static int
-m32r_insert_watchpoint (CORE_ADDR addr, int len, int type)
+m32r_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *cond)
 {
   int i;
 
@@ -1445,7 +1446,8 @@ m32r_insert_watchpoint (CORE_ADDR addr,
 }
 
 static int
-m32r_remove_watchpoint (CORE_ADDR addr, int len, int type)
+m32r_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *cond)
 {
   int i;
 
Index: gdb.git/gdb/remote-mips.c
===================================================================
--- gdb.git.orig/gdb/remote-mips.c	2010-06-05 00:27:58.000000000 -0300
+++ gdb.git/gdb/remote-mips.c	2010-06-06 12:14:22.000000000 -0300
@@ -2401,7 +2401,8 @@ calculate_mask (CORE_ADDR addr, int len)
    watchpoint. */
 
 int
-mips_insert_watchpoint (CORE_ADDR addr, int len, int type)
+mips_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *cond)
 {
   if (mips_set_breakpoint (addr, len, type))
     return -1;
@@ -2412,7 +2413,8 @@ mips_insert_watchpoint (CORE_ADDR addr,
 /* Remove a watchpoint.  */
 
 int
-mips_remove_watchpoint (CORE_ADDR addr, int len, int type)
+mips_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *cond)
 {
   if (mips_clear_breakpoint (addr, len, type))
     return -1;
Index: gdb.git/gdb/remote.c
===================================================================
--- gdb.git.orig/gdb/remote.c	2010-06-05 00:27:58.000000000 -0300
+++ gdb.git/gdb/remote.c	2010-06-06 12:14:22.000000000 -0300
@@ -7497,7 +7497,8 @@ watchpoint_to_Z_packet (int type)
 }
 
 static int
-remote_insert_watchpoint (CORE_ADDR addr, int len, int type)
+remote_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			  struct expression *cond)
 {
   struct remote_state *rs = get_remote_state ();
   char *p;
@@ -7530,7 +7531,8 @@ remote_insert_watchpoint (CORE_ADDR addr
 
 
 static int
-remote_remove_watchpoint (CORE_ADDR addr, int len, int type)
+remote_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			  struct expression *cond)
 {
   struct remote_state *rs = get_remote_state ();
   char *p;
Index: gdb.git/gdb/s390-nat.c
===================================================================
--- gdb.git.orig/gdb/s390-nat.c	2010-06-05 00:27:58.000000000 -0300
+++ gdb.git/gdb/s390-nat.c	2010-06-06 12:14:22.000000000 -0300
@@ -335,7 +335,8 @@ s390_fix_watch_points (ptid_t ptid)
 }
 
 static int
-s390_insert_watchpoint (CORE_ADDR addr, int len, int type)
+s390_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *cond)
 {
   struct lwp_info *lp;
   ptid_t ptid;
@@ -356,7 +357,8 @@ s390_insert_watchpoint (CORE_ADDR addr,
 }
 
 static int
-s390_remove_watchpoint (CORE_ADDR addr, int len, int type)
+s390_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *cond)
 {
   struct lwp_info *lp;
   ptid_t ptid;
Index: gdb.git/gdb/target.c
===================================================================
--- gdb.git.orig/gdb/target.c	2010-06-05 00:27:58.000000000 -0300
+++ gdb.git/gdb/target.c	2010-06-06 12:14:22.000000000 -0300
@@ -117,9 +117,11 @@ static int debug_to_insert_hw_breakpoint
 static int debug_to_remove_hw_breakpoint (struct gdbarch *,
 					  struct bp_target_info *);
 
-static int debug_to_insert_watchpoint (CORE_ADDR, int, int);
+static int debug_to_insert_watchpoint (CORE_ADDR, int, int,
+				       struct expression *);
 
-static int debug_to_remove_watchpoint (CORE_ADDR, int, int);
+static int debug_to_remove_watchpoint (CORE_ADDR, int, int,
+				       struct expression *);
 
 static int debug_to_stopped_by_watchpoint (void);
 
@@ -130,6 +132,9 @@ static int debug_to_watchpoint_addr_with
 
 static int debug_to_region_ok_for_hw_watchpoint (CORE_ADDR, int);
 
+static int debug_to_can_accel_watchpoint_condition (CORE_ADDR, int, int,
+						    struct expression *);
+
 static void debug_to_terminal_init (void);
 
 static void debug_to_terminal_inferior (void);
@@ -591,6 +596,7 @@ update_current_target (void)
       INHERIT (to_stopped_by_watchpoint, t);
       INHERIT (to_watchpoint_addr_within_range, t);
       INHERIT (to_region_ok_for_hw_watchpoint, t);
+      INHERIT (to_can_accel_watchpoint_condition, t);
       INHERIT (to_terminal_init, t);
       INHERIT (to_terminal_inferior, t);
       INHERIT (to_terminal_ours_for_output, t);
@@ -709,10 +715,10 @@ update_current_target (void)
 	    (int (*) (struct gdbarch *, struct bp_target_info *))
 	    return_minus_one);
   de_fault (to_insert_watchpoint,
-	    (int (*) (CORE_ADDR, int, int))
+	    (int (*) (CORE_ADDR, int, int, struct expression *))
 	    return_minus_one);
   de_fault (to_remove_watchpoint,
-	    (int (*) (CORE_ADDR, int, int))
+	    (int (*) (CORE_ADDR, int, int, struct expression *))
 	    return_minus_one);
   de_fault (to_stopped_by_watchpoint,
 	    (int (*) (void))
@@ -724,6 +730,9 @@ 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_can_accel_watchpoint_condition,
+            (int (*) (CORE_ADDR, int, int, struct expression *))
+            return_zero);
   de_fault (to_terminal_init,
 	    (void (*) (void))
 	    target_ignore);
@@ -3237,6 +3246,21 @@ debug_to_region_ok_for_hw_watchpoint (CO
 }
 
 static int
+debug_to_can_accel_watchpoint_condition (CORE_ADDR addr, int len, int rw,
+					 struct expression *cond)
+{
+  int retval;
+
+  retval = debug_target.to_can_accel_watchpoint_condition (addr, len, rw, cond);
+
+  fprintf_unfiltered (gdb_stdlog,
+		      "target_can_accel_watchpoint_condition (0x%lx, %d, %d, 0x%lx) = %ld\n",
+		      (unsigned long) addr, len, rw, (unsigned long) cond,
+		      (unsigned long) retval);
+  return retval;
+}
+
+static int
 debug_to_stopped_by_watchpoint (void)
 {
   int retval;
@@ -3311,28 +3335,32 @@ debug_to_remove_hw_breakpoint (struct gd
 }
 
 static int
-debug_to_insert_watchpoint (CORE_ADDR addr, int len, int type)
+debug_to_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			    struct expression *cond)
 {
   int retval;
 
-  retval = debug_target.to_insert_watchpoint (addr, len, type);
+  retval = debug_target.to_insert_watchpoint (addr, len, type, cond);
 
   fprintf_unfiltered (gdb_stdlog,
-		      "target_insert_watchpoint (0x%lx, %d, %d) = %ld\n",
-		      (unsigned long) addr, len, type, (unsigned long) retval);
+		      "target_insert_watchpoint (0x%lx, %d, %d, 0x%ld) = %ld\n",
+		      (unsigned long) addr, len, type, (unsigned long) cond,
+		      (unsigned long) retval);
   return retval;
 }
 
 static int
-debug_to_remove_watchpoint (CORE_ADDR addr, int len, int type)
+debug_to_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			    struct expression *cond)
 {
   int retval;
 
-  retval = debug_target.to_remove_watchpoint (addr, len, type);
+  retval = debug_target.to_remove_watchpoint (addr, len, type, cond);
 
   fprintf_unfiltered (gdb_stdlog,
-		      "target_remove_watchpoint (0x%lx, %d, %d) = %ld\n",
-		      (unsigned long) addr, len, type, (unsigned long) retval);
+		      "target_remove_watchpoint (0x%lx, %d, %d, 0x%ld) = %ld\n",
+		      (unsigned long) addr, len, type, (unsigned long) cond,
+		      (unsigned long) retval);
   return retval;
 }
 
@@ -3587,6 +3615,7 @@ setup_target_debug (void)
   current_target.to_stopped_data_address = debug_to_stopped_data_address;
   current_target.to_watchpoint_addr_within_range = debug_to_watchpoint_addr_within_range;
   current_target.to_region_ok_for_hw_watchpoint = debug_to_region_ok_for_hw_watchpoint;
+  current_target.to_can_accel_watchpoint_condition = debug_to_can_accel_watchpoint_condition;
   current_target.to_terminal_init = debug_to_terminal_init;
   current_target.to_terminal_inferior = debug_to_terminal_inferior;
   current_target.to_terminal_ours_for_output = debug_to_terminal_ours_for_output;
Index: gdb.git/gdb/target.h
===================================================================
--- gdb.git.orig/gdb/target.h	2010-06-05 00:27:58.000000000 -0300
+++ gdb.git/gdb/target.h	2010-06-06 12:14:22.000000000 -0300
@@ -36,6 +36,8 @@ struct trace_status;
 struct uploaded_tsv;
 struct uploaded_tp;
 
+struct expression;
+
 /* 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
@@ -420,8 +422,12 @@ struct target_ops
     int (*to_can_use_hw_breakpoint) (int, int, int);
     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);
+
+    /* Documentation of what the two routines belwo are expected to do is
+       provided with the corresponding target_* macros.  */
+    int (*to_remove_watchpoint) (CORE_ADDR, int, int, struct expression *);
+    int (*to_insert_watchpoint) (CORE_ADDR, int, int, struct expression *);
+
     int (*to_stopped_by_watchpoint) (void);
     int to_have_steppable_watchpoint;
     int to_have_continuable_watchpoint;
@@ -429,6 +435,8 @@ struct target_ops
     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_can_accel_watchpoint_condition) (CORE_ADDR, int, int,
+					      struct expression *);
     void (*to_terminal_init) (void);
     void (*to_terminal_inferior) (void);
     void (*to_terminal_ours_for_output) (void);
@@ -1279,14 +1287,15 @@ extern char *normal_pid_to_str (ptid_t p
 
 /* 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.
+   COND is the expression for its condition, or NULL if there's none.
    Returns 0 for success, 1 if the watchpoint type is not supported,
    -1 for failure.  */
 
-#define	target_insert_watchpoint(addr, len, type)	\
-     (*current_target.to_insert_watchpoint) (addr, len, type)
+#define	target_insert_watchpoint(addr, len, type, cond) \
+     (*current_target.to_insert_watchpoint) (addr, len, type, cond)
 
-#define	target_remove_watchpoint(addr, len, type)	\
-     (*current_target.to_remove_watchpoint) (addr, len, type)
+#define	target_remove_watchpoint(addr, len, type, cond) \
+     (*current_target.to_remove_watchpoint) (addr, len, type, cond)
 
 #define target_insert_hw_breakpoint(gdbarch, bp_tgt) \
      (*current_target.to_insert_hw_breakpoint) (gdbarch, bp_tgt)
@@ -1303,6 +1312,12 @@ extern char *normal_pid_to_str (ptid_t p
 #define target_watchpoint_addr_within_range(target, addr, start, length) \
   (*target.to_watchpoint_addr_within_range) (target, addr, start, length)
 
+/* Return non-zero if the target is capable of using hardware to evaluate
+   the condition expression, thus only triggering the watchpoint when it is
+   true.  */
+#define target_can_accel_watchpoint_condition(addr, len, type, cond) \
+  (*current_target.to_can_accel_watchpoint_condition) (addr, len, type, cond)
+
 /* Target can execute in reverse?  */
 #define target_can_execute_reverse \
      (current_target.to_can_execute_reverse ? \

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 2/4] Hardware accelerated watchpoint conditions
  2010-06-09  4:02             ` Thiago Jung Bauermann
@ 2010-06-09 13:28               ` Ulrich Weigand
  2010-06-23 17:21                 ` Thiago Jung Bauermann
  0 siblings, 1 reply; 17+ messages in thread
From: Ulrich Weigand @ 2010-06-09 13:28 UTC (permalink / raw)
  To: Thiago Jung Bauermann
  Cc: Joel Brobecker, gdb-patches, Luis Machado, Matt Tyrlik

Thiago Jung Bauermann wrote:
> On Thu, 2010-02-11 at 19:23 +0100, Ulrich Weigand wrote:
> > This logic, together with the variety of special-purpose subroutines,
> > strikes me as overly restrictive on the syntactical format of the
> > condition expression, for example:
> > - why shouldn't "if VAR.MEMBER == LITERAL" be allowed?
> > - why shouldn't "if VAR == <constant expression>" be allowed?
> > 
> > What we really need here is a variant of expression evaluation that
> > is "extremely lazy" and stops as soon as any reference to target
> > memory or register contents would be made.  If we run both sides
> > of the BINOP_EQUAL through this new evaluator, and one side can
> > be fully evaluated, and the other can be evaluated to a lazy
> > lval_memory value, we should be in business.
> > 
> > This new evaluator might possibly take the form of a new "enum noside"
> > value as argument to evaluate_subexp, or might be a completely separate
> > routine (like e.g. gen_eval_for_expr).  [ Or maybe even the regular
> > evaluator after temporarily resetting current_target to a target that
> > throws an exception on every memory / register access?  That may be
> > a bit ugly though ... ]
> 
> I ended up doing the following to validate the watchpoint condition:
> 
> - verify whether the expression is an equality
> - evaluate each side with evaluate_subexp (with EVAL_NORMAL, i.e., with 
>   side-effects)
> - one of the resulting values should be not_lval, and the other should 
>   be lval_memory
> 
> I don't think fully evaluating the expression is a problem because GDB
> already evaluates it each time the watchpoint triggers, so it should be
> harmless to do the same here.
> 
> What do you think?

Unfortunately, I think this doesn't quite work: the problem is not that
accesses have been evaluated (that should be fine as you said), but rather
the problem is that you do not guarantee that the comparison value is
*constant*.  Now you do have the check against not_lval, which will
indeed exclude simple non-constant values like direct register or
memory references.  However, if the right side is a *complex* but
non-constant expression, you'll also see non_lval and accept it.

For example, I think your code would currently (erroneously) claim to
be able to use hardware assists to watch something like:

  watch x if x == y + z

with global variables x, y, z.

The prior attempt got this correct (but sub-optimal) by disallowing
any complex expression.  What we really want is to allow any *constant*
expresssion, i.e. any expression whose value does not depend on the
contents of registers or memory.

> For completeness, I changed the code to calculate the DVC taking all
> aspects in consideration. It became a bit complicated, so I put many
> comments to explain what it is doing.

OK, thanks for the explanation.

> One important thing about this patch is that I had to add a new target
> method: target_can_accel_watchpoint_condition. It is called in
> watchpoint_locations_match to avoid making GDB insert only one of two
> bp_locations which are at the same address but with different
> conditions. When the target supports evaluating the watchpoint
> expression in hardware, GDB needs to insert both hardware watchpoints
> even if they are at the same address, so that their different conditions
> have a chance to trigger.

Hmm, I'm wondering -- it seems a bit odd that there is no feedback
from target_insert_watchpoint itself whether the condition could be
honored or not -- it's just silently ignored, and you have to consider
this extra target hook.  Maybe a more straightforward interface would
be to have target_insert_watchpoint fail if called with a condition
it cannot implement -- common code could then retry with a NULL
condition, and reset the breakpoint type to remember that for this
watchpoint, software condition checks need to be applied ...

(But this is really a separate issue from the main purpose of this
patch; please do not consider this as a matter that would block
acceptance of the patch as is, as far as I'm concerned.)

> +/* Calculate the enable bits and the contents of the Data Value Compare
> +   debug register present in BookE processors.
> +
> +   ADDR is the address to be watched, LEN is the length of watched data
> +   and DATA_VALUE is the value which will trigger the watchpoint.  On exit,
> +   CONDITION_MODE will hold the enable bits for the DVC, and CONDITION_VALUE
> +   will hold the value which should be put in the DVC register.  */

DATA_LEN is not described.  I'm wondering why two lengths are needed here?

> +static void
> +calculate_dvc (CORE_ADDR addr, int len, CORE_ADDR data_value,
> +	       int data_value_len, uint32_t *condition_mode,
> +	       uint64_t *condition_value)

> +/* Verifies whether the expression COND can be implemented using the
> +   DVC (Data Value Compare) register in BookE processors.  The expression
> +   must test the watch value for equality with a constant expression.  */
> +static int
> +check_condition (CORE_ADDR watch_addr, struct expression *cond,
> +		 CORE_ADDR *data_value, int *data_value_len)
> +{
> +  int pc = 1, copy_len;
> +  struct value *v_left, *v_right, *val;
> +
> +  if (cond->elts[0].opcode != BINOP_EQUAL)
> +    return 0;
> +
> +  v_left = evaluate_subexp (NULL_TYPE, cond, &pc, EVAL_NORMAL);
> +  v_right = evaluate_subexp (NULL_TYPE, cond, &pc, EVAL_NORMAL);
> +
> +  if (VALUE_LVAL (v_left) == lval_memory && VALUE_LVAL (v_right) == not_lval
> +      && value_address (v_left) == watch_addr)
> +    val = v_right;
> +  else if (VALUE_LVAL (v_left) == not_lval && VALUE_LVAL (v_right) == lval_memory
> +	   && value_address (v_right) == watch_addr)
> +    val = v_left;
> +  else
> +    return 0;

See the discussion above; this does not ensure that VAL represents a
*constant* expression.

> +  *data_value = 0;
> +  *data_value_len = TYPE_LENGTH (value_type (val));
> +  copy_len = *data_value_len > sizeof (CORE_ADDR)?
> +               sizeof (CORE_ADDR) : *data_value_len;
> +  memcpy (data_value, value_contents (val), copy_len);

There seem to be byte order assumptions here.  In theory, in a multi-arch
setup, the byte order of VAL might differ from the native byte order of
a CORE_ADDR ...   Can this not be done via value_as_long, possibly 
followed by shifts?


Thanks,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 2/4] Hardware accelerated watchpoint conditions
  2010-06-09 13:28               ` Ulrich Weigand
@ 2010-06-23 17:21                 ` Thiago Jung Bauermann
  2010-06-23 19:57                   ` Ulrich Weigand
  0 siblings, 1 reply; 17+ messages in thread
From: Thiago Jung Bauermann @ 2010-06-23 17:21 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: Joel Brobecker, gdb-patches, Luis Machado, Matt Tyrlik

[-- Attachment #1: Type: text/plain, Size: 6106 bytes --]

On Wed, 2010-06-09 at 15:27 +0200, Ulrich Weigand wrote:
> Thiago Jung Bauermann wrote:
> Unfortunately, I think this doesn't quite work: the problem is not that
> accesses have been evaluated (that should be fine as you said), but rather
> the problem is that you do not guarantee that the comparison value is
> *constant*.  Now you do have the check against not_lval, which will
> indeed exclude simple non-constant values like direct register or
> memory references.  However, if the right side is a *complex* but
> non-constant expression, you'll also see non_lval and accept it.
> 
> For example, I think your code would currently (erroneously) claim to
> be able to use hardware assists to watch something like:
> 
>   watch x if x == y + z
> 
> with global variables x, y, z.
> 
> The prior attempt got this correct (but sub-optimal) by disallowing
> any complex expression.  What we really want is to allow any *constant*
> expresssion, i.e. any expression whose value does not depend on the
> contents of registers or memory.

Indeed. I didn't realised that. I changed the patch to use the approach
found in can_use_hardware_watchpoint: evaluate the expression and then
go through the value chain generated by the evaluation to check whether
there's any memory or register access. What do you think?

If this doesn't work then I'll go back to the simple approach of the
first patch. :-)

> > One important thing about this patch is that I had to add a new target
> > method: target_can_accel_watchpoint_condition. It is called in
> > watchpoint_locations_match to avoid making GDB insert only one of two
> > bp_locations which are at the same address but with different
> > conditions. When the target supports evaluating the watchpoint
> > expression in hardware, GDB needs to insert both hardware watchpoints
> > even if they are at the same address, so that their different conditions
> > have a chance to trigger.
> 
> Hmm, I'm wondering -- it seems a bit odd that there is no feedback
> from target_insert_watchpoint itself whether the condition could be
> honored or not -- it's just silently ignored, and you have to consider
> this extra target hook.  Maybe a more straightforward interface would
> be to have target_insert_watchpoint fail if called with a condition
> it cannot implement -- common code could then retry with a NULL
> condition, and reset the breakpoint type to remember that for this
> watchpoint, software condition checks need to be applied ...

We need to determine whether the condition can be implemented in
hardware before target_insert_watchpoint is called because
update_global_location_list will flag duplicate watchpoint locations and
those won't be inserted at all...

> (But this is really a separate issue from the main purpose of this
> patch; please do not consider this as a matter that would block
> acceptance of the patch as is, as far as I'm concerned.)

Thanks! I'm in favor of avoiding adding unnecessary flags and hooks, but
in this case I think it's necessary.

> > +/* Calculate the enable bits and the contents of the Data Value Compare
> > +   debug register present in BookE processors.
> > +
> > +   ADDR is the address to be watched, LEN is the length of watched data
> > +   and DATA_VALUE is the value which will trigger the watchpoint.  On exit,
> > +   CONDITION_MODE will hold the enable bits for the DVC, and CONDITION_VALUE
> > +   will hold the value which should be put in the DVC register.  */
> 
> DATA_LEN is not described.  I'm wondering why two lengths are needed here?

I described it now. We need two lengths because the watched value and
the constant in the condition may have different types. For instance, if
you have a "short int foo" and your condition is "foo == 2", then the
watched variable is of type short int and the condition constant is an
int.

> > +  *data_value = 0;
> > +  *data_value_len = TYPE_LENGTH (value_type (val));
> > +  copy_len = *data_value_len > sizeof (CORE_ADDR)?
> > +               sizeof (CORE_ADDR) : *data_value_len;
> > +  memcpy (data_value, value_contents (val), copy_len);
> 
> There seem to be byte order assumptions here.  In theory, in a multi-arch
> setup, the byte order of VAL might differ from the native byte order of
> a CORE_ADDR ...   Can this not be done via value_as_long, possibly 
> followed by shifts?

I didn't realise that. This version follows your suggestion.

Thanks and regards,
Thiago Jung Bauermann
IBM Linux Technology Center


2010-06-23  Sergio Durigan Junior  <sergiodj@linux.vnet.ibm.com>
	    Thiago Jung Bauermann  <bauerman@br.ibm.com>

	* breakpoint.c (insert_bp_location): Pass watchpoint condition in
	target_insert_watchpoint.
	(remove_breakpoint_1) Pass watchpoint condition in
	target_remove_watchpoint.
	(watchpoint_locations_match): Call
	target_can_accel_watchpoint_condition.
	* ppc-linux-nat.c: Include exceptions.h and wrapper.h
	(ppc_linux_region_ok_for_hw_watchpoint): Formatting fix.
	(can_use_watchpoint_cond_accel): New function.
	(calculate_dvc): Likewise.
	(num_memory_accesses): Likewise.
	(fetch_subexp_value): Likewise.
	(free_value_chain): Likewise.
	(check_condition): Likewise.
	(ppc_linux_can_accel_watchpoint_condition): Likewise
	(ppc_linux_insert_watchpoint): Call can_use_watchpoint_cond_accel,
	check_condition and calculate_dvc.
	(ppc_linux_remove_watchpoint): Likewise.
	(_initialize_ppc_linux_nat): Set to_can_accel_watchpoint_condition to
	ppc_linux_can_accel_watchpoint_condition
	* target.c (debug_to_insert_watchpoint): Add argument for watchpoint
	condition.
	(debug_to_remove_watchpoint): Likewise.
	(debug_to_can_accel_watchpoint_condition): New function.
	(update_current_target): Set to_can_accel_watchpoint_condition.
	(setup_target_debug): Set to_can_accel_watchpoint_condition.
	* target.h: Add opaque declarations for struct expression.
	(struct target_ops) <to_insert_watchpoint>,
	<to_remove_watchpoint>: Add new arguments to pass the watchpoint
	<to_can_accel_watchpoint_condition>: New member.
	condition.  Update all callers and implementations.
	(target_can_accel_watchpoint_condition): New macro.


[-- Attachment #2: condition.diff --]
[-- Type: text/x-patch, Size: 33195 bytes --]

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index f2b973a..9ee7ad9 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -1796,7 +1796,8 @@ Note: automatically using hardware breakpoints for read-only addresses.\n"));
     {
       val = target_insert_watchpoint (bpt->address,
 				      bpt->length,
-				      bpt->watchpoint_type);
+				      bpt->watchpoint_type,
+				      bpt->owner->cond_exp);
 
       /* If trying to set a read-watchpoint, and it turns out it's not
 	 supported, try emulating one with an access watchpoint.  */
@@ -1824,7 +1825,8 @@ Note: automatically using hardware breakpoints for read-only addresses.\n"));
 	    {
 	      val = target_insert_watchpoint (bpt->address,
 					      bpt->length,
-					      hw_access);
+					      hw_access,
+					      bpt->owner->cond_exp);
 	      if (val == 0)
 		bpt->watchpoint_type = hw_access;
 	    }
@@ -2493,8 +2495,8 @@ remove_breakpoint_1 (struct bp_location *b, insertion_state_t is)
   else if (b->loc_type == bp_loc_hardware_watchpoint)
     {
       b->inserted = (is == mark_inserted);
-      val = target_remove_watchpoint (b->address, b->length, 
-				      b->watchpoint_type);
+      val = target_remove_watchpoint (b->address, b->length,
+				      b->watchpoint_type, b->owner->cond_exp);
 
       /* Failure to remove any of the hardware watchpoints comes here.  */
       if ((is == mark_uninserted) && (b->inserted))
@@ -5262,6 +5264,21 @@ watchpoint_locations_match (struct bp_location *loc1, struct bp_location *loc2)
   gdb_assert (loc1->owner != NULL);
   gdb_assert (loc2->owner != NULL);
 
+  /* If the target can evaluate the condition expression in hardware, then we
+     we need to insert both watchpoints even if they are at the same place.
+     Otherwise the watchpoint will only trigger when the condition of whichever
+     watchpoint was inserted evaluates to true, not giving a chance for GDB to
+     check the condition of the other watchpoint.  */
+  if ((loc1->owner->cond_exp
+       && target_can_accel_watchpoint_condition (loc1->address, loc1->length,
+						 loc1->watchpoint_type,
+						 loc1->owner->cond_exp))
+      || (loc2->owner->cond_exp
+	  && target_can_accel_watchpoint_condition (loc2->address, loc2->length,
+						    loc2->watchpoint_type,
+						    loc2->owner->cond_exp)))
+    return 0;
+
   /* Note that this checks the owner's type, not the location's.  In
      case the target does not support read watchpoints, but does
      support access watchpoints, we'll have bp_read_watchpoint
diff --git a/gdb/i386-nat.c b/gdb/i386-nat.c
index 82c51d7..eaa3644 100644
--- a/gdb/i386-nat.c
+++ b/gdb/i386-nat.c
@@ -484,7 +484,8 @@ Invalid value %d of operation in i386_handle_nonaligned_watchpoint.\n"),
    of the type TYPE.  Return 0 on success, -1 on failure.  */
 
 static int
-i386_insert_watchpoint (CORE_ADDR addr, int len, int type)
+i386_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *cond)
 {
   int retval;
 
@@ -511,7 +512,8 @@ i386_insert_watchpoint (CORE_ADDR addr, int len, int type)
    address ADDR, whose length is LEN bytes, and for accesses of the
    type TYPE.  Return 0 on success, -1 on failure.  */
 static int
-i386_remove_watchpoint (CORE_ADDR addr, int len, int type)
+i386_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *cond)
 {
   int retval;
 
diff --git a/gdb/ia64-linux-nat.c b/gdb/ia64-linux-nat.c
index e6a7077..d33e88e 100644
--- a/gdb/ia64-linux-nat.c
+++ b/gdb/ia64-linux-nat.c
@@ -530,7 +530,8 @@ is_power_of_2 (int val)
 }
 
 static int
-ia64_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw)
+ia64_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw,
+			      struct expression *cond)
 {
   struct lwp_info *lp;
   ptid_t ptid;
@@ -584,7 +585,8 @@ ia64_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw)
 }
 
 static int
-ia64_linux_remove_watchpoint (CORE_ADDR addr, int len, int type)
+ia64_linux_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			      struct expression *cond)
 {
   int idx;
   long dbr_addr, dbr_mask;
diff --git a/gdb/inf-ttrace.c b/gdb/inf-ttrace.c
index 199ceb9..aa0462f 100644
--- a/gdb/inf-ttrace.c
+++ b/gdb/inf-ttrace.c
@@ -314,7 +314,8 @@ inf_ttrace_disable_page_protections (pid_t pid)
    type TYPE.  */
 
 static int
-inf_ttrace_insert_watchpoint (CORE_ADDR addr, int len, int type)
+inf_ttrace_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			      struct expression *cond)
 {
   const int pagesize = inf_ttrace_page_dict.pagesize;
   pid_t pid = ptid_get_pid (inferior_ptid);
@@ -337,7 +338,8 @@ inf_ttrace_insert_watchpoint (CORE_ADDR addr, int len, int type)
    type TYPE.  */
 
 static int
-inf_ttrace_remove_watchpoint (CORE_ADDR addr, int len, int type)
+inf_ttrace_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			      struct expression *cond)
 {
   const int pagesize = inf_ttrace_page_dict.pagesize;
   pid_t pid = ptid_get_pid (inferior_ptid);
diff --git a/gdb/mips-linux-nat.c b/gdb/mips-linux-nat.c
index fe05192..e9e7c02 100644
--- a/gdb/mips-linux-nat.c
+++ b/gdb/mips-linux-nat.c
@@ -926,7 +926,8 @@ populate_regs_from_watches (struct pt_watch_regs *regs)
    watch.  Return zero on success.  */
 
 static int
-mips_linux_insert_watchpoint (CORE_ADDR addr, int len, int type)
+mips_linux_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			      struct expression *cond)
 {
   struct pt_watch_regs regs;
   struct mips_watchpoint *new_watch;
@@ -975,7 +976,8 @@ mips_linux_insert_watchpoint (CORE_ADDR addr, int len, int type)
    Return zero on success.  */
 
 static int
-mips_linux_remove_watchpoint (CORE_ADDR addr, int len, int type)
+mips_linux_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			      struct expression *cond)
 {
   int retval;
   int deleted_one;
diff --git a/gdb/nto-procfs.c b/gdb/nto-procfs.c
index 2741ecf..a8cd1cd 100644
--- a/gdb/nto-procfs.c
+++ b/gdb/nto-procfs.c
@@ -1506,13 +1506,15 @@ procfs_can_use_hw_breakpoint (int type, int cnt, int othertype)
 }
 
 static int
-procfs_remove_hw_watchpoint (CORE_ADDR addr, int len, int type)
+procfs_remove_hw_watchpoint (CORE_ADDR addr, int len, int type,
+			     struct expression *cond)
 {
   return procfs_hw_watchpoint (addr, -1, type);
 }
 
 static int
-procfs_insert_hw_watchpoint (CORE_ADDR addr, int len, int type)
+procfs_insert_hw_watchpoint (CORE_ADDR addr, int len, int type,
+			     struct expression *cond)
 {
   return procfs_hw_watchpoint (addr, len, type);
 }
diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c
index f61ac5d..052ccc2 100644
--- a/gdb/ppc-linux-nat.c
+++ b/gdb/ppc-linux-nat.c
@@ -29,6 +29,8 @@
 #include "gdb_assert.h"
 #include "target.h"
 #include "linux-nat.h"
+#include "exceptions.h"
+#include "wrapper.h"
 
 #include <stdint.h>
 #include <sys/types.h>
@@ -1492,7 +1494,7 @@ ppc_linux_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
       if (booke_debug_info.data_bp_alignment
 	  && (addr + len > (addr & ~(booke_debug_info.data_bp_alignment - 1))
 	      + booke_debug_info.data_bp_alignment))
-	  return 0;
+	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
@@ -1685,8 +1687,309 @@ get_trigger_type (int rw)
   return t;
 }
 
+/* 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;
+  CORE_ADDR tmp_value;
+
+  if (!have_ptrace_booke_interface () || cnt == 0)
+    return 0;
+
+  p = booke_find_thread_points_by_tid (tid, 0);
+
+  if (p)
+    {
+      for (i = 0; i < max_slots_number; i++)
+	if (p->hw_breaks[i].hw_break != NULL
+	    && (p->hw_breaks[i].hw_break->condition_mode
+		!= PPC_BREAKPOINT_CONDITION_NONE))
+	  cnt--;
+
+      /* There are no available slots now.  */
+      if (cnt <= 0)
+	return 0;
+    }
+
+  return 1;
+}
+
+/* Calculate the enable bits and the contents of the Data Value Compare
+   debug register present in BookE processors.
+
+   ADDR is the address to be watched, LEN is the length of watched data
+   and DATA_VALUE is the value which will trigger the watchpoint.
+   DATA_VALUE_LEN is the length in bytes of DATA_VALUE, that is, the length
+   of the type of the value given by the user in the condition expression,
+   which may be different from the type of the watched value (e.g., watching
+   a short integer but with the condition given as an integer).
+   On exit, CONDITION_MODE will hold the enable bits for the DVC, and
+   CONDITION_VALUE will hold the value which should be put in the
+   DVC register.  */
+static void
+calculate_dvc (CORE_ADDR addr, int len, CORE_ADDR data_value,
+	       int data_value_len, uint32_t *condition_mode,
+	       uint64_t *condition_value)
+{
+  int i, num_byte_enable, align_offset, num_bytes_off_dvc,
+      rightmost_enabled_byte;
+  CORE_ADDR addr_end_data, addr_end_dvc;
+
+  /* The DVC register compares bytes within fixed-length windows which
+     are word-aligned, with length equal to that of the DVC register.
+     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;
+  addr_end_data = addr + len;
+  addr_end_dvc = (addr - align_offset
+		  + booke_debug_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;
+  /* Here, bytes are numbered from right to left.  */
+  rightmost_enabled_byte = (addr_end_data < addr_end_dvc)?
+			      addr_end_dvc - addr_end_data : 0;
+
+  *condition_mode = PPC_BREAKPOINT_CONDITION_AND;
+  for (i = 0; i < num_byte_enable; i++)
+    *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
+     (i.e., the ALIGN_OFFSET).  */
+
+  /* The size of the user-provided data value matters because the value is
+     "left-aligned" within DATA_VALUE, e.g: a 1-byte data type will occupy the
+     first byte of DATA_VALUE, a two-byte data type the first two, and so on.
+     This means that we need to adjust the user-provided value within
+     DATA_VALUE when copying it to CONDITION_VALUE.  */
+
+  if (data_value_len - len > align_offset)
+    /* The user-provided value type is larger than the watched value type,
+       and it is also to the right of the offset within the DVC register
+       where it should be.  */
+    *condition_value = (uint64_t) data_value << (data_value_len - len
+						 - align_offset) * 8;
+  else
+    /* The user-provided value type is either smaller than the watched
+       value type, or else it is equal or larger than the watched value
+       type but to the left of the offset within the DVC register where
+       it should be.  */
+    *condition_value = (uint64_t) data_value >> (align_offset
+						 - (data_value_len - len)) * 8;
+}
+
+/* Return the number of memory locations that need to be accessed to
+   evaluate the expression which generated the given value chain.
+   Returns -1 if there's any register access involved.  */
+static int
+num_memory_accesses (struct value *v)
+{
+  int found_memory_cnt = 0;
+  struct value *head = v;
+
+  /* The idea here is that evaluating an expression generates a series
+     of values, one holding the value of every subexpression.  (The
+     expression a*b+c has five subexpressions: a, b, a*b, c, and
+     a*b+c.)  GDB's values hold almost enough information to establish
+     the criteria given above --- they identify memory lvalues,
+     register lvalues, computed values, etcetera.  So we can evaluate
+     the expression, and then scan the chain of values that leaves
+     behind to determine the memory locations involved in the evaluation
+     of an expression.
+
+     However, I don't think that the values returned by inferior
+     function calls are special in any way.  So this function may not
+     notice that an expression contains an inferior function call.
+     FIXME.  */
+
+  for (; v; v = value_next (v))
+    {
+      if (VALUE_LVAL (v) == lval_memory)
+	{
+	  /* A lazy memory lvalue is one that GDB never needed to fetch;
+	     we either just used its address (e.g., `a' in `a.b') or
+	     we never needed it at all (e.g., `a' in `a,b').  */
+	  if (!value_lazy (v))
+	    found_memory_cnt++;
+	}
+      else if (VALUE_LVAL (v) != not_lval
+	       && deprecated_value_modifiable (v) == 0)
+	return -1;	/* ??? What does this represent? */
+      else if (VALUE_LVAL (v) == lval_register)
+	return -1;	/* cannot watch a register with a HW watchpoint */
+    }
+
+  return found_memory_cnt;
+}
+
+/* Find the current value of EXP.  Return the value in *VALP and *RESULTP
+   and the chain of intermediate and final values in *VAL_CHAIN.  RESULTP
+   and VAL_CHAIN may be NULL if the caller does not need them.
+
+   If a memory error occurs while evaluating the expression, *RESULTP will
+   be set to NULL.  *RESULTP may be a lazy value, if the result could
+   not be read from memory.  It is used to determine whether a value
+   is user-specified (we should watch the whole value) or intermediate
+   (we should watch only the bit used to locate the final value).
+
+   If the final value, or any intermediate value, could not be read
+   from memory, *VALP will be set to NULL.  *VAL_CHAIN will still be
+   set to any referenced values.  *VALP will never be a lazy value.
+
+   If VAL_CHAIN is non-NULL, *VAL_CHAIN will be released from the
+   value chain.  The caller must free the values individually.  If
+   VAL_CHAIN is NULL, all generated values will be left on the value
+   chain.  */
+static void
+fetch_subexp_value (struct expression *exp, int *pc, struct value **valp,
+			struct value **resultp, struct value **val_chain)
+{
+  struct value *mark, *new_mark, *result;
+  volatile struct gdb_exception ex;
+
+  *valp = NULL;
+  if (resultp)
+    *resultp = NULL;
+  if (val_chain)
+    *val_chain = NULL;
+
+  /* Evaluate the expression.  */
+  mark = value_mark ();
+  result = NULL;
+
+  TRY_CATCH (ex, RETURN_MASK_ALL)
+    {
+      result = evaluate_subexp (NULL_TYPE, exp, pc, EVAL_NORMAL);
+    }
+  if (ex.reason < 0)
+    {
+      /* Ignore memory errors, we want watchpoints pointing at
+	 inaccessible memory to still be created; otherwise, throw the
+	 error to some higher catcher.  */
+      switch (ex.error)
+	{
+	case MEMORY_ERROR:
+	  break;
+	default:
+	  throw_exception (ex);
+	  break;
+	}
+    }
+
+  new_mark = value_mark ();
+  if (mark == new_mark)
+    return;
+  if (resultp)
+    *resultp = result;
+
+  if (result != NULL
+      && (!value_lazy (result) || gdb_value_fetch_lazy (result)))
+    *valp = result;
+
+  if (val_chain)
+    {
+      /* Return the chain of intermediate values.  */
+      *val_chain = new_mark;
+      value_release_to_mark (mark);
+    }
+}
+
+/* Frees all the elements in a chain of values.  */
+static void
+free_value_chain (struct value *v)
+{
+  struct value *next;
+
+  for (; v; v = next)
+    {
+      next = value_next (v);
+      value_free (v);
+    }
+}
+
+/* Verifies whether the expression COND can be implemented using the
+   DVC (Data Value Compare) register in BookE processors.  The expression
+   must test the watch value for equality with a constant expression.  */
 static int
-ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw)
+check_condition (CORE_ADDR watch_addr, struct expression *cond,
+		 CORE_ADDR *data_value, int *data_value_len)
+{
+  int pc = 1, num_accesses_left, num_accesses_right;
+  struct value *val, *left_val, *right_val, *left_chain, *right_chain;
+
+  if (cond->elts[0].opcode != BINOP_EQUAL)
+    return 0;
+
+  fetch_subexp_value (cond, &pc, &left_val, NULL, &left_chain);
+  num_accesses_left = num_memory_accesses (left_chain);
+
+  if (left_val == NULL || num_accesses_left < 0)
+    {
+      free_value_chain (left_chain);
+
+      return 0;
+    }
+
+  fetch_subexp_value (cond, &pc, &right_val, NULL, &right_chain);
+  num_accesses_right = num_memory_accesses (right_chain);
+
+  if (right_val == NULL || num_accesses_right < 0)
+    {
+      free_value_chain (left_chain);
+      free_value_chain (right_chain);
+
+      return 0;
+    }
+
+  if (num_accesses_left == 1 && num_accesses_right == 0
+      && VALUE_LVAL (left_val) == lval_memory
+      && value_address (left_val) == watch_addr)
+    val = right_val;
+  else if (num_accesses_left == 0 && num_accesses_right == 1
+	   && VALUE_LVAL (right_val) == lval_memory
+	   && value_address (right_val) == watch_addr)
+    val = left_val;
+  else
+    {
+      free_value_chain (left_chain);
+      free_value_chain (right_chain);
+
+      return 0;
+    }
+
+  *data_value = value_as_long (val);
+  *data_value_len = TYPE_LENGTH (value_type (val));
+  *data_value = *data_value << (sizeof (CORE_ADDR) - *data_value_len) * 8;
+
+  free_value_chain (left_chain);
+  free_value_chain (right_chain);
+
+  return 1;
+}
+
+/* Return non-zero if the target is capable of using hardware to evaluate
+   the condition expression, thus only triggering the watchpoint when it is
+   true.  */
+static int
+ppc_linux_can_accel_watchpoint_condition (CORE_ADDR addr, int len, int rw,
+					  struct expression *cond)
+{
+  int data_value_len;
+  CORE_ADDR data_value;
+
+  return (have_ptrace_booke_interface ()
+	  && booke_debug_info.num_condition_regs > 0
+	  && check_condition (addr, cond, &data_value, &data_value_len));
+}
+
+static int
+ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw,
+			     struct expression *cond)
 {
   struct lwp_info *lp;
   ptid_t ptid;
@@ -1694,15 +1997,25 @@ ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw)
 
   if (have_ptrace_booke_interface ())
     {
+      int data_value_len;
       struct ppc_hw_breakpoint p;
+      CORE_ADDR data_value;
+
+      if (cond && can_use_watchpoint_cond_accel ()
+	  && check_condition (addr, cond, &data_value, &data_value_len))
+	calculate_dvc (addr, len, data_value, data_value_len,
+		       &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.condition_mode  = PPC_BREAKPOINT_CONDITION_NONE;
       p.addr            = (uint64_t) addr;
       p.addr2           = 0;
-      p.condition_value = 0;
 
       ALL_LWPS (lp, ptid)
 	booke_insert_point (&p, TIDGET (ptid));
@@ -1749,7 +2062,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, saved_dabr_value) < 0)
+	if (ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0,
+		    saved_dabr_value) < 0)
 	  return -1;
 
       ret = 0;
@@ -1759,7 +2073,8 @@ 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_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw,
+			     struct expression *cond)
 {
   struct lwp_info *lp;
   ptid_t ptid;
@@ -1767,15 +2082,25 @@ ppc_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw)
 
   if (have_ptrace_booke_interface ())
     {
+      int data_value_len;
       struct ppc_hw_breakpoint p;
+      CORE_ADDR data_value;
+
+      if (cond && booke_debug_info.num_condition_regs > 0
+	  && check_condition (addr, cond, &data_value, &data_value_len))
+	calculate_dvc (addr, len, data_value, data_value_len,
+		       &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.condition_mode  = PPC_BREAKPOINT_CONDITION_NONE;
       p.addr            = (uint64_t) addr;
       p.addr2           = 0;
-      p.condition_value = 0;
 
       ALL_LWPS (lp, ptid)
 	booke_remove_point (&p, TIDGET (ptid));
@@ -1786,7 +2111,8 @@ ppc_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw)
     {
       saved_dabr_value = 0;
       ALL_LWPS (lp, ptid)
-	if (ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0, saved_dabr_value) < 0)
+	if (ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0,
+		    saved_dabr_value) < 0)
 	  return -1;
 
       ret = 0;
@@ -2137,6 +2463,7 @@ _initialize_ppc_linux_nat (void)
   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_read_description = ppc_linux_read_description;
   t->to_auxv_parse = ppc_linux_auxv_parse;
diff --git a/gdb/procfs.c b/gdb/procfs.c
index 10aaa48..3bef9ab 100644
--- a/gdb/procfs.c
+++ b/gdb/procfs.c
@@ -5161,7 +5161,8 @@ procfs_stopped_data_address (struct target_ops *targ, CORE_ADDR *addr)
 }
 
 static int
-procfs_insert_watchpoint (CORE_ADDR addr, int len, int type)
+procfs_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			  struct expression *cond)
 {
   if (!target_have_steppable_watchpoint
       && !gdbarch_have_nonsteppable_watchpoint (target_gdbarch))
@@ -5182,7 +5183,8 @@ procfs_insert_watchpoint (CORE_ADDR addr, int len, int type)
 }
 
 static int
-procfs_remove_watchpoint (CORE_ADDR addr, int len, int type)
+procfs_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			  struct expression *cond)
 {
   return procfs_set_watchpoint (inferior_ptid, addr, 0, 0, 0);
 }
diff --git a/gdb/remote-m32r-sdi.c b/gdb/remote-m32r-sdi.c
index ad21774..ca450d5 100644
--- a/gdb/remote-m32r-sdi.c
+++ b/gdb/remote-m32r-sdi.c
@@ -1421,7 +1421,8 @@ m32r_can_use_hw_watchpoint (int type, int cnt, int othertype)
    watchpoint. */
 
 static int
-m32r_insert_watchpoint (CORE_ADDR addr, int len, int type)
+m32r_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *cond)
 {
   int i;
 
@@ -1445,7 +1446,8 @@ m32r_insert_watchpoint (CORE_ADDR addr, int len, int type)
 }
 
 static int
-m32r_remove_watchpoint (CORE_ADDR addr, int len, int type)
+m32r_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *cond)
 {
   int i;
 
diff --git a/gdb/remote-mips.c b/gdb/remote-mips.c
index 28d2ecb..ec2e5eb 100644
--- a/gdb/remote-mips.c
+++ b/gdb/remote-mips.c
@@ -2401,7 +2401,8 @@ calculate_mask (CORE_ADDR addr, int len)
    watchpoint. */
 
 int
-mips_insert_watchpoint (CORE_ADDR addr, int len, int type)
+mips_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *cond)
 {
   if (mips_set_breakpoint (addr, len, type))
     return -1;
@@ -2412,7 +2413,8 @@ mips_insert_watchpoint (CORE_ADDR addr, int len, int type)
 /* Remove a watchpoint.  */
 
 int
-mips_remove_watchpoint (CORE_ADDR addr, int len, int type)
+mips_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *cond)
 {
   if (mips_clear_breakpoint (addr, len, type))
     return -1;
diff --git a/gdb/remote.c b/gdb/remote.c
index 35d517d..c5c8d3e 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -7537,7 +7537,8 @@ watchpoint_to_Z_packet (int type)
 }
 
 static int
-remote_insert_watchpoint (CORE_ADDR addr, int len, int type)
+remote_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			  struct expression *cond)
 {
   struct remote_state *rs = get_remote_state ();
   char *p;
@@ -7570,7 +7571,8 @@ remote_insert_watchpoint (CORE_ADDR addr, int len, int type)
 
 
 static int
-remote_remove_watchpoint (CORE_ADDR addr, int len, int type)
+remote_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			  struct expression *cond)
 {
   struct remote_state *rs = get_remote_state ();
   char *p;
diff --git a/gdb/s390-nat.c b/gdb/s390-nat.c
index 3af42ff..b412fda 100644
--- a/gdb/s390-nat.c
+++ b/gdb/s390-nat.c
@@ -335,7 +335,8 @@ s390_fix_watch_points (ptid_t ptid)
 }
 
 static int
-s390_insert_watchpoint (CORE_ADDR addr, int len, int type)
+s390_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *cond)
 {
   struct lwp_info *lp;
   ptid_t ptid;
@@ -356,7 +357,8 @@ s390_insert_watchpoint (CORE_ADDR addr, int len, int type)
 }
 
 static int
-s390_remove_watchpoint (CORE_ADDR addr, int len, int type)
+s390_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *cond)
 {
   struct lwp_info *lp;
   ptid_t ptid;
diff --git a/gdb/target.c b/gdb/target.c
index 7aa77e6..c3fb29b 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -117,9 +117,11 @@ static int debug_to_insert_hw_breakpoint (struct gdbarch *,
 static int debug_to_remove_hw_breakpoint (struct gdbarch *,
 					  struct bp_target_info *);
 
-static int debug_to_insert_watchpoint (CORE_ADDR, int, int);
+static int debug_to_insert_watchpoint (CORE_ADDR, int, int,
+				       struct expression *);
 
-static int debug_to_remove_watchpoint (CORE_ADDR, int, int);
+static int debug_to_remove_watchpoint (CORE_ADDR, int, int,
+				       struct expression *);
 
 static int debug_to_stopped_by_watchpoint (void);
 
@@ -130,6 +132,9 @@ static int debug_to_watchpoint_addr_within_range (struct target_ops *,
 
 static int debug_to_region_ok_for_hw_watchpoint (CORE_ADDR, int);
 
+static int debug_to_can_accel_watchpoint_condition (CORE_ADDR, int, int,
+						    struct expression *);
+
 static void debug_to_terminal_init (void);
 
 static void debug_to_terminal_inferior (void);
@@ -607,6 +612,7 @@ update_current_target (void)
       INHERIT (to_stopped_by_watchpoint, t);
       INHERIT (to_watchpoint_addr_within_range, t);
       INHERIT (to_region_ok_for_hw_watchpoint, t);
+      INHERIT (to_can_accel_watchpoint_condition, t);
       INHERIT (to_terminal_init, t);
       INHERIT (to_terminal_inferior, t);
       INHERIT (to_terminal_ours_for_output, t);
@@ -726,10 +732,10 @@ update_current_target (void)
 	    (int (*) (struct gdbarch *, struct bp_target_info *))
 	    return_minus_one);
   de_fault (to_insert_watchpoint,
-	    (int (*) (CORE_ADDR, int, int))
+	    (int (*) (CORE_ADDR, int, int, struct expression *))
 	    return_minus_one);
   de_fault (to_remove_watchpoint,
-	    (int (*) (CORE_ADDR, int, int))
+	    (int (*) (CORE_ADDR, int, int, struct expression *))
 	    return_minus_one);
   de_fault (to_stopped_by_watchpoint,
 	    (int (*) (void))
@@ -741,6 +747,9 @@ 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_can_accel_watchpoint_condition,
+            (int (*) (CORE_ADDR, int, int, struct expression *))
+            return_zero);
   de_fault (to_terminal_init,
 	    (void (*) (void))
 	    target_ignore);
@@ -3306,6 +3315,21 @@ debug_to_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
 }
 
 static int
+debug_to_can_accel_watchpoint_condition (CORE_ADDR addr, int len, int rw,
+					 struct expression *cond)
+{
+  int retval;
+
+  retval = debug_target.to_can_accel_watchpoint_condition (addr, len, rw, cond);
+
+  fprintf_unfiltered (gdb_stdlog,
+		      "target_can_accel_watchpoint_condition (0x%lx, %d, %d, 0x%lx) = %ld\n",
+		      (unsigned long) addr, len, rw, (unsigned long) cond,
+		      (unsigned long) retval);
+  return retval;
+}
+
+static int
 debug_to_stopped_by_watchpoint (void)
 {
   int retval;
@@ -3380,28 +3404,32 @@ debug_to_remove_hw_breakpoint (struct gdbarch *gdbarch,
 }
 
 static int
-debug_to_insert_watchpoint (CORE_ADDR addr, int len, int type)
+debug_to_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			    struct expression *cond)
 {
   int retval;
 
-  retval = debug_target.to_insert_watchpoint (addr, len, type);
+  retval = debug_target.to_insert_watchpoint (addr, len, type, cond);
 
   fprintf_unfiltered (gdb_stdlog,
-		      "target_insert_watchpoint (0x%lx, %d, %d) = %ld\n",
-		      (unsigned long) addr, len, type, (unsigned long) retval);
+		      "target_insert_watchpoint (0x%lx, %d, %d, 0x%ld) = %ld\n",
+		      (unsigned long) addr, len, type, (unsigned long) cond,
+		      (unsigned long) retval);
   return retval;
 }
 
 static int
-debug_to_remove_watchpoint (CORE_ADDR addr, int len, int type)
+debug_to_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			    struct expression *cond)
 {
   int retval;
 
-  retval = debug_target.to_remove_watchpoint (addr, len, type);
+  retval = debug_target.to_remove_watchpoint (addr, len, type, cond);
 
   fprintf_unfiltered (gdb_stdlog,
-		      "target_remove_watchpoint (0x%lx, %d, %d) = %ld\n",
-		      (unsigned long) addr, len, type, (unsigned long) retval);
+		      "target_remove_watchpoint (0x%lx, %d, %d, 0x%ld) = %ld\n",
+		      (unsigned long) addr, len, type, (unsigned long) cond,
+		      (unsigned long) retval);
   return retval;
 }
 
@@ -3656,6 +3684,7 @@ setup_target_debug (void)
   current_target.to_stopped_data_address = debug_to_stopped_data_address;
   current_target.to_watchpoint_addr_within_range = debug_to_watchpoint_addr_within_range;
   current_target.to_region_ok_for_hw_watchpoint = debug_to_region_ok_for_hw_watchpoint;
+  current_target.to_can_accel_watchpoint_condition = debug_to_can_accel_watchpoint_condition;
   current_target.to_terminal_init = debug_to_terminal_init;
   current_target.to_terminal_inferior = debug_to_terminal_inferior;
   current_target.to_terminal_ours_for_output = debug_to_terminal_ours_for_output;
diff --git a/gdb/target.h b/gdb/target.h
index 870a1eb..9ef2947 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -36,6 +36,8 @@ struct trace_status;
 struct uploaded_tsv;
 struct uploaded_tp;
 
+struct expression;
+
 /* 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
@@ -420,8 +422,12 @@ struct target_ops
     int (*to_can_use_hw_breakpoint) (int, int, int);
     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);
+
+    /* Documentation of what the two routines belwo are expected to do is
+       provided with the corresponding target_* macros.  */
+    int (*to_remove_watchpoint) (CORE_ADDR, int, int, struct expression *);
+    int (*to_insert_watchpoint) (CORE_ADDR, int, int, struct expression *);
+
     int (*to_stopped_by_watchpoint) (void);
     int to_have_steppable_watchpoint;
     int to_have_continuable_watchpoint;
@@ -429,6 +435,8 @@ struct target_ops
     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_can_accel_watchpoint_condition) (CORE_ADDR, int, int,
+					      struct expression *);
     void (*to_terminal_init) (void);
     void (*to_terminal_inferior) (void);
     void (*to_terminal_ours_for_output) (void);
@@ -1282,14 +1290,15 @@ extern char *normal_pid_to_str (ptid_t ptid);
 
 /* 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.
+   COND is the expression for its condition, or NULL if there's none.
    Returns 0 for success, 1 if the watchpoint type is not supported,
    -1 for failure.  */
 
-#define	target_insert_watchpoint(addr, len, type)	\
-     (*current_target.to_insert_watchpoint) (addr, len, type)
+#define	target_insert_watchpoint(addr, len, type, cond) \
+     (*current_target.to_insert_watchpoint) (addr, len, type, cond)
 
-#define	target_remove_watchpoint(addr, len, type)	\
-     (*current_target.to_remove_watchpoint) (addr, len, type)
+#define	target_remove_watchpoint(addr, len, type, cond) \
+     (*current_target.to_remove_watchpoint) (addr, len, type, cond)
 
 #define target_insert_hw_breakpoint(gdbarch, bp_tgt) \
      (*current_target.to_insert_hw_breakpoint) (gdbarch, bp_tgt)
@@ -1306,6 +1315,12 @@ 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)
 
+/* Return non-zero if the target is capable of using hardware to evaluate
+   the condition expression, thus only triggering the watchpoint when it is
+   true.  */
+#define target_can_accel_watchpoint_condition(addr, len, type, cond) \
+  (*current_target.to_can_accel_watchpoint_condition) (addr, len, type, cond)
+
 /* Target can execute in reverse?  */
 #define target_can_execute_reverse \
      (current_target.to_can_execute_reverse ? \

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 2/4] Hardware accelerated watchpoint conditions
  2010-06-23 17:21                 ` Thiago Jung Bauermann
@ 2010-06-23 19:57                   ` Ulrich Weigand
  2010-07-01 14:51                     ` Thiago Jung Bauermann
  0 siblings, 1 reply; 17+ messages in thread
From: Ulrich Weigand @ 2010-06-23 19:57 UTC (permalink / raw)
  To: Thiago Jung Bauermann
  Cc: Joel Brobecker, gdb-patches, Luis Machado, Matt Tyrlik

Thiago Jung Bauermann wrote:

> Indeed. I didn't realised that. I changed the patch to use the approach
> found in can_use_hardware_watchpoint: evaluate the expression and then
> go through the value chain generated by the evaluation to check whether
> there's any memory or register access. What do you think?

Ah, excellent point.  I agree this should work fine, thanks.

> > DATA_LEN is not described.  I'm wondering why two lengths are needed here?
> 
> I described it now. We need two lengths because the watched value and
> the constant in the condition may have different types. For instance, if
> you have a "short int foo" and your condition is "foo == 2", then the
> watched variable is of type short int and the condition constant is an
> int.

Still seems unnecessarily complex to me, but see below ...

> +static void
> +calculate_dvc (CORE_ADDR addr, int len, CORE_ADDR data_value,
> +	       int data_value_len, uint32_t *condition_mode,
> +	       uint64_t *condition_value)
> +{
> +  int i, num_byte_enable, align_offset, num_bytes_off_dvc,
> +      rightmost_enabled_byte;
> +  CORE_ADDR addr_end_data, addr_end_dvc;
> +
> +  /* The DVC register compares bytes within fixed-length windows which
> +     are word-aligned, with length equal to that of the DVC register.
> +     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;
> +  addr_end_data = addr + len;
> +  addr_end_dvc = (addr - align_offset
> +		  + booke_debug_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;
> +  /* Here, bytes are numbered from right to left.  */
> +  rightmost_enabled_byte = (addr_end_data < addr_end_dvc)?
> +			      addr_end_dvc - addr_end_data : 0;
> +
> +  *condition_mode = PPC_BREAKPOINT_CONDITION_AND;
> +  for (i = 0; i < num_byte_enable; i++)
> +    *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
> +     (i.e., the ALIGN_OFFSET).  */
> +
> +  /* The size of the user-provided data value matters because the value is
> +     "left-aligned" within DATA_VALUE, e.g: a 1-byte data type will occupy the
> +     first byte of DATA_VALUE, a two-byte data type the first two, and so on.

Well, but that's only because you arranged the value in that weird way
in the first place :-)   See check_condition below:
  *data_value = value_as_long (val);
  *data_value_len = TYPE_LENGTH (value_type (val));
  *data_value = *data_value << (sizeof (CORE_ADDR) - *data_value_len) * 8;

> +  if (data_value_len - len > align_offset)
> +    /* The user-provided value type is larger than the watched value type,
> +       and it is also to the right of the offset within the DVC register
> +       where it should be.  */
> +    *condition_value = (uint64_t) data_value << (data_value_len - len
> +						 - align_offset) * 8;
> +  else
> +    /* The user-provided value type is either smaller than the watched
> +       value type, or else it is equal or larger than the watched value
> +       type but to the left of the offset within the DVC register where
> +       it should be.  */
> +    *condition_value = (uint64_t) data_value >> (align_offset
> +						 - (data_value_len - len)) * 8;

Unless I'm missing something, this also makes the additional assumption
that the width of the DVC register equals the size of a CORE_ADDR:
In check_condition, you ensure the value is "left-aligned" within a
CORE_ADDR, and here you assume the value is left-aligned within the
DVC registers size ...

It seems to me this whole thing could be simplified by removing the
DATA_VALUE_LEN, *not* shifting the value at all in check_condition,
and replacing the above if-else construct by something along the
lines of:

   *condition_value = ((uint_64_t) data_value >> num_bytes_off_dvc * 8)
		       << (rightmost_enabled_byte * 8);

Thoughts?

As a side remark, if num_bytes_off_dvc is non-zero, it seems the hardware
will only check *part* of the condition.  That's probably better than
nothing, but means the definition of target_can_accel_watchpoint_condition:

  /* Return non-zero if the target is capable of using hardware to evaluate
     the condition expression, thus only triggering the watchpoint when it is
     true.  */

is a bit optimistic.  Maybe it should be reworded along the lines of

  /* Return non-zero if the target is capable of using hardware to evaluate
     the condition expression.  In this case, if the condition is false when
     the watched memory location changes, execution may continue without
     the debugger being notified.  */


> +  for (; v; v = value_next (v))
> +    {
> +      if (VALUE_LVAL (v) == lval_memory)
> +	{
> +	  /* A lazy memory lvalue is one that GDB never needed to fetch;
> +	     we either just used its address (e.g., `a' in `a.b') or
> +	     we never needed it at all (e.g., `a' in `a,b').  */
> +	  if (!value_lazy (v))
> +	    found_memory_cnt++;
> +	}
> +      else if (VALUE_LVAL (v) != not_lval
> +	       && deprecated_value_modifiable (v) == 0)
> +	return -1;	/* ??? What does this represent? */

These are values from the history (e.g. $1).  In this context, they
should be treated as non-lvalues, so they should be fine ...

> +/* Find the current value of EXP.  Return the value in *VALP and *RESULTP
> +   and the chain of intermediate and final values in *VAL_CHAIN.  RESULTP
> +   and VAL_CHAIN may be NULL if the caller does not need them.
> +
> +   If a memory error occurs while evaluating the expression, *RESULTP will
> +   be set to NULL.  *RESULTP may be a lazy value, if the result could
> +   not be read from memory.  It is used to determine whether a value
> +   is user-specified (we should watch the whole value) or intermediate
> +   (we should watch only the bit used to locate the final value).
> +
> +   If the final value, or any intermediate value, could not be read
> +   from memory, *VALP will be set to NULL.  *VAL_CHAIN will still be
> +   set to any referenced values.  *VALP will never be a lazy value.
> +
> +   If VAL_CHAIN is non-NULL, *VAL_CHAIN will be released from the
> +   value chain.  The caller must free the values individually.  If
> +   VAL_CHAIN is NULL, all generated values will be left on the value
> +   chain.  */
> +static void
> +fetch_subexp_value (struct expression *exp, int *pc, struct value **valp,
> +			struct value **resultp, struct value **val_chain)

This whole function is a 1:1 copy of breakpoint.c:fetch_watchpoint_value,
right?  I'd prefer if this function were moved to expr.c and used from
both places.

> +/* Frees all the elements in a chain of values.  */
> +static void
> +free_value_chain (struct value *v)
> +{
> +  struct value *next;
> +
> +  for (; v; v = next)
> +    {
> +      next = value_next (v);
> +      value_free (v);
> +    }
> +}

Likewise, this ought to go to value.c.

> +    /* Documentation of what the two routines belwo are expected to do is
> +       provided with the corresponding target_* macros.  */

Typo "belwo"

Otherwise, this is looking really good now!

Thanks,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 2/4] Hardware accelerated watchpoint conditions
  2010-06-23 19:57                   ` Ulrich Weigand
@ 2010-07-01 14:51                     ` Thiago Jung Bauermann
  2010-07-02 13:20                       ` Ulrich Weigand
  0 siblings, 1 reply; 17+ messages in thread
From: Thiago Jung Bauermann @ 2010-07-01 14:51 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: Joel Brobecker, gdb-patches, Luis Machado, Matt Tyrlik

[-- Attachment #1: Type: text/plain, Size: 8681 bytes --]

Hi,

On Wed, 2010-06-23 at 21:57 +0200, Ulrich Weigand wrote:
> Thiago Jung Bauermann wrote:
> > +  /* The size of the user-provided data value matters because the value is
> > +     "left-aligned" within DATA_VALUE, e.g: a 1-byte data type will occupy the
> > +     first byte of DATA_VALUE, a two-byte data type the first two, and so on.
> 
> Well, but that's only because you arranged the value in that weird way
> in the first place :-)   See check_condition below:
>   *data_value = value_as_long (val);
>   *data_value_len = TYPE_LENGTH (value_type (val));
>   *data_value = *data_value << (sizeof (CORE_ADDR) - *data_value_len) * 8;

That was true when using memcpy instead of value_as_long, and I thought
that keeping it that way made things simpler for calculate_dvc. It turns
out that I was wrong.

> > +  if (data_value_len - len > align_offset)
> > +    /* The user-provided value type is larger than the watched value type,
> > +       and it is also to the right of the offset within the DVC register
> > +       where it should be.  */
> > +    *condition_value = (uint64_t) data_value << (data_value_len - len
> > +						 - align_offset) * 8;
> > +  else
> > +    /* The user-provided value type is either smaller than the watched
> > +       value type, or else it is equal or larger than the watched value
> > +       type but to the left of the offset within the DVC register where
> > +       it should be.  */
> > +    *condition_value = (uint64_t) data_value >> (align_offset
> > +						 - (data_value_len - len)) * 8;
> 
> Unless I'm missing something, this also makes the additional assumption
> that the width of the DVC register equals the size of a CORE_ADDR:
> In check_condition, you ensure the value is "left-aligned" within a
> CORE_ADDR, and here you assume the value is left-aligned within the
> DVC registers size ...
> 
> It seems to me this whole thing could be simplified by removing the
> DATA_VALUE_LEN, *not* shifting the value at all in check_condition,
> and replacing the above if-else construct by something along the
> lines of:
> 
>    *condition_value = ((uint_64_t) data_value >> num_bytes_off_dvc * 8)
> 		       << (rightmost_enabled_byte * 8);
> 
> Thoughts?

I made the changes you suggested and they indeed simplified the code.

> As a side remark, if num_bytes_off_dvc is non-zero, it seems the hardware
> will only check *part* of the condition.  That's probably better than
> nothing, but means the definition of target_can_accel_watchpoint_condition:
> 
>   /* Return non-zero if the target is capable of using hardware to evaluate
>      the condition expression, thus only triggering the watchpoint when it is
>      true.  */
> 
> is a bit optimistic.  Maybe it should be reworded along the lines of
> 
>   /* Return non-zero if the target is capable of using hardware to evaluate
>      the condition expression.  In this case, if the condition is false when
>      the watched memory location changes, execution may continue without
>      the debugger being notified.  */
> 

I changed the comment to read:

/* Return non-zero if the target is capable of using hardware to evaluate
   the condition expression.  In this case, if the condition is false when
   the watched memory location changes, execution may continue without the
   debugger being notified.

   Due to limitations in the hardware implementation, it may be capable of
   avoiding triggering the watchpoint in some cases where the condition
   expression is false, but may report some false positives as well.
   For this reason, GDB will still evaluate the condition expression when
   the watchpoint triggers.  */

What do you think?

> > +  for (; v; v = value_next (v))
> > +    {
> > +      if (VALUE_LVAL (v) == lval_memory)
> > +	{
> > +	  /* A lazy memory lvalue is one that GDB never needed to fetch;
> > +	     we either just used its address (e.g., `a' in `a.b') or
> > +	     we never needed it at all (e.g., `a' in `a,b').  */
> > +	  if (!value_lazy (v))
> > +	    found_memory_cnt++;
> > +	}
> > +      else if (VALUE_LVAL (v) != not_lval
> > +	       && deprecated_value_modifiable (v) == 0)
> > +	return -1;	/* ??? What does this represent? */
> 
> These are values from the history (e.g. $1).  In this context, they
> should be treated as non-lvalues, so they should be fine ...

I removed that else if then. I'll submit a separate patch to replace
that comment in can_use_hardware_watchpoint.

> > +/* Find the current value of EXP.  Return the value in *VALP and *RESULTP
> > +   and the chain of intermediate and final values in *VAL_CHAIN.  RESULTP
> > +   and VAL_CHAIN may be NULL if the caller does not need them.
> > +
> > +   If a memory error occurs while evaluating the expression, *RESULTP will
> > +   be set to NULL.  *RESULTP may be a lazy value, if the result could
> > +   not be read from memory.  It is used to determine whether a value
> > +   is user-specified (we should watch the whole value) or intermediate
> > +   (we should watch only the bit used to locate the final value).
> > +
> > +   If the final value, or any intermediate value, could not be read
> > +   from memory, *VALP will be set to NULL.  *VAL_CHAIN will still be
> > +   set to any referenced values.  *VALP will never be a lazy value.
> > +
> > +   If VAL_CHAIN is non-NULL, *VAL_CHAIN will be released from the
> > +   value chain.  The caller must free the values individually.  If
> > +   VAL_CHAIN is NULL, all generated values will be left on the value
> > +   chain.  */
> > +static void
> > +fetch_subexp_value (struct expression *exp, int *pc, struct value **valp,
> > +			struct value **resultp, struct value **val_chain)
> 
> This whole function is a 1:1 copy of breakpoint.c:fetch_watchpoint_value,
> right?  I'd prefer if this function were moved to expr.c and used from
> both places.

I copied that function to ppc-linux-nat.c because I expected I'd need
bigger changes in it. It turned out I only needed a pc argument for
evaluate_subexp. I put the function in eval.c and changed callers of
fetch_watchpoint_value in breakpoint.c to use fetch_subexp_value with a
dummy pc argument.

> > +/* Frees all the elements in a chain of values.  */
> > +static void
> > +free_value_chain (struct value *v)
> > +{
> > +  struct value *next;
> > +
> > +  for (; v; v = next)
> > +    {
> > +      next = value_next (v);
> > +      value_free (v);
> > +    }
> > +}
> 
> Likewise, this ought to go to value.c.

Done.

> > +    /* Documentation of what the two routines belwo are expected to do is
> > +       provided with the corresponding target_* macros.  */
> 
> Typo "belwo"

Fixed.

> Otherwise, this is looking really good now!

Great! Thanks for your review and suggestions! There were indeed
definite improvements in the patch.

Thanks and regards,
Thiago Jung Bauermann
IBM Linux Technology Center


2010-07-01  Sergio Durigan Junior  <sergiodj@linux.vnet.ibm.com>
	    Thiago Jung Bauermann  <bauerman@br.ibm.com>

	* breakpoint.c (fetch_watchpoint_value): Rename to fetch_subexp_value
	and move to eval.c.  Change callers.
	(insert_bp_location): Pass watchpoint condition in
	target_insert_watchpoint.
	(remove_breakpoint_1) Pass watchpoint condition in
	target_remove_watchpoint.
	(watchpoint_locations_match): Call
	target_can_accel_watchpoint_condition.
	* eval.c: Include wrapper.h.
	(fetch_subexp_value): Moved from breakpoint.c.
	* ppc-linux-nat.c (ppc_linux_region_ok_for_hw_watchpoint):
	Formatting fix.
	(can_use_watchpoint_cond_accel): New function.
	(calculate_dvc): Likewise.
	(num_memory_accesses): Likewise.
	(check_condition): Likewise.
	(ppc_linux_can_accel_watchpoint_condition): Likewise
	(ppc_linux_insert_watchpoint): Call can_use_watchpoint_cond_accel,
	check_condition and calculate_dvc.
	(ppc_linux_remove_watchpoint): Likewise.
	(_initialize_ppc_linux_nat): Set to_can_accel_watchpoint_condition to
	ppc_linux_can_accel_watchpoint_condition
	* target.c (debug_to_insert_watchpoint): Add argument for watchpoint
	condition.
	(debug_to_remove_watchpoint): Likewise.
	(debug_to_can_accel_watchpoint_condition): New function.
	(update_current_target): Set to_can_accel_watchpoint_condition.
	(setup_target_debug): Set to_can_accel_watchpoint_condition.
	* target.h: Add opaque declaration for struct expression.
	(struct target_ops) <to_insert_watchpoint>,
	<to_remove_watchpoint>: Add new arguments to pass the watchpoint
	<to_can_accel_watchpoint_condition>: New member.
	condition.  Update all callers and implementations.
	(target_can_accel_watchpoint_condition): New macro.
	* value.c (free_value_chain): New function.
	* value.h (fetch_subexp_value): New prototype.
	(free_value_chain): Likewise.


[-- Attachment #2: condition.diff --]
[-- Type: text/x-patch, Size: 38929 bytes --]

Index: gdb/breakpoint.c
===================================================================
--- gdb.orig/breakpoint.c	2010-07-01 00:00:32.000000000 -0300
+++ gdb/breakpoint.c	2010-07-01 00:00:56.000000000 -0300
@@ -1202,84 +1202,6 @@ is_watchpoint (const struct breakpoint *
 	  || bpt->type == bp_watchpoint);
 }
 
-/* Find the current value of a watchpoint on EXP.  Return the value in
-   *VALP and *RESULTP and the chain of intermediate and final values
-   in *VAL_CHAIN.  RESULTP and VAL_CHAIN may be NULL if the caller does
-   not need them.
-
-   If a memory error occurs while evaluating the expression, *RESULTP will
-   be set to NULL.  *RESULTP may be a lazy value, if the result could
-   not be read from memory.  It is used to determine whether a value
-   is user-specified (we should watch the whole value) or intermediate
-   (we should watch only the bit used to locate the final value).
-
-   If the final value, or any intermediate value, could not be read
-   from memory, *VALP will be set to NULL.  *VAL_CHAIN will still be
-   set to any referenced values.  *VALP will never be a lazy value.
-   This is the value which we store in struct breakpoint.
-
-   If VAL_CHAIN is non-NULL, *VAL_CHAIN will be released from the
-   value chain.  The caller must free the values individually.  If
-   VAL_CHAIN is NULL, all generated values will be left on the value
-   chain.  */
-
-static void
-fetch_watchpoint_value (struct expression *exp, struct value **valp,
-			struct value **resultp, struct value **val_chain)
-{
-  struct value *mark, *new_mark, *result;
-  volatile struct gdb_exception ex;
-
-  *valp = NULL;
-  if (resultp)
-    *resultp = NULL;
-  if (val_chain)
-    *val_chain = NULL;
-
-  /* Evaluate the expression.  */
-  mark = value_mark ();
-  result = NULL;
-
-  TRY_CATCH (ex, RETURN_MASK_ALL)
-    {
-      result = evaluate_expression (exp);
-    }
-  if (ex.reason < 0)
-    {
-      /* Ignore memory errors, we want watchpoints pointing at
-	 inaccessible memory to still be created; otherwise, throw the
-	 error to some higher catcher.  */
-      switch (ex.error)
-	{
-	case MEMORY_ERROR:
-	  break;
-	default:
-	  throw_exception (ex);
-	  break;
-	}
-    }
-
-  new_mark = value_mark ();
-  if (mark == new_mark)
-    return;
-  if (resultp)
-    *resultp = result;
-
-  /* Make sure it's not lazy, so that after the target stops again we
-     have a non-lazy previous value to compare with.  */
-  if (result != NULL
-      && (!value_lazy (result) || gdb_value_fetch_lazy (result)))
-    *valp = result;
-
-  if (val_chain)
-    {
-      /* Return the chain of intermediate values.  We use this to
-	 decide which addresses to watch.  */
-      *val_chain = new_mark;
-      value_release_to_mark (mark);
-    }
-}
-
 /* Assuming that B is a watchpoint: returns true if the current thread
    and its running state are safe to evaluate or update watchpoint B.
    Watchpoints on local expressions need to be evaluated in the
@@ -1437,10 +1359,11 @@ update_watchpoint (struct breakpoint *b,
     }
   else if (within_current_scope && b->exp)
     {
+      int pc = 0;
       struct value *val_chain, *v, *result, *next;
       struct program_space *frame_pspace;
 
-      fetch_watchpoint_value (b->exp, &v, &result, &val_chain);
+      fetch_subexp_value (b->exp, &pc, &v, &result, &val_chain);
 
       /* Avoid setting b->val if it's already set.  The meaning of
 	 b->val is 'the last value' user saw, and we should update
@@ -1796,7 +1719,8 @@ Note: automatically using hardware break
     {
       val = target_insert_watchpoint (bpt->address,
 				      bpt->length,
-				      bpt->watchpoint_type);
+				      bpt->watchpoint_type,
+				      bpt->owner->cond_exp);
 
       /* If trying to set a read-watchpoint, and it turns out it's not
 	 supported, try emulating one with an access watchpoint.  */
@@ -1824,7 +1748,8 @@ Note: automatically using hardware break
 	    {
 	      val = target_insert_watchpoint (bpt->address,
 					      bpt->length,
-					      hw_access);
+					      hw_access,
+					      bpt->owner->cond_exp);
 	      if (val == 0)
 		bpt->watchpoint_type = hw_access;
 	    }
@@ -2493,8 +2418,8 @@ remove_breakpoint_1 (struct bp_location
   else if (b->loc_type == bp_loc_hardware_watchpoint)
     {
       b->inserted = (is == mark_inserted);
-      val = target_remove_watchpoint (b->address, b->length, 
-				      b->watchpoint_type);
+      val = target_remove_watchpoint (b->address, b->length,
+				      b->watchpoint_type, b->owner->cond_exp);
 
       /* Failure to remove any of the hardware watchpoints comes here.  */
       if ((is == mark_uninserted) && (b->inserted))
@@ -3647,10 +3572,11 @@ watchpoint_check (void *p)
          call free_all_values.  We can't call free_all_values because
          we might be in the middle of evaluating a function call.  */
 
+      int pc = 0;
       struct value *mark = value_mark ();
       struct value *new_val;
 
-      fetch_watchpoint_value (b->exp, &new_val, NULL, NULL);
+      fetch_subexp_value (b->exp, &pc, &new_val, NULL, NULL);
 
       /* We use value_equal_contents instead of value_equal because the latter
 	 coerces an array to a pointer, thus comparing just the address of the
@@ -5217,6 +5143,21 @@ watchpoint_locations_match (struct bp_lo
   gdb_assert (loc1->owner != NULL);
   gdb_assert (loc2->owner != NULL);
 
+  /* If the target can evaluate the condition expression in hardware, then we
+     we need to insert both watchpoints even if they are at the same place.
+     Otherwise the watchpoint will only trigger when the condition of whichever
+     watchpoint was inserted evaluates to true, not giving a chance for GDB to
+     check the condition of the other watchpoint.  */
+  if ((loc1->owner->cond_exp
+       && target_can_accel_watchpoint_condition (loc1->address, loc1->length,
+						 loc1->watchpoint_type,
+						 loc1->owner->cond_exp))
+      || (loc2->owner->cond_exp
+	  && target_can_accel_watchpoint_condition (loc2->address, loc2->length,
+						    loc2->watchpoint_type,
+						    loc2->owner->cond_exp)))
+    return 0;
+
   /* Note that this checks the owner's type, not the location's.  In
      case the target does not support read watchpoints, but does
      support access watchpoints, we'll have bp_read_watchpoint
@@ -7854,6 +7795,7 @@ watch_command_1 (char *arg, int accessfl
   enum bptype bp_type;
   int mem_cnt = 0;
   int thread = -1;
+  int pc = 0;
 
   /* Make sure that we actually have parameters to parse.  */
   if (arg != NULL && arg[0] != '\0')
@@ -7940,7 +7882,7 @@ watch_command_1 (char *arg, int accessfl
 
   exp_valid_block = innermost_block;
   mark = value_mark ();
-  fetch_watchpoint_value (exp, &val, NULL, NULL);
+  fetch_subexp_value (exp, &pc, &val, NULL, NULL);
   if (val != NULL)
     release_value (val);
 
Index: gdb/eval.c
===================================================================
--- gdb.orig/eval.c	2010-07-01 00:00:32.000000000 -0300
+++ gdb/eval.c	2010-07-01 00:00:56.000000000 -0300
@@ -43,6 +43,7 @@
 #include "gdb_obstack.h"
 #include "objfiles.h"
 #include "python/python.h"
+#include "wrapper.h"
 
 #include "gdb_assert.h"
 
@@ -186,6 +187,84 @@ evaluate_subexpression_type (struct expr
   return evaluate_subexp (NULL_TYPE, exp, &subexp, EVAL_AVOID_SIDE_EFFECTS);
 }
 
+/* Find the current value of a watchpoint on EXP.  Return the value in
+   *VALP and *RESULTP and the chain of intermediate and final values
+   in *VAL_CHAIN.  RESULTP and VAL_CHAIN may be NULL if the caller does
+   not need them.
+
+   If a memory error occurs while evaluating the expression, *RESULTP will
+   be set to NULL.  *RESULTP may be a lazy value, if the result could
+   not be read from memory.  It is used to determine whether a value
+   is user-specified (we should watch the whole value) or intermediate
+   (we should watch only the bit used to locate the final value).
+
+   If the final value, or any intermediate value, could not be read
+   from memory, *VALP will be set to NULL.  *VAL_CHAIN will still be
+   set to any referenced values.  *VALP will never be a lazy value.
+   This is the value which we store in struct breakpoint.
+
+   If VAL_CHAIN is non-NULL, *VAL_CHAIN will be released from the
+   value chain.  The caller must free the values individually.  If
+   VAL_CHAIN is NULL, all generated values will be left on the value
+   chain.  */
+
+void
+fetch_subexp_value (struct expression *exp, int *pc, struct value **valp,
+		    struct value **resultp, struct value **val_chain)
+{
+  struct value *mark, *new_mark, *result;
+  volatile struct gdb_exception ex;
+
+  *valp = NULL;
+  if (resultp)
+    *resultp = NULL;
+  if (val_chain)
+    *val_chain = NULL;
+
+  /* Evaluate the expression.  */
+  mark = value_mark ();
+  result = NULL;
+
+  TRY_CATCH (ex, RETURN_MASK_ALL)
+    {
+      result = evaluate_subexp (NULL_TYPE, exp, pc, EVAL_NORMAL);
+    }
+  if (ex.reason < 0)
+    {
+      /* Ignore memory errors, we want watchpoints pointing at
+	 inaccessible memory to still be created; otherwise, throw the
+	 error to some higher catcher.  */
+      switch (ex.error)
+	{
+	case MEMORY_ERROR:
+	  break;
+	default:
+	  throw_exception (ex);
+	  break;
+	}
+    }
+
+  new_mark = value_mark ();
+  if (mark == new_mark)
+    return;
+  if (resultp)
+    *resultp = result;
+
+  /* Make sure it's not lazy, so that after the target stops again we
+     have a non-lazy previous value to compare with.  */
+  if (result != NULL
+      && (!value_lazy (result) || gdb_value_fetch_lazy (result)))
+    *valp = result;
+
+  if (val_chain)
+    {
+      /* Return the chain of intermediate values.  We use this to
+	 decide which addresses to watch.  */
+      *val_chain = new_mark;
+      value_release_to_mark (mark);
+    }
+}
+
 /* Extract a field operation from an expression.  If the subexpression
    of EXP starting at *SUBEXP is not a structure dereference
    operation, return NULL.  Otherwise, return the name of the
Index: gdb/i386-nat.c
===================================================================
--- gdb.orig/i386-nat.c	2010-07-01 00:00:32.000000000 -0300
+++ gdb/i386-nat.c	2010-07-01 00:00:56.000000000 -0300
@@ -484,7 +484,8 @@ Invalid value %d of operation in i386_ha
    of the type TYPE.  Return 0 on success, -1 on failure.  */
 
 static int
-i386_insert_watchpoint (CORE_ADDR addr, int len, int type)
+i386_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *cond)
 {
   int retval;
 
@@ -511,7 +512,8 @@ i386_insert_watchpoint (CORE_ADDR addr,
    address ADDR, whose length is LEN bytes, and for accesses of the
    type TYPE.  Return 0 on success, -1 on failure.  */
 static int
-i386_remove_watchpoint (CORE_ADDR addr, int len, int type)
+i386_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *cond)
 {
   int retval;
 
Index: gdb/ia64-linux-nat.c
===================================================================
--- gdb.orig/ia64-linux-nat.c	2010-07-01 00:00:32.000000000 -0300
+++ gdb/ia64-linux-nat.c	2010-07-01 00:00:56.000000000 -0300
@@ -530,7 +530,8 @@ is_power_of_2 (int val)
 }
 
 static int
-ia64_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw)
+ia64_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw,
+			      struct expression *cond)
 {
   struct lwp_info *lp;
   ptid_t ptid;
@@ -584,7 +585,8 @@ ia64_linux_insert_watchpoint (CORE_ADDR
 }
 
 static int
-ia64_linux_remove_watchpoint (CORE_ADDR addr, int len, int type)
+ia64_linux_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			      struct expression *cond)
 {
   int idx;
   long dbr_addr, dbr_mask;
Index: gdb/inf-ttrace.c
===================================================================
--- gdb.orig/inf-ttrace.c	2010-07-01 00:00:32.000000000 -0300
+++ gdb/inf-ttrace.c	2010-07-01 00:00:56.000000000 -0300
@@ -314,7 +314,8 @@ inf_ttrace_disable_page_protections (pid
    type TYPE.  */
 
 static int
-inf_ttrace_insert_watchpoint (CORE_ADDR addr, int len, int type)
+inf_ttrace_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			      struct expression *cond)
 {
   const int pagesize = inf_ttrace_page_dict.pagesize;
   pid_t pid = ptid_get_pid (inferior_ptid);
@@ -337,7 +338,8 @@ inf_ttrace_insert_watchpoint (CORE_ADDR
    type TYPE.  */
 
 static int
-inf_ttrace_remove_watchpoint (CORE_ADDR addr, int len, int type)
+inf_ttrace_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			      struct expression *cond)
 {
   const int pagesize = inf_ttrace_page_dict.pagesize;
   pid_t pid = ptid_get_pid (inferior_ptid);
Index: gdb/mips-linux-nat.c
===================================================================
--- gdb.orig/mips-linux-nat.c	2010-07-01 00:00:32.000000000 -0300
+++ gdb/mips-linux-nat.c	2010-07-01 00:00:56.000000000 -0300
@@ -926,7 +926,8 @@ populate_regs_from_watches (struct pt_wa
    watch.  Return zero on success.  */
 
 static int
-mips_linux_insert_watchpoint (CORE_ADDR addr, int len, int type)
+mips_linux_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			      struct expression *cond)
 {
   struct pt_watch_regs regs;
   struct mips_watchpoint *new_watch;
@@ -975,7 +976,8 @@ mips_linux_insert_watchpoint (CORE_ADDR
    Return zero on success.  */
 
 static int
-mips_linux_remove_watchpoint (CORE_ADDR addr, int len, int type)
+mips_linux_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			      struct expression *cond)
 {
   int retval;
   int deleted_one;
Index: gdb/nto-procfs.c
===================================================================
--- gdb.orig/nto-procfs.c	2010-07-01 00:00:32.000000000 -0300
+++ gdb/nto-procfs.c	2010-07-01 00:00:56.000000000 -0300
@@ -1506,13 +1506,15 @@ procfs_can_use_hw_breakpoint (int type,
 }
 
 static int
-procfs_remove_hw_watchpoint (CORE_ADDR addr, int len, int type)
+procfs_remove_hw_watchpoint (CORE_ADDR addr, int len, int type,
+			     struct expression *cond)
 {
   return procfs_hw_watchpoint (addr, -1, type);
 }
 
 static int
-procfs_insert_hw_watchpoint (CORE_ADDR addr, int len, int type)
+procfs_insert_hw_watchpoint (CORE_ADDR addr, int len, int type,
+			     struct expression *cond)
 {
   return procfs_hw_watchpoint (addr, len, type);
 }
Index: gdb/ppc-linux-nat.c
===================================================================
--- gdb.orig/ppc-linux-nat.c	2010-07-01 00:00:32.000000000 -0300
+++ gdb/ppc-linux-nat.c	2010-07-01 10:50:11.000000000 -0300
@@ -1492,7 +1492,7 @@ ppc_linux_region_ok_for_hw_watchpoint (C
       if (booke_debug_info.data_bp_alignment
 	  && (addr + len > (addr & ~(booke_debug_info.data_bp_alignment - 1))
 	      + booke_debug_info.data_bp_alignment))
-	  return 0;
+	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
@@ -1685,8 +1685,196 @@ get_trigger_type (int rw)
   return t;
 }
 
+/* Check whether we have at least one free DVC register.  */
 static int
-ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw)
+can_use_watchpoint_cond_accel (void)
+{
+  struct thread_points *p;
+  int tid = TIDGET (inferior_ptid);
+  int cnt = booke_debug_info.num_condition_regs, i;
+  CORE_ADDR tmp_value;
+
+  if (!have_ptrace_booke_interface () || cnt == 0)
+    return 0;
+
+  p = booke_find_thread_points_by_tid (tid, 0);
+
+  if (p)
+    {
+      for (i = 0; i < max_slots_number; i++)
+	if (p->hw_breaks[i].hw_break != NULL
+	    && (p->hw_breaks[i].hw_break->condition_mode
+		!= PPC_BREAKPOINT_CONDITION_NONE))
+	  cnt--;
+
+      /* There are no available slots now.  */
+      if (cnt <= 0)
+	return 0;
+    }
+
+  return 1;
+}
+
+/* Calculate the enable bits and the contents of the Data Value Compare
+   debug register present in BookE processors.
+
+   ADDR is the address to be watched, LEN is the length of watched data
+   and DATA_VALUE is the value which will trigger the watchpoint.
+   On exit, CONDITION_MODE will hold the enable bits for the DVC, and
+   CONDITION_VALUE will hold the value which should be put in the
+   DVC register.  */
+static void
+calculate_dvc (CORE_ADDR addr, int len, CORE_ADDR data_value,
+	       uint32_t *condition_mode, uint64_t *condition_value)
+{
+  int i, num_byte_enable, align_offset, num_bytes_off_dvc,
+      rightmost_enabled_byte;
+  CORE_ADDR addr_end_data, addr_end_dvc;
+
+  /* The DVC register compares bytes within fixed-length windows which
+     are word-aligned, with length equal to that of the DVC register.
+     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;
+  addr_end_data = addr + len;
+  addr_end_dvc = (addr - align_offset
+		  + booke_debug_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;
+  /* Here, bytes are numbered from right to left.  */
+  rightmost_enabled_byte = (addr_end_data < addr_end_dvc)?
+			      addr_end_dvc - addr_end_data : 0;
+
+  *condition_mode = PPC_BREAKPOINT_CONDITION_AND;
+  for (i = 0; i < num_byte_enable; i++)
+    *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
+     (i.e., the ALIGN_OFFSET).  */
+
+  *condition_value = ((uint64_t) data_value >> num_bytes_off_dvc * 8
+		      << rightmost_enabled_byte * 8);
+}
+
+/* Return the number of memory locations that need to be accessed to
+   evaluate the expression which generated the given value chain.
+   Returns -1 if there's any register access involved.  */
+static int
+num_memory_accesses (struct value *v)
+{
+  int found_memory_cnt = 0;
+  struct value *head = v;
+
+  /* The idea here is that evaluating an expression generates a series
+     of values, one holding the value of every subexpression.  (The
+     expression a*b+c has five subexpressions: a, b, a*b, c, and
+     a*b+c.)  GDB's values hold almost enough information to establish
+     the criteria given above --- they identify memory lvalues,
+     register lvalues, computed values, etcetera.  So we can evaluate
+     the expression, and then scan the chain of values that leaves
+     behind to determine the memory locations involved in the evaluation
+     of an expression.
+
+     However, I don't think that the values returned by inferior
+     function calls are special in any way.  So this function may not
+     notice that an expression contains an inferior function call.
+     FIXME.  */
+
+  for (; v; v = value_next (v))
+    {
+      if (VALUE_LVAL (v) == lval_memory)
+	{
+	  /* A lazy memory lvalue is one that GDB never needed to fetch;
+	     we either just used its address (e.g., `a' in `a.b') or
+	     we never needed it at all (e.g., `a' in `a,b').  */
+	  if (!value_lazy (v))
+	    found_memory_cnt++;
+	}
+      else if (VALUE_LVAL (v) == lval_register)
+	return -1;	/* Cannot watch a register with a HW watchpoint.  */
+    }
+
+  return found_memory_cnt;
+}
+
+/* Verifies whether the expression COND can be implemented using the
+   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.  */
+static int
+check_condition (CORE_ADDR watch_addr, struct expression *cond,
+		 CORE_ADDR *data_value)
+{
+  int pc = 1, num_accesses_left, num_accesses_right;
+  struct value *left_val, *right_val, *left_chain, *right_chain;
+
+  if (cond->elts[0].opcode != BINOP_EQUAL)
+    return 0;
+
+  fetch_subexp_value (cond, &pc, &left_val, NULL, &left_chain);
+  num_accesses_left = num_memory_accesses (left_chain);
+
+  if (left_val == NULL || num_accesses_left < 0)
+    {
+      free_value_chain (left_chain);
+
+      return 0;
+    }
+
+  fetch_subexp_value (cond, &pc, &right_val, NULL, &right_chain);
+  num_accesses_right = num_memory_accesses (right_chain);
+
+  if (right_val == NULL || num_accesses_right < 0)
+    {
+      free_value_chain (left_chain);
+      free_value_chain (right_chain);
+
+      return 0;
+    }
+
+  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);
+  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);
+  else
+    {
+      free_value_chain (left_chain);
+      free_value_chain (right_chain);
+
+      return 0;
+    }
+
+  free_value_chain (left_chain);
+  free_value_chain (right_chain);
+
+  return 1;
+}
+
+/* Return non-zero if the target is capable of using hardware to evaluate
+   the condition expression, thus only triggering the watchpoint when it is
+   true.  */
+static int
+ppc_linux_can_accel_watchpoint_condition (CORE_ADDR addr, int len, int rw,
+					  struct expression *cond)
+{
+  CORE_ADDR data_value;
+
+  return (have_ptrace_booke_interface ()
+	  && booke_debug_info.num_condition_regs > 0
+	  && check_condition (addr, cond, &data_value));
+}
+
+static int
+ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw,
+			     struct expression *cond)
 {
   struct lwp_info *lp;
   ptid_t ptid;
@@ -1695,14 +1883,23 @@ ppc_linux_insert_watchpoint (CORE_ADDR a
   if (have_ptrace_booke_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.condition_mode  = PPC_BREAKPOINT_CONDITION_NONE;
       p.addr            = (uint64_t) addr;
       p.addr2           = 0;
-      p.condition_value = 0;
 
       ALL_LWPS (lp, ptid)
 	booke_insert_point (&p, TIDGET (ptid));
@@ -1749,7 +1946,8 @@ ppc_linux_insert_watchpoint (CORE_ADDR a
       saved_dabr_value = dabr_value;
 
       ALL_LWPS (lp, ptid)
-	if (ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0, saved_dabr_value) < 0)
+	if (ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0,
+		    saved_dabr_value) < 0)
 	  return -1;
 
       ret = 0;
@@ -1759,7 +1957,8 @@ ppc_linux_insert_watchpoint (CORE_ADDR a
 }
 
 static int
-ppc_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw)
+ppc_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw,
+			     struct expression *cond)
 {
   struct lwp_info *lp;
   ptid_t ptid;
@@ -1768,14 +1967,23 @@ ppc_linux_remove_watchpoint (CORE_ADDR a
   if (have_ptrace_booke_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.condition_mode  = PPC_BREAKPOINT_CONDITION_NONE;
       p.addr            = (uint64_t) addr;
       p.addr2           = 0;
-      p.condition_value = 0;
 
       ALL_LWPS (lp, ptid)
 	booke_remove_point (&p, TIDGET (ptid));
@@ -1786,7 +1994,8 @@ ppc_linux_remove_watchpoint (CORE_ADDR a
     {
       saved_dabr_value = 0;
       ALL_LWPS (lp, ptid)
-	if (ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0, saved_dabr_value) < 0)
+	if (ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0,
+		    saved_dabr_value) < 0)
 	  return -1;
 
       ret = 0;
@@ -2137,6 +2346,7 @@ _initialize_ppc_linux_nat (void)
   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_read_description = ppc_linux_read_description;
   t->to_auxv_parse = ppc_linux_auxv_parse;
Index: gdb/procfs.c
===================================================================
--- gdb.orig/procfs.c	2010-07-01 00:00:32.000000000 -0300
+++ gdb/procfs.c	2010-07-01 00:00:56.000000000 -0300
@@ -5161,7 +5161,8 @@ procfs_stopped_data_address (struct targ
 }
 
 static int
-procfs_insert_watchpoint (CORE_ADDR addr, int len, int type)
+procfs_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			  struct expression *cond)
 {
   if (!target_have_steppable_watchpoint
       && !gdbarch_have_nonsteppable_watchpoint (target_gdbarch))
@@ -5182,7 +5183,8 @@ procfs_insert_watchpoint (CORE_ADDR addr
 }
 
 static int
-procfs_remove_watchpoint (CORE_ADDR addr, int len, int type)
+procfs_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			  struct expression *cond)
 {
   return procfs_set_watchpoint (inferior_ptid, addr, 0, 0, 0);
 }
Index: gdb/remote-m32r-sdi.c
===================================================================
--- gdb.orig/remote-m32r-sdi.c	2010-07-01 00:00:32.000000000 -0300
+++ gdb/remote-m32r-sdi.c	2010-07-01 00:00:56.000000000 -0300
@@ -1421,7 +1421,8 @@ m32r_can_use_hw_watchpoint (int type, in
    watchpoint. */
 
 static int
-m32r_insert_watchpoint (CORE_ADDR addr, int len, int type)
+m32r_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *cond)
 {
   int i;
 
@@ -1445,7 +1446,8 @@ m32r_insert_watchpoint (CORE_ADDR addr,
 }
 
 static int
-m32r_remove_watchpoint (CORE_ADDR addr, int len, int type)
+m32r_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *cond)
 {
   int i;
 
Index: gdb/remote-mips.c
===================================================================
--- gdb.orig/remote-mips.c	2010-07-01 00:00:32.000000000 -0300
+++ gdb/remote-mips.c	2010-07-01 00:00:56.000000000 -0300
@@ -2401,7 +2401,8 @@ calculate_mask (CORE_ADDR addr, int len)
    watchpoint. */
 
 int
-mips_insert_watchpoint (CORE_ADDR addr, int len, int type)
+mips_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *cond)
 {
   if (mips_set_breakpoint (addr, len, type))
     return -1;
@@ -2412,7 +2413,8 @@ mips_insert_watchpoint (CORE_ADDR addr,
 /* Remove a watchpoint.  */
 
 int
-mips_remove_watchpoint (CORE_ADDR addr, int len, int type)
+mips_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *cond)
 {
   if (mips_clear_breakpoint (addr, len, type))
     return -1;
Index: gdb/remote.c
===================================================================
--- gdb.orig/remote.c	2010-07-01 00:00:32.000000000 -0300
+++ gdb/remote.c	2010-07-01 00:00:56.000000000 -0300
@@ -7537,7 +7537,8 @@ watchpoint_to_Z_packet (int type)
 }
 
 static int
-remote_insert_watchpoint (CORE_ADDR addr, int len, int type)
+remote_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			  struct expression *cond)
 {
   struct remote_state *rs = get_remote_state ();
   char *p;
@@ -7570,7 +7571,8 @@ remote_insert_watchpoint (CORE_ADDR addr
 
 
 static int
-remote_remove_watchpoint (CORE_ADDR addr, int len, int type)
+remote_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			  struct expression *cond)
 {
   struct remote_state *rs = get_remote_state ();
   char *p;
Index: gdb/s390-nat.c
===================================================================
--- gdb.orig/s390-nat.c	2010-07-01 00:00:32.000000000 -0300
+++ gdb/s390-nat.c	2010-07-01 00:00:56.000000000 -0300
@@ -335,7 +335,8 @@ s390_fix_watch_points (ptid_t ptid)
 }
 
 static int
-s390_insert_watchpoint (CORE_ADDR addr, int len, int type)
+s390_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *cond)
 {
   struct lwp_info *lp;
   ptid_t ptid;
@@ -356,7 +357,8 @@ s390_insert_watchpoint (CORE_ADDR addr,
 }
 
 static int
-s390_remove_watchpoint (CORE_ADDR addr, int len, int type)
+s390_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *cond)
 {
   struct lwp_info *lp;
   ptid_t ptid;
Index: gdb/target.c
===================================================================
--- gdb.orig/target.c	2010-07-01 00:00:32.000000000 -0300
+++ gdb/target.c	2010-07-01 00:00:56.000000000 -0300
@@ -117,9 +117,11 @@ static int debug_to_insert_hw_breakpoint
 static int debug_to_remove_hw_breakpoint (struct gdbarch *,
 					  struct bp_target_info *);
 
-static int debug_to_insert_watchpoint (CORE_ADDR, int, int);
+static int debug_to_insert_watchpoint (CORE_ADDR, int, int,
+				       struct expression *);
 
-static int debug_to_remove_watchpoint (CORE_ADDR, int, int);
+static int debug_to_remove_watchpoint (CORE_ADDR, int, int,
+				       struct expression *);
 
 static int debug_to_stopped_by_watchpoint (void);
 
@@ -130,6 +132,9 @@ static int debug_to_watchpoint_addr_with
 
 static int debug_to_region_ok_for_hw_watchpoint (CORE_ADDR, int);
 
+static int debug_to_can_accel_watchpoint_condition (CORE_ADDR, int, int,
+						    struct expression *);
+
 static void debug_to_terminal_init (void);
 
 static void debug_to_terminal_inferior (void);
@@ -607,6 +612,7 @@ update_current_target (void)
       INHERIT (to_stopped_by_watchpoint, t);
       INHERIT (to_watchpoint_addr_within_range, t);
       INHERIT (to_region_ok_for_hw_watchpoint, t);
+      INHERIT (to_can_accel_watchpoint_condition, t);
       INHERIT (to_terminal_init, t);
       INHERIT (to_terminal_inferior, t);
       INHERIT (to_terminal_ours_for_output, t);
@@ -726,10 +732,10 @@ update_current_target (void)
 	    (int (*) (struct gdbarch *, struct bp_target_info *))
 	    return_minus_one);
   de_fault (to_insert_watchpoint,
-	    (int (*) (CORE_ADDR, int, int))
+	    (int (*) (CORE_ADDR, int, int, struct expression *))
 	    return_minus_one);
   de_fault (to_remove_watchpoint,
-	    (int (*) (CORE_ADDR, int, int))
+	    (int (*) (CORE_ADDR, int, int, struct expression *))
 	    return_minus_one);
   de_fault (to_stopped_by_watchpoint,
 	    (int (*) (void))
@@ -741,6 +747,9 @@ 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_can_accel_watchpoint_condition,
+            (int (*) (CORE_ADDR, int, int, struct expression *))
+            return_zero);
   de_fault (to_terminal_init,
 	    (void (*) (void))
 	    target_ignore);
@@ -3306,6 +3315,21 @@ debug_to_region_ok_for_hw_watchpoint (CO
 }
 
 static int
+debug_to_can_accel_watchpoint_condition (CORE_ADDR addr, int len, int rw,
+					 struct expression *cond)
+{
+  int retval;
+
+  retval = debug_target.to_can_accel_watchpoint_condition (addr, len, rw, cond);
+
+  fprintf_unfiltered (gdb_stdlog,
+		      "target_can_accel_watchpoint_condition (0x%lx, %d, %d, 0x%lx) = %ld\n",
+		      (unsigned long) addr, len, rw, (unsigned long) cond,
+		      (unsigned long) retval);
+  return retval;
+}
+
+static int
 debug_to_stopped_by_watchpoint (void)
 {
   int retval;
@@ -3380,28 +3404,32 @@ debug_to_remove_hw_breakpoint (struct gd
 }
 
 static int
-debug_to_insert_watchpoint (CORE_ADDR addr, int len, int type)
+debug_to_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			    struct expression *cond)
 {
   int retval;
 
-  retval = debug_target.to_insert_watchpoint (addr, len, type);
+  retval = debug_target.to_insert_watchpoint (addr, len, type, cond);
 
   fprintf_unfiltered (gdb_stdlog,
-		      "target_insert_watchpoint (0x%lx, %d, %d) = %ld\n",
-		      (unsigned long) addr, len, type, (unsigned long) retval);
+		      "target_insert_watchpoint (0x%lx, %d, %d, 0x%ld) = %ld\n",
+		      (unsigned long) addr, len, type, (unsigned long) cond,
+		      (unsigned long) retval);
   return retval;
 }
 
 static int
-debug_to_remove_watchpoint (CORE_ADDR addr, int len, int type)
+debug_to_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			    struct expression *cond)
 {
   int retval;
 
-  retval = debug_target.to_remove_watchpoint (addr, len, type);
+  retval = debug_target.to_remove_watchpoint (addr, len, type, cond);
 
   fprintf_unfiltered (gdb_stdlog,
-		      "target_remove_watchpoint (0x%lx, %d, %d) = %ld\n",
-		      (unsigned long) addr, len, type, (unsigned long) retval);
+		      "target_remove_watchpoint (0x%lx, %d, %d, 0x%ld) = %ld\n",
+		      (unsigned long) addr, len, type, (unsigned long) cond,
+		      (unsigned long) retval);
   return retval;
 }
 
@@ -3656,6 +3684,7 @@ setup_target_debug (void)
   current_target.to_stopped_data_address = debug_to_stopped_data_address;
   current_target.to_watchpoint_addr_within_range = debug_to_watchpoint_addr_within_range;
   current_target.to_region_ok_for_hw_watchpoint = debug_to_region_ok_for_hw_watchpoint;
+  current_target.to_can_accel_watchpoint_condition = debug_to_can_accel_watchpoint_condition;
   current_target.to_terminal_init = debug_to_terminal_init;
   current_target.to_terminal_inferior = debug_to_terminal_inferior;
   current_target.to_terminal_ours_for_output = debug_to_terminal_ours_for_output;
Index: gdb/target.h
===================================================================
--- gdb.orig/target.h	2010-07-01 00:00:32.000000000 -0300
+++ gdb/target.h	2010-07-01 00:00:56.000000000 -0300
@@ -36,6 +36,8 @@ struct trace_status;
 struct uploaded_tsv;
 struct uploaded_tp;
 
+struct expression;
+
 /* 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
@@ -420,8 +422,12 @@ struct target_ops
     int (*to_can_use_hw_breakpoint) (int, int, int);
     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);
+
+    /* Documentation of what the two routines below are expected to do is
+       provided with the corresponding target_* macros.  */
+    int (*to_remove_watchpoint) (CORE_ADDR, int, int, struct expression *);
+    int (*to_insert_watchpoint) (CORE_ADDR, int, int, struct expression *);
+
     int (*to_stopped_by_watchpoint) (void);
     int to_have_steppable_watchpoint;
     int to_have_continuable_watchpoint;
@@ -429,6 +435,8 @@ struct target_ops
     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_can_accel_watchpoint_condition) (CORE_ADDR, int, int,
+					      struct expression *);
     void (*to_terminal_init) (void);
     void (*to_terminal_inferior) (void);
     void (*to_terminal_ours_for_output) (void);
@@ -1282,14 +1290,15 @@ extern char *normal_pid_to_str (ptid_t p
 
 /* 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.
+   COND is the expression for its condition, or NULL if there's none.
    Returns 0 for success, 1 if the watchpoint type is not supported,
    -1 for failure.  */
 
-#define	target_insert_watchpoint(addr, len, type)	\
-     (*current_target.to_insert_watchpoint) (addr, len, type)
+#define	target_insert_watchpoint(addr, len, type, cond) \
+     (*current_target.to_insert_watchpoint) (addr, len, type, cond)
 
-#define	target_remove_watchpoint(addr, len, type)	\
-     (*current_target.to_remove_watchpoint) (addr, len, type)
+#define	target_remove_watchpoint(addr, len, type, cond) \
+     (*current_target.to_remove_watchpoint) (addr, len, type, cond)
 
 #define target_insert_hw_breakpoint(gdbarch, bp_tgt) \
      (*current_target.to_insert_hw_breakpoint) (gdbarch, bp_tgt)
@@ -1306,6 +1315,19 @@ extern char *normal_pid_to_str (ptid_t p
 #define target_watchpoint_addr_within_range(target, addr, start, length) \
   (*target.to_watchpoint_addr_within_range) (target, addr, start, length)
 
+/* Return non-zero if the target is capable of using hardware to evaluate
+   the condition expression.  In this case, if the condition is false when
+   the watched memory location changes, execution may continue without the
+   debugger being notified.
+
+   Due to limitations in the hardware implementation, it may be capable of
+   avoiding triggering the watchpoint in some cases where the condition
+   expression is false, but may report some false positives as well.
+   For this reason, GDB will still evaluate the condition expression when
+   the watchpoint triggers.  */
+#define target_can_accel_watchpoint_condition(addr, len, type, cond) \
+  (*current_target.to_can_accel_watchpoint_condition) (addr, len, type, cond)
+
 /* Target can execute in reverse?  */
 #define target_can_execute_reverse \
      (current_target.to_can_execute_reverse ? \
Index: gdb/value.c
===================================================================
--- gdb.orig/value.c	2010-07-01 00:00:32.000000000 -0300
+++ gdb/value.c	2010-07-01 00:00:56.000000000 -0300
@@ -722,6 +722,20 @@ free_all_values (void)
   all_values = 0;
 }
 
+/* Frees all the elements in a chain of values.  */
+
+void
+free_value_chain (struct value *v)
+{
+  struct value *next;
+
+  for (; v; v = next)
+    {
+      next = value_next (v);
+      value_free (v);
+    }
+}
+
 /* Remove VAL from the chain all_values
    so it will not be freed automatically.  */
 
Index: gdb/value.h
===================================================================
--- gdb.orig/value.h	2010-07-01 00:00:32.000000000 -0300
+++ gdb/value.h	2010-07-01 00:00:56.000000000 -0300
@@ -538,6 +538,10 @@ extern struct value *evaluate_subexp (st
 extern struct value *evaluate_subexpression_type (struct expression *exp,
 						  int subexp);
 
+extern void fetch_subexp_value (struct expression *exp, int *pc,
+				struct value **valp, struct value **resultp,
+				struct value **val_chain);
+
 extern char *extract_field_op (struct expression *exp, int *subexp);
 
 extern struct value *evaluate_subexp_with_coercion (struct expression *,
@@ -635,6 +639,8 @@ extern void value_free (struct value *va
 
 extern void free_all_values (void);
 
+extern void free_value_chain (struct value *v);
+
 extern void release_value (struct value *val);
 
 extern int record_latest_value (struct value *val);

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 2/4] Hardware accelerated watchpoint conditions
  2010-07-01 14:51                     ` Thiago Jung Bauermann
@ 2010-07-02 13:20                       ` Ulrich Weigand
  2010-07-06 22:22                         ` Thiago Jung Bauermann
  0 siblings, 1 reply; 17+ messages in thread
From: Ulrich Weigand @ 2010-07-02 13:20 UTC (permalink / raw)
  To: Thiago Jung Bauermann
  Cc: Joel Brobecker, gdb-patches, Luis Machado, Matt Tyrlik

Thiago Jung Bauermann wrote:

> I changed the comment to read:
> 
> /* Return non-zero if the target is capable of using hardware to evaluate
>    the condition expression.  In this case, if the condition is false when
>    the watched memory location changes, execution may continue without the
>    debugger being notified.
> 
>    Due to limitations in the hardware implementation, it may be capable of
>    avoiding triggering the watchpoint in some cases where the condition
>    expression is false, but may report some false positives as well.
>    For this reason, GDB will still evaluate the condition expression when
>    the watchpoint triggers.  */
> 
> What do you think?

Looks good to me.

> > > +  for (; v; v = value_next (v))
> > > +    {
> > > +      if (VALUE_LVAL (v) == lval_memory)
> > > +	{
> > > +	  /* A lazy memory lvalue is one that GDB never needed to fetch;
> > > +	     we either just used its address (e.g., `a' in `a.b') or
> > > +	     we never needed it at all (e.g., `a' in `a,b').  */
> > > +	  if (!value_lazy (v))
> > > +	    found_memory_cnt++;
> > > +	}
> > > +      else if (VALUE_LVAL (v) != not_lval
> > > +	       && deprecated_value_modifiable (v) == 0)
> > > +	return -1;	/* ??? What does this represent? */
> > 
> > These are values from the history (e.g. $1).  In this context, they
> > should be treated as non-lvalues, so they should be fine ...
> 
> I removed that else if then. I'll submit a separate patch to replace
> that comment in can_use_hardware_watchpoint.

Actually, thinking about this a bit more, the logic still does not
seem quite correct.  What we really want is:

- not_lval values: these are fine
- deprecated_value_modifiable (v) == 0 (history) values: treat just
  like not_lval, no matter what their VALUE_LVAL says
- lval_memory values: check whether they are lazy or not and count them
- all other values (lval_computed, lval_internalvar ...): *not* OK

In particular, the missing check on lval_computed may become more important
now that DWARF multi-piece values are always represented as lval_computed ...
(This may also affect watchpoint code in breakpoint.c, but I guess that's
a different issue.)

> 2010-07-01  Sergio Durigan Junior  <sergiodj@linux.vnet.ibm.com>
> 	    Thiago Jung Bauermann  <bauerman@br.ibm.com>
> 
> 	* breakpoint.c (fetch_watchpoint_value): Rename to fetch_subexp_value
> 	and move to eval.c.  Change callers.
> 	(insert_bp_location): Pass watchpoint condition in
> 	target_insert_watchpoint.
> 	(remove_breakpoint_1) Pass watchpoint condition in
> 	target_remove_watchpoint.
> 	(watchpoint_locations_match): Call
> 	target_can_accel_watchpoint_condition.
> 	* eval.c: Include wrapper.h.
> 	(fetch_subexp_value): Moved from breakpoint.c.
> 	* ppc-linux-nat.c (ppc_linux_region_ok_for_hw_watchpoint):
> 	Formatting fix.
> 	(can_use_watchpoint_cond_accel): New function.
> 	(calculate_dvc): Likewise.
> 	(num_memory_accesses): Likewise.
> 	(check_condition): Likewise.
> 	(ppc_linux_can_accel_watchpoint_condition): Likewise
> 	(ppc_linux_insert_watchpoint): Call can_use_watchpoint_cond_accel,
> 	check_condition and calculate_dvc.
> 	(ppc_linux_remove_watchpoint): Likewise.
> 	(_initialize_ppc_linux_nat): Set to_can_accel_watchpoint_condition to
> 	ppc_linux_can_accel_watchpoint_condition
> 	* target.c (debug_to_insert_watchpoint): Add argument for watchpoint
> 	condition.
> 	(debug_to_remove_watchpoint): Likewise.
> 	(debug_to_can_accel_watchpoint_condition): New function.
> 	(update_current_target): Set to_can_accel_watchpoint_condition.
> 	(setup_target_debug): Set to_can_accel_watchpoint_condition.
> 	* target.h: Add opaque declaration for struct expression.
> 	(struct target_ops) <to_insert_watchpoint>,
> 	<to_remove_watchpoint>: Add new arguments to pass the watchpoint
> 	<to_can_accel_watchpoint_condition>: New member.
> 	condition.  Update all callers and implementations.
> 	(target_can_accel_watchpoint_condition): New macro.
> 	* value.c (free_value_chain): New function.
> 	* value.h (fetch_subexp_value): New prototype.
> 	(free_value_chain): Likewise.

Except for the num_memory_accesses logic discussed above, the patch
is otherwise OK now.

Thanks,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 2/4] Hardware accelerated watchpoint conditions
  2010-07-02 13:20                       ` Ulrich Weigand
@ 2010-07-06 22:22                         ` Thiago Jung Bauermann
  2010-07-07 12:25                           ` Ulrich Weigand
  0 siblings, 1 reply; 17+ messages in thread
From: Thiago Jung Bauermann @ 2010-07-06 22:22 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: Joel Brobecker, gdb-patches, Luis Machado, Matt Tyrlik

[-- Attachment #1: Type: text/plain, Size: 4324 bytes --]

On Fri, 2010-07-02 at 15:19 +0200, Ulrich Weigand wrote:
> Thiago Jung Bauermann wrote:
> > > > +  for (; v; v = value_next (v))
> > > > +    {
> > > > +      if (VALUE_LVAL (v) == lval_memory)
> > > > +	{
> > > > +	  /* A lazy memory lvalue is one that GDB never needed to fetch;
> > > > +	     we either just used its address (e.g., `a' in `a.b') or
> > > > +	     we never needed it at all (e.g., `a' in `a,b').  */
> > > > +	  if (!value_lazy (v))
> > > > +	    found_memory_cnt++;
> > > > +	}
> > > > +      else if (VALUE_LVAL (v) != not_lval
> > > > +	       && deprecated_value_modifiable (v) == 0)
> > > > +	return -1;	/* ??? What does this represent? */
> > > 
> > > These are values from the history (e.g. $1).  In this context, they
> > > should be treated as non-lvalues, so they should be fine ...
> > 
> > I removed that else if then. I'll submit a separate patch to replace
> > that comment in can_use_hardware_watchpoint.
> 
> Actually, thinking about this a bit more, the logic still does not
> seem quite correct.  What we really want is:
> 
> - not_lval values: these are fine
> - deprecated_value_modifiable (v) == 0 (history) values: treat just
>   like not_lval, no matter what their VALUE_LVAL says
> - lval_memory values: check whether they are lazy or not and count them
> - all other values (lval_computed, lval_internalvar ...): *not* OK
> 
> In particular, the missing check on lval_computed may become more important
> now that DWARF multi-piece values are always represented as lval_computed ...
> (This may also affect watchpoint code in breakpoint.c, but I guess that's
> a different issue.)

Ok, makes sense. That loop now reads:

  for (; v; v = value_next (v))
    {
      /* Constants and values from the history are fine.  */
      if (VALUE_LVAL (v) == not_lval || deprecated_value_modifiable (v) == 0)
        continue;
      else if (VALUE_LVAL (v) == lval_memory)
        {
          /* A lazy memory lvalue is one that GDB never needed to fetch;
             we either just used its address (e.g., `a' in `a.b') or
             we never needed it at all (e.g., `a' in `a,b').  */
          if (!value_lazy (v))
            found_memory_cnt++;
        }
      /* Other kinds of values are not fine. */
      else
        return -1;
    }

> Except for the num_memory_accesses logic discussed above, the patch
> is otherwise OK now.

Great! Except for the change in the loop above, the rest of the patch is
the same.

Thanks for your help with this work.


2010-07-06  Sergio Durigan Junior  <sergiodj@linux.vnet.ibm.com>
	    Thiago Jung Bauermann  <bauerman@br.ibm.com>

	* breakpoint.c (fetch_watchpoint_value): Rename to fetch_subexp_value
	and move to eval.c.  Change callers.
	(insert_bp_location): Pass watchpoint condition in
	target_insert_watchpoint.
	(remove_breakpoint_1) Pass watchpoint condition in
	target_remove_watchpoint.
	(watchpoint_locations_match): Call
	target_can_accel_watchpoint_condition.
	* eval.c: Include wrapper.h.
	(fetch_subexp_value): Moved from breakpoint.c.
	* ppc-linux-nat.c (ppc_linux_region_ok_for_hw_watchpoint):
	Formatting fix.
	(can_use_watchpoint_cond_accel): New function.
	(calculate_dvc): Likewise.
	(num_memory_accesses): Likewise.
	(check_condition): Likewise.
	(ppc_linux_can_accel_watchpoint_condition): Likewise
	(ppc_linux_insert_watchpoint): Call can_use_watchpoint_cond_accel,
	check_condition and calculate_dvc.
	(ppc_linux_remove_watchpoint): Likewise.
	(_initialize_ppc_linux_nat): Set to_can_accel_watchpoint_condition to
	ppc_linux_can_accel_watchpoint_condition
	* target.c (debug_to_insert_watchpoint): Add argument for watchpoint
	condition.
	(debug_to_remove_watchpoint): Likewise.
	(debug_to_can_accel_watchpoint_condition): New function.
	(update_current_target): Set to_can_accel_watchpoint_condition.
	(setup_target_debug): Set to_can_accel_watchpoint_condition.
	* target.h: Add opaque declaration for struct expression.
	(struct target_ops) <to_insert_watchpoint>,
	<to_remove_watchpoint>: Add new arguments to pass the watchpoint
	<to_can_accel_watchpoint_condition>: New member.
	condition.  Update all callers and implementations.
	(target_can_accel_watchpoint_condition): New macro.
	* value.c (free_value_chain): New function.
	* value.h (fetch_subexp_value): New prototype.
	(free_value_chain): Likewise.


[-- Attachment #2: condition.diff --]
[-- Type: text/x-patch, Size: 39207 bytes --]

Index: gdb/breakpoint.c
===================================================================
--- gdb.orig/breakpoint.c	2010-07-06 19:05:12.000000000 -0300
+++ gdb/breakpoint.c	2010-07-06 19:07:53.000000000 -0300
@@ -1234,84 +1234,6 @@ is_watchpoint (const struct breakpoint *
 	  || bpt->type == bp_watchpoint);
 }
 
-/* Find the current value of a watchpoint on EXP.  Return the value in
-   *VALP and *RESULTP and the chain of intermediate and final values
-   in *VAL_CHAIN.  RESULTP and VAL_CHAIN may be NULL if the caller does
-   not need them.
-
-   If a memory error occurs while evaluating the expression, *RESULTP will
-   be set to NULL.  *RESULTP may be a lazy value, if the result could
-   not be read from memory.  It is used to determine whether a value
-   is user-specified (we should watch the whole value) or intermediate
-   (we should watch only the bit used to locate the final value).
-
-   If the final value, or any intermediate value, could not be read
-   from memory, *VALP will be set to NULL.  *VAL_CHAIN will still be
-   set to any referenced values.  *VALP will never be a lazy value.
-   This is the value which we store in struct breakpoint.
-
-   If VAL_CHAIN is non-NULL, *VAL_CHAIN will be released from the
-   value chain.  The caller must free the values individually.  If
-   VAL_CHAIN is NULL, all generated values will be left on the value
-   chain.  */
-
-static void
-fetch_watchpoint_value (struct expression *exp, struct value **valp,
-			struct value **resultp, struct value **val_chain)
-{
-  struct value *mark, *new_mark, *result;
-  volatile struct gdb_exception ex;
-
-  *valp = NULL;
-  if (resultp)
-    *resultp = NULL;
-  if (val_chain)
-    *val_chain = NULL;
-
-  /* Evaluate the expression.  */
-  mark = value_mark ();
-  result = NULL;
-
-  TRY_CATCH (ex, RETURN_MASK_ALL)
-    {
-      result = evaluate_expression (exp);
-    }
-  if (ex.reason < 0)
-    {
-      /* Ignore memory errors, we want watchpoints pointing at
-	 inaccessible memory to still be created; otherwise, throw the
-	 error to some higher catcher.  */
-      switch (ex.error)
-	{
-	case MEMORY_ERROR:
-	  break;
-	default:
-	  throw_exception (ex);
-	  break;
-	}
-    }
-
-  new_mark = value_mark ();
-  if (mark == new_mark)
-    return;
-  if (resultp)
-    *resultp = result;
-
-  /* Make sure it's not lazy, so that after the target stops again we
-     have a non-lazy previous value to compare with.  */
-  if (result != NULL
-      && (!value_lazy (result) || gdb_value_fetch_lazy (result)))
-    *valp = result;
-
-  if (val_chain)
-    {
-      /* Return the chain of intermediate values.  We use this to
-	 decide which addresses to watch.  */
-      *val_chain = new_mark;
-      value_release_to_mark (mark);
-    }
-}
-
 /* Assuming that B is a watchpoint: returns true if the current thread
    and its running state are safe to evaluate or update watchpoint B.
    Watchpoints on local expressions need to be evaluated in the
@@ -1469,10 +1391,11 @@ update_watchpoint (struct breakpoint *b,
     }
   else if (within_current_scope && b->exp)
     {
+      int pc = 0;
       struct value *val_chain, *v, *result, *next;
       struct program_space *frame_pspace;
 
-      fetch_watchpoint_value (b->exp, &v, &result, &val_chain);
+      fetch_subexp_value (b->exp, &pc, &v, &result, &val_chain);
 
       /* Avoid setting b->val if it's already set.  The meaning of
 	 b->val is 'the last value' user saw, and we should update
@@ -1828,7 +1751,8 @@ Note: automatically using hardware break
     {
       val = target_insert_watchpoint (bpt->address,
 				      bpt->length,
-				      bpt->watchpoint_type);
+				      bpt->watchpoint_type,
+				      bpt->owner->cond_exp);
 
       /* If trying to set a read-watchpoint, and it turns out it's not
 	 supported, try emulating one with an access watchpoint.  */
@@ -1856,7 +1780,8 @@ Note: automatically using hardware break
 	    {
 	      val = target_insert_watchpoint (bpt->address,
 					      bpt->length,
-					      hw_access);
+					      hw_access,
+					      bpt->owner->cond_exp);
 	      if (val == 0)
 		bpt->watchpoint_type = hw_access;
 	    }
@@ -2525,8 +2450,8 @@ remove_breakpoint_1 (struct bp_location 
   else if (b->loc_type == bp_loc_hardware_watchpoint)
     {
       b->inserted = (is == mark_inserted);
-      val = target_remove_watchpoint (b->address, b->length, 
-				      b->watchpoint_type);
+      val = target_remove_watchpoint (b->address, b->length,
+				      b->watchpoint_type, b->owner->cond_exp);
 
       /* Failure to remove any of the hardware watchpoints comes here.  */
       if ((is == mark_uninserted) && (b->inserted))
@@ -3679,10 +3604,11 @@ watchpoint_check (void *p)
          call free_all_values.  We can't call free_all_values because
          we might be in the middle of evaluating a function call.  */
 
+      int pc = 0;
       struct value *mark = value_mark ();
       struct value *new_val;
 
-      fetch_watchpoint_value (b->exp, &new_val, NULL, NULL);
+      fetch_subexp_value (b->exp, &pc, &new_val, NULL, NULL);
 
       /* We use value_equal_contents instead of value_equal because the latter
 	 coerces an array to a pointer, thus comparing just the address of the
@@ -5262,6 +5188,21 @@ watchpoint_locations_match (struct bp_lo
   gdb_assert (loc1->owner != NULL);
   gdb_assert (loc2->owner != NULL);
 
+  /* If the target can evaluate the condition expression in hardware, then we
+     we need to insert both watchpoints even if they are at the same place.
+     Otherwise the watchpoint will only trigger when the condition of whichever
+     watchpoint was inserted evaluates to true, not giving a chance for GDB to
+     check the condition of the other watchpoint.  */
+  if ((loc1->owner->cond_exp
+       && target_can_accel_watchpoint_condition (loc1->address, loc1->length,
+						 loc1->watchpoint_type,
+						 loc1->owner->cond_exp))
+      || (loc2->owner->cond_exp
+	  && target_can_accel_watchpoint_condition (loc2->address, loc2->length,
+						    loc2->watchpoint_type,
+						    loc2->owner->cond_exp)))
+    return 0;
+
   /* Note that this checks the owner's type, not the location's.  In
      case the target does not support read watchpoints, but does
      support access watchpoints, we'll have bp_read_watchpoint
@@ -8057,6 +7998,7 @@ watch_command_1 (char *arg, int accessfl
   enum bptype bp_type;
   int mem_cnt = 0;
   int thread = -1;
+  int pc = 0;
 
   /* Make sure that we actually have parameters to parse.  */
   if (arg != NULL && arg[0] != '\0')
@@ -8143,7 +8085,7 @@ watch_command_1 (char *arg, int accessfl
 
   exp_valid_block = innermost_block;
   mark = value_mark ();
-  fetch_watchpoint_value (exp, &val, NULL, NULL);
+  fetch_subexp_value (exp, &pc, &val, NULL, NULL);
   if (val != NULL)
     release_value (val);
 
Index: gdb/eval.c
===================================================================
--- gdb.orig/eval.c	2010-07-02 17:03:03.000000000 -0300
+++ gdb/eval.c	2010-07-06 19:07:53.000000000 -0300
@@ -43,6 +43,7 @@
 #include "gdb_obstack.h"
 #include "objfiles.h"
 #include "python/python.h"
+#include "wrapper.h"
 
 #include "gdb_assert.h"
 
@@ -186,6 +187,84 @@ evaluate_subexpression_type (struct expr
   return evaluate_subexp (NULL_TYPE, exp, &subexp, EVAL_AVOID_SIDE_EFFECTS);
 }
 
+/* Find the current value of a watchpoint on EXP.  Return the value in
+   *VALP and *RESULTP and the chain of intermediate and final values
+   in *VAL_CHAIN.  RESULTP and VAL_CHAIN may be NULL if the caller does
+   not need them.
+
+   If a memory error occurs while evaluating the expression, *RESULTP will
+   be set to NULL.  *RESULTP may be a lazy value, if the result could
+   not be read from memory.  It is used to determine whether a value
+   is user-specified (we should watch the whole value) or intermediate
+   (we should watch only the bit used to locate the final value).
+
+   If the final value, or any intermediate value, could not be read
+   from memory, *VALP will be set to NULL.  *VAL_CHAIN will still be
+   set to any referenced values.  *VALP will never be a lazy value.
+   This is the value which we store in struct breakpoint.
+
+   If VAL_CHAIN is non-NULL, *VAL_CHAIN will be released from the
+   value chain.  The caller must free the values individually.  If
+   VAL_CHAIN is NULL, all generated values will be left on the value
+   chain.  */
+
+void
+fetch_subexp_value (struct expression *exp, int *pc, struct value **valp,
+		    struct value **resultp, struct value **val_chain)
+{
+  struct value *mark, *new_mark, *result;
+  volatile struct gdb_exception ex;
+
+  *valp = NULL;
+  if (resultp)
+    *resultp = NULL;
+  if (val_chain)
+    *val_chain = NULL;
+
+  /* Evaluate the expression.  */
+  mark = value_mark ();
+  result = NULL;
+
+  TRY_CATCH (ex, RETURN_MASK_ALL)
+    {
+      result = evaluate_subexp (NULL_TYPE, exp, pc, EVAL_NORMAL);
+    }
+  if (ex.reason < 0)
+    {
+      /* Ignore memory errors, we want watchpoints pointing at
+	 inaccessible memory to still be created; otherwise, throw the
+	 error to some higher catcher.  */
+      switch (ex.error)
+	{
+	case MEMORY_ERROR:
+	  break;
+	default:
+	  throw_exception (ex);
+	  break;
+	}
+    }
+
+  new_mark = value_mark ();
+  if (mark == new_mark)
+    return;
+  if (resultp)
+    *resultp = result;
+
+  /* Make sure it's not lazy, so that after the target stops again we
+     have a non-lazy previous value to compare with.  */
+  if (result != NULL
+      && (!value_lazy (result) || gdb_value_fetch_lazy (result)))
+    *valp = result;
+
+  if (val_chain)
+    {
+      /* Return the chain of intermediate values.  We use this to
+	 decide which addresses to watch.  */
+      *val_chain = new_mark;
+      value_release_to_mark (mark);
+    }
+}
+
 /* Extract a field operation from an expression.  If the subexpression
    of EXP starting at *SUBEXP is not a structure dereference
    operation, return NULL.  Otherwise, return the name of the
Index: gdb/i386-nat.c
===================================================================
--- gdb.orig/i386-nat.c	2010-07-02 17:03:03.000000000 -0300
+++ gdb/i386-nat.c	2010-07-06 19:07:53.000000000 -0300
@@ -484,7 +484,8 @@ Invalid value %d of operation in i386_ha
    of the type TYPE.  Return 0 on success, -1 on failure.  */
 
 static int
-i386_insert_watchpoint (CORE_ADDR addr, int len, int type)
+i386_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *cond)
 {
   int retval;
 
@@ -511,7 +512,8 @@ i386_insert_watchpoint (CORE_ADDR addr, 
    address ADDR, whose length is LEN bytes, and for accesses of the
    type TYPE.  Return 0 on success, -1 on failure.  */
 static int
-i386_remove_watchpoint (CORE_ADDR addr, int len, int type)
+i386_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *cond)
 {
   int retval;
 
Index: gdb/ia64-linux-nat.c
===================================================================
--- gdb.orig/ia64-linux-nat.c	2010-07-02 17:03:03.000000000 -0300
+++ gdb/ia64-linux-nat.c	2010-07-06 19:07:53.000000000 -0300
@@ -530,7 +530,8 @@ is_power_of_2 (int val)
 }
 
 static int
-ia64_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw)
+ia64_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw,
+			      struct expression *cond)
 {
   struct lwp_info *lp;
   ptid_t ptid;
@@ -584,7 +585,8 @@ ia64_linux_insert_watchpoint (CORE_ADDR 
 }
 
 static int
-ia64_linux_remove_watchpoint (CORE_ADDR addr, int len, int type)
+ia64_linux_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			      struct expression *cond)
 {
   int idx;
   long dbr_addr, dbr_mask;
Index: gdb/inf-ttrace.c
===================================================================
--- gdb.orig/inf-ttrace.c	2010-07-02 17:03:03.000000000 -0300
+++ gdb/inf-ttrace.c	2010-07-06 19:07:53.000000000 -0300
@@ -314,7 +314,8 @@ inf_ttrace_disable_page_protections (pid
    type TYPE.  */
 
 static int
-inf_ttrace_insert_watchpoint (CORE_ADDR addr, int len, int type)
+inf_ttrace_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			      struct expression *cond)
 {
   const int pagesize = inf_ttrace_page_dict.pagesize;
   pid_t pid = ptid_get_pid (inferior_ptid);
@@ -337,7 +338,8 @@ inf_ttrace_insert_watchpoint (CORE_ADDR 
    type TYPE.  */
 
 static int
-inf_ttrace_remove_watchpoint (CORE_ADDR addr, int len, int type)
+inf_ttrace_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			      struct expression *cond)
 {
   const int pagesize = inf_ttrace_page_dict.pagesize;
   pid_t pid = ptid_get_pid (inferior_ptid);
Index: gdb/mips-linux-nat.c
===================================================================
--- gdb.orig/mips-linux-nat.c	2010-07-02 17:03:03.000000000 -0300
+++ gdb/mips-linux-nat.c	2010-07-06 19:07:53.000000000 -0300
@@ -926,7 +926,8 @@ populate_regs_from_watches (struct pt_wa
    watch.  Return zero on success.  */
 
 static int
-mips_linux_insert_watchpoint (CORE_ADDR addr, int len, int type)
+mips_linux_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			      struct expression *cond)
 {
   struct pt_watch_regs regs;
   struct mips_watchpoint *new_watch;
@@ -975,7 +976,8 @@ mips_linux_insert_watchpoint (CORE_ADDR 
    Return zero on success.  */
 
 static int
-mips_linux_remove_watchpoint (CORE_ADDR addr, int len, int type)
+mips_linux_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			      struct expression *cond)
 {
   int retval;
   int deleted_one;
Index: gdb/nto-procfs.c
===================================================================
--- gdb.orig/nto-procfs.c	2010-07-02 17:03:03.000000000 -0300
+++ gdb/nto-procfs.c	2010-07-06 19:07:53.000000000 -0300
@@ -1506,13 +1506,15 @@ procfs_can_use_hw_breakpoint (int type, 
 }
 
 static int
-procfs_remove_hw_watchpoint (CORE_ADDR addr, int len, int type)
+procfs_remove_hw_watchpoint (CORE_ADDR addr, int len, int type,
+			     struct expression *cond)
 {
   return procfs_hw_watchpoint (addr, -1, type);
 }
 
 static int
-procfs_insert_hw_watchpoint (CORE_ADDR addr, int len, int type)
+procfs_insert_hw_watchpoint (CORE_ADDR addr, int len, int type,
+			     struct expression *cond)
 {
   return procfs_hw_watchpoint (addr, len, type);
 }
Index: gdb/ppc-linux-nat.c
===================================================================
--- gdb.orig/ppc-linux-nat.c	2010-07-02 17:03:03.000000000 -0300
+++ gdb/ppc-linux-nat.c	2010-07-06 19:07:53.000000000 -0300
@@ -1492,7 +1492,7 @@ ppc_linux_region_ok_for_hw_watchpoint (C
       if (booke_debug_info.data_bp_alignment
 	  && (addr + len > (addr & ~(booke_debug_info.data_bp_alignment - 1))
 	      + booke_debug_info.data_bp_alignment))
-	  return 0;
+	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
@@ -1685,8 +1685,202 @@ get_trigger_type (int rw)
   return t;
 }
 
+/* Check whether we have at least one free DVC register.  */
 static int
-ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw)
+can_use_watchpoint_cond_accel (void)
+{
+  struct thread_points *p;
+  int tid = TIDGET (inferior_ptid);
+  int cnt = booke_debug_info.num_condition_regs, i;
+  CORE_ADDR tmp_value;
+
+  if (!have_ptrace_booke_interface () || cnt == 0)
+    return 0;
+
+  p = booke_find_thread_points_by_tid (tid, 0);
+
+  if (p)
+    {
+      for (i = 0; i < max_slots_number; i++)
+	if (p->hw_breaks[i].hw_break != NULL
+	    && (p->hw_breaks[i].hw_break->condition_mode
+		!= PPC_BREAKPOINT_CONDITION_NONE))
+	  cnt--;
+
+      /* There are no available slots now.  */
+      if (cnt <= 0)
+	return 0;
+    }
+
+  return 1;
+}
+
+/* Calculate the enable bits and the contents of the Data Value Compare
+   debug register present in BookE processors.
+
+   ADDR is the address to be watched, LEN is the length of watched data
+   and DATA_VALUE is the value which will trigger the watchpoint.
+   On exit, CONDITION_MODE will hold the enable bits for the DVC, and
+   CONDITION_VALUE will hold the value which should be put in the
+   DVC register.  */
+static void
+calculate_dvc (CORE_ADDR addr, int len, CORE_ADDR data_value,
+	       uint32_t *condition_mode, uint64_t *condition_value)
+{
+  int i, num_byte_enable, align_offset, num_bytes_off_dvc,
+      rightmost_enabled_byte;
+  CORE_ADDR addr_end_data, addr_end_dvc;
+
+  /* The DVC register compares bytes within fixed-length windows which
+     are word-aligned, with length equal to that of the DVC register.
+     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;
+  addr_end_data = addr + len;
+  addr_end_dvc = (addr - align_offset
+		  + booke_debug_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;
+  /* Here, bytes are numbered from right to left.  */
+  rightmost_enabled_byte = (addr_end_data < addr_end_dvc)?
+			      addr_end_dvc - addr_end_data : 0;
+
+  *condition_mode = PPC_BREAKPOINT_CONDITION_AND;
+  for (i = 0; i < num_byte_enable; i++)
+    *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
+     (i.e., the ALIGN_OFFSET).  */
+
+  *condition_value = ((uint64_t) data_value >> num_bytes_off_dvc * 8
+		      << rightmost_enabled_byte * 8);
+}
+
+/* Return the number of memory locations that need to be accessed to
+   evaluate the expression which generated the given value chain.
+   Returns -1 if there's any register access involved, or if there are
+   other kinds of values which are not acceptable in a condition
+   expression (e.g., lval_computed or lval_internalvar).  */
+static int
+num_memory_accesses (struct value *v)
+{
+  int found_memory_cnt = 0;
+  struct value *head = v;
+
+  /* The idea here is that evaluating an expression generates a series
+     of values, one holding the value of every subexpression.  (The
+     expression a*b+c has five subexpressions: a, b, a*b, c, and
+     a*b+c.)  GDB's values hold almost enough information to establish
+     the criteria given above --- they identify memory lvalues,
+     register lvalues, computed values, etcetera.  So we can evaluate
+     the expression, and then scan the chain of values that leaves
+     behind to determine the memory locations involved in the evaluation
+     of an expression.
+
+     However, I don't think that the values returned by inferior
+     function calls are special in any way.  So this function may not
+     notice that an expression contains an inferior function call.
+     FIXME.  */
+
+  for (; v; v = value_next (v))
+    {
+      /* Constants and values from the history are fine.  */
+      if (VALUE_LVAL (v) == not_lval || deprecated_value_modifiable (v) == 0)
+	continue;
+      else if (VALUE_LVAL (v) == lval_memory)
+	{
+	  /* A lazy memory lvalue is one that GDB never needed to fetch;
+	     we either just used its address (e.g., `a' in `a.b') or
+	     we never needed it at all (e.g., `a' in `a,b').  */
+	  if (!value_lazy (v))
+	    found_memory_cnt++;
+	}
+      /* Other kinds of values are not fine. */
+      else
+	return -1;
+    }
+
+  return found_memory_cnt;
+}
+
+/* Verifies whether the expression COND can be implemented using the
+   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.  */
+static int
+check_condition (CORE_ADDR watch_addr, struct expression *cond,
+		 CORE_ADDR *data_value)
+{
+  int pc = 1, num_accesses_left, num_accesses_right;
+  struct value *left_val, *right_val, *left_chain, *right_chain;
+
+  if (cond->elts[0].opcode != BINOP_EQUAL)
+    return 0;
+
+  fetch_subexp_value (cond, &pc, &left_val, NULL, &left_chain);
+  num_accesses_left = num_memory_accesses (left_chain);
+
+  if (left_val == NULL || num_accesses_left < 0)
+    {
+      free_value_chain (left_chain);
+
+      return 0;
+    }
+
+  fetch_subexp_value (cond, &pc, &right_val, NULL, &right_chain);
+  num_accesses_right = num_memory_accesses (right_chain);
+
+  if (right_val == NULL || num_accesses_right < 0)
+    {
+      free_value_chain (left_chain);
+      free_value_chain (right_chain);
+
+      return 0;
+    }
+
+  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);
+  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);
+  else
+    {
+      free_value_chain (left_chain);
+      free_value_chain (right_chain);
+
+      return 0;
+    }
+
+  free_value_chain (left_chain);
+  free_value_chain (right_chain);
+
+  return 1;
+}
+
+/* Return non-zero if the target is capable of using hardware to evaluate
+   the condition expression, thus only triggering the watchpoint when it is
+   true.  */
+static int
+ppc_linux_can_accel_watchpoint_condition (CORE_ADDR addr, int len, int rw,
+					  struct expression *cond)
+{
+  CORE_ADDR data_value;
+
+  return (have_ptrace_booke_interface ()
+	  && booke_debug_info.num_condition_regs > 0
+	  && check_condition (addr, cond, &data_value));
+}
+
+static int
+ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw,
+			     struct expression *cond)
 {
   struct lwp_info *lp;
   ptid_t ptid;
@@ -1695,14 +1889,23 @@ ppc_linux_insert_watchpoint (CORE_ADDR a
   if (have_ptrace_booke_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.condition_mode  = PPC_BREAKPOINT_CONDITION_NONE;
       p.addr            = (uint64_t) addr;
       p.addr2           = 0;
-      p.condition_value = 0;
 
       ALL_LWPS (lp, ptid)
 	booke_insert_point (&p, TIDGET (ptid));
@@ -1749,7 +1952,8 @@ ppc_linux_insert_watchpoint (CORE_ADDR a
       saved_dabr_value = dabr_value;
 
       ALL_LWPS (lp, ptid)
-	if (ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0, saved_dabr_value) < 0)
+	if (ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0,
+		    saved_dabr_value) < 0)
 	  return -1;
 
       ret = 0;
@@ -1759,7 +1963,8 @@ ppc_linux_insert_watchpoint (CORE_ADDR a
 }
 
 static int
-ppc_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw)
+ppc_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw,
+			     struct expression *cond)
 {
   struct lwp_info *lp;
   ptid_t ptid;
@@ -1768,14 +1973,23 @@ ppc_linux_remove_watchpoint (CORE_ADDR a
   if (have_ptrace_booke_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.condition_mode  = PPC_BREAKPOINT_CONDITION_NONE;
       p.addr            = (uint64_t) addr;
       p.addr2           = 0;
-      p.condition_value = 0;
 
       ALL_LWPS (lp, ptid)
 	booke_remove_point (&p, TIDGET (ptid));
@@ -1786,7 +2000,8 @@ ppc_linux_remove_watchpoint (CORE_ADDR a
     {
       saved_dabr_value = 0;
       ALL_LWPS (lp, ptid)
-	if (ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0, saved_dabr_value) < 0)
+	if (ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0,
+		    saved_dabr_value) < 0)
 	  return -1;
 
       ret = 0;
@@ -2137,6 +2352,7 @@ _initialize_ppc_linux_nat (void)
   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_read_description = ppc_linux_read_description;
   t->to_auxv_parse = ppc_linux_auxv_parse;
Index: gdb/procfs.c
===================================================================
--- gdb.orig/procfs.c	2010-07-06 19:05:12.000000000 -0300
+++ gdb/procfs.c	2010-07-06 19:07:53.000000000 -0300
@@ -5161,7 +5161,8 @@ procfs_stopped_data_address (struct targ
 }
 
 static int
-procfs_insert_watchpoint (CORE_ADDR addr, int len, int type)
+procfs_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			  struct expression *cond)
 {
   if (!target_have_steppable_watchpoint
       && !gdbarch_have_nonsteppable_watchpoint (target_gdbarch))
@@ -5182,7 +5183,8 @@ procfs_insert_watchpoint (CORE_ADDR addr
 }
 
 static int
-procfs_remove_watchpoint (CORE_ADDR addr, int len, int type)
+procfs_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			  struct expression *cond)
 {
   return procfs_set_watchpoint (inferior_ptid, addr, 0, 0, 0);
 }
Index: gdb/remote-m32r-sdi.c
===================================================================
--- gdb.orig/remote-m32r-sdi.c	2010-07-02 17:03:03.000000000 -0300
+++ gdb/remote-m32r-sdi.c	2010-07-06 19:07:53.000000000 -0300
@@ -1421,7 +1421,8 @@ m32r_can_use_hw_watchpoint (int type, in
    watchpoint. */
 
 static int
-m32r_insert_watchpoint (CORE_ADDR addr, int len, int type)
+m32r_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *cond)
 {
   int i;
 
@@ -1445,7 +1446,8 @@ m32r_insert_watchpoint (CORE_ADDR addr, 
 }
 
 static int
-m32r_remove_watchpoint (CORE_ADDR addr, int len, int type)
+m32r_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *cond)
 {
   int i;
 
Index: gdb/remote-mips.c
===================================================================
--- gdb.orig/remote-mips.c	2010-07-02 17:03:04.000000000 -0300
+++ gdb/remote-mips.c	2010-07-06 19:07:53.000000000 -0300
@@ -2401,7 +2401,8 @@ calculate_mask (CORE_ADDR addr, int len)
    watchpoint. */
 
 int
-mips_insert_watchpoint (CORE_ADDR addr, int len, int type)
+mips_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *cond)
 {
   if (mips_set_breakpoint (addr, len, type))
     return -1;
@@ -2412,7 +2413,8 @@ mips_insert_watchpoint (CORE_ADDR addr, 
 /* Remove a watchpoint.  */
 
 int
-mips_remove_watchpoint (CORE_ADDR addr, int len, int type)
+mips_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *cond)
 {
   if (mips_clear_breakpoint (addr, len, type))
     return -1;
Index: gdb/remote.c
===================================================================
--- gdb.orig/remote.c	2010-07-06 19:05:12.000000000 -0300
+++ gdb/remote.c	2010-07-06 19:07:53.000000000 -0300
@@ -7646,7 +7646,8 @@ watchpoint_to_Z_packet (int type)
 }
 
 static int
-remote_insert_watchpoint (CORE_ADDR addr, int len, int type)
+remote_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			  struct expression *cond)
 {
   struct remote_state *rs = get_remote_state ();
   char *p;
@@ -7679,7 +7680,8 @@ remote_insert_watchpoint (CORE_ADDR addr
 
 
 static int
-remote_remove_watchpoint (CORE_ADDR addr, int len, int type)
+remote_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			  struct expression *cond)
 {
   struct remote_state *rs = get_remote_state ();
   char *p;
Index: gdb/s390-nat.c
===================================================================
--- gdb.orig/s390-nat.c	2010-07-02 17:03:04.000000000 -0300
+++ gdb/s390-nat.c	2010-07-06 19:07:53.000000000 -0300
@@ -335,7 +335,8 @@ s390_fix_watch_points (ptid_t ptid)
 }
 
 static int
-s390_insert_watchpoint (CORE_ADDR addr, int len, int type)
+s390_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *cond)
 {
   struct lwp_info *lp;
   ptid_t ptid;
@@ -356,7 +357,8 @@ s390_insert_watchpoint (CORE_ADDR addr, 
 }
 
 static int
-s390_remove_watchpoint (CORE_ADDR addr, int len, int type)
+s390_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			struct expression *cond)
 {
   struct lwp_info *lp;
   ptid_t ptid;
Index: gdb/target.c
===================================================================
--- gdb.orig/target.c	2010-07-06 19:05:12.000000000 -0300
+++ gdb/target.c	2010-07-06 19:07:53.000000000 -0300
@@ -117,9 +117,11 @@ static int debug_to_insert_hw_breakpoint
 static int debug_to_remove_hw_breakpoint (struct gdbarch *,
 					  struct bp_target_info *);
 
-static int debug_to_insert_watchpoint (CORE_ADDR, int, int);
+static int debug_to_insert_watchpoint (CORE_ADDR, int, int,
+				       struct expression *);
 
-static int debug_to_remove_watchpoint (CORE_ADDR, int, int);
+static int debug_to_remove_watchpoint (CORE_ADDR, int, int,
+				       struct expression *);
 
 static int debug_to_stopped_by_watchpoint (void);
 
@@ -130,6 +132,9 @@ static int debug_to_watchpoint_addr_with
 
 static int debug_to_region_ok_for_hw_watchpoint (CORE_ADDR, int);
 
+static int debug_to_can_accel_watchpoint_condition (CORE_ADDR, int, int,
+						    struct expression *);
+
 static void debug_to_terminal_init (void);
 
 static void debug_to_terminal_inferior (void);
@@ -607,6 +612,7 @@ update_current_target (void)
       INHERIT (to_stopped_by_watchpoint, t);
       INHERIT (to_watchpoint_addr_within_range, t);
       INHERIT (to_region_ok_for_hw_watchpoint, t);
+      INHERIT (to_can_accel_watchpoint_condition, t);
       INHERIT (to_terminal_init, t);
       INHERIT (to_terminal_inferior, t);
       INHERIT (to_terminal_ours_for_output, t);
@@ -728,10 +734,10 @@ update_current_target (void)
 	    (int (*) (struct gdbarch *, struct bp_target_info *))
 	    return_minus_one);
   de_fault (to_insert_watchpoint,
-	    (int (*) (CORE_ADDR, int, int))
+	    (int (*) (CORE_ADDR, int, int, struct expression *))
 	    return_minus_one);
   de_fault (to_remove_watchpoint,
-	    (int (*) (CORE_ADDR, int, int))
+	    (int (*) (CORE_ADDR, int, int, struct expression *))
 	    return_minus_one);
   de_fault (to_stopped_by_watchpoint,
 	    (int (*) (void))
@@ -743,6 +749,9 @@ 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_can_accel_watchpoint_condition,
+            (int (*) (CORE_ADDR, int, int, struct expression *))
+            return_zero);
   de_fault (to_terminal_init,
 	    (void (*) (void))
 	    target_ignore);
@@ -3314,6 +3323,21 @@ debug_to_region_ok_for_hw_watchpoint (CO
 }
 
 static int
+debug_to_can_accel_watchpoint_condition (CORE_ADDR addr, int len, int rw,
+					 struct expression *cond)
+{
+  int retval;
+
+  retval = debug_target.to_can_accel_watchpoint_condition (addr, len, rw, cond);
+
+  fprintf_unfiltered (gdb_stdlog,
+		      "target_can_accel_watchpoint_condition (0x%lx, %d, %d, 0x%lx) = %ld\n",
+		      (unsigned long) addr, len, rw, (unsigned long) cond,
+		      (unsigned long) retval);
+  return retval;
+}
+
+static int
 debug_to_stopped_by_watchpoint (void)
 {
   int retval;
@@ -3388,28 +3412,32 @@ debug_to_remove_hw_breakpoint (struct gd
 }
 
 static int
-debug_to_insert_watchpoint (CORE_ADDR addr, int len, int type)
+debug_to_insert_watchpoint (CORE_ADDR addr, int len, int type,
+			    struct expression *cond)
 {
   int retval;
 
-  retval = debug_target.to_insert_watchpoint (addr, len, type);
+  retval = debug_target.to_insert_watchpoint (addr, len, type, cond);
 
   fprintf_unfiltered (gdb_stdlog,
-		      "target_insert_watchpoint (0x%lx, %d, %d) = %ld\n",
-		      (unsigned long) addr, len, type, (unsigned long) retval);
+		      "target_insert_watchpoint (0x%lx, %d, %d, 0x%ld) = %ld\n",
+		      (unsigned long) addr, len, type, (unsigned long) cond,
+		      (unsigned long) retval);
   return retval;
 }
 
 static int
-debug_to_remove_watchpoint (CORE_ADDR addr, int len, int type)
+debug_to_remove_watchpoint (CORE_ADDR addr, int len, int type,
+			    struct expression *cond)
 {
   int retval;
 
-  retval = debug_target.to_remove_watchpoint (addr, len, type);
+  retval = debug_target.to_remove_watchpoint (addr, len, type, cond);
 
   fprintf_unfiltered (gdb_stdlog,
-		      "target_remove_watchpoint (0x%lx, %d, %d) = %ld\n",
-		      (unsigned long) addr, len, type, (unsigned long) retval);
+		      "target_remove_watchpoint (0x%lx, %d, %d, 0x%ld) = %ld\n",
+		      (unsigned long) addr, len, type, (unsigned long) cond,
+		      (unsigned long) retval);
   return retval;
 }
 
@@ -3664,6 +3692,7 @@ setup_target_debug (void)
   current_target.to_stopped_data_address = debug_to_stopped_data_address;
   current_target.to_watchpoint_addr_within_range = debug_to_watchpoint_addr_within_range;
   current_target.to_region_ok_for_hw_watchpoint = debug_to_region_ok_for_hw_watchpoint;
+  current_target.to_can_accel_watchpoint_condition = debug_to_can_accel_watchpoint_condition;
   current_target.to_terminal_init = debug_to_terminal_init;
   current_target.to_terminal_inferior = debug_to_terminal_inferior;
   current_target.to_terminal_ours_for_output = debug_to_terminal_ours_for_output;
Index: gdb/target.h
===================================================================
--- gdb.orig/target.h	2010-07-06 19:05:12.000000000 -0300
+++ gdb/target.h	2010-07-06 19:07:53.000000000 -0300
@@ -37,6 +37,8 @@ struct uploaded_tsv;
 struct uploaded_tp;
 struct static_tracepoint_marker;
 
+struct expression;
+
 /* 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
@@ -426,8 +428,12 @@ struct target_ops
     int (*to_can_use_hw_breakpoint) (int, int, int);
     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);
+
+    /* Documentation of what the two routines below are expected to do is
+       provided with the corresponding target_* macros.  */
+    int (*to_remove_watchpoint) (CORE_ADDR, int, int, struct expression *);
+    int (*to_insert_watchpoint) (CORE_ADDR, int, int, struct expression *);
+
     int (*to_stopped_by_watchpoint) (void);
     int to_have_steppable_watchpoint;
     int to_have_continuable_watchpoint;
@@ -435,6 +441,8 @@ struct target_ops
     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_can_accel_watchpoint_condition) (CORE_ADDR, int, int,
+					      struct expression *);
     void (*to_terminal_init) (void);
     void (*to_terminal_inferior) (void);
     void (*to_terminal_ours_for_output) (void);
@@ -1298,14 +1306,15 @@ extern char *normal_pid_to_str (ptid_t p
 
 /* 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.
+   COND is the expression for its condition, or NULL if there's none.
    Returns 0 for success, 1 if the watchpoint type is not supported,
    -1 for failure.  */
 
-#define	target_insert_watchpoint(addr, len, type)	\
-     (*current_target.to_insert_watchpoint) (addr, len, type)
+#define	target_insert_watchpoint(addr, len, type, cond) \
+     (*current_target.to_insert_watchpoint) (addr, len, type, cond)
 
-#define	target_remove_watchpoint(addr, len, type)	\
-     (*current_target.to_remove_watchpoint) (addr, len, type)
+#define	target_remove_watchpoint(addr, len, type, cond) \
+     (*current_target.to_remove_watchpoint) (addr, len, type, cond)
 
 #define target_insert_hw_breakpoint(gdbarch, bp_tgt) \
      (*current_target.to_insert_hw_breakpoint) (gdbarch, bp_tgt)
@@ -1322,6 +1331,19 @@ extern char *normal_pid_to_str (ptid_t p
 #define target_watchpoint_addr_within_range(target, addr, start, length) \
   (*target.to_watchpoint_addr_within_range) (target, addr, start, length)
 
+/* Return non-zero if the target is capable of using hardware to evaluate
+   the condition expression.  In this case, if the condition is false when
+   the watched memory location changes, execution may continue without the
+   debugger being notified.
+
+   Due to limitations in the hardware implementation, it may be capable of
+   avoiding triggering the watchpoint in some cases where the condition
+   expression is false, but may report some false positives as well.
+   For this reason, GDB will still evaluate the condition expression when
+   the watchpoint triggers.  */
+#define target_can_accel_watchpoint_condition(addr, len, type, cond) \
+  (*current_target.to_can_accel_watchpoint_condition) (addr, len, type, cond)
+
 /* Target can execute in reverse?  */
 #define target_can_execute_reverse \
      (current_target.to_can_execute_reverse ? \
Index: gdb/value.c
===================================================================
--- gdb.orig/value.c	2010-07-06 19:05:12.000000000 -0300
+++ gdb/value.c	2010-07-06 19:07:53.000000000 -0300
@@ -722,6 +722,20 @@ free_all_values (void)
   all_values = 0;
 }
 
+/* Frees all the elements in a chain of values.  */
+
+void
+free_value_chain (struct value *v)
+{
+  struct value *next;
+
+  for (; v; v = next)
+    {
+      next = value_next (v);
+      value_free (v);
+    }
+}
+
 /* Remove VAL from the chain all_values
    so it will not be freed automatically.  */
 
Index: gdb/value.h
===================================================================
--- gdb.orig/value.h	2010-07-06 19:05:12.000000000 -0300
+++ gdb/value.h	2010-07-06 19:07:53.000000000 -0300
@@ -538,6 +538,10 @@ extern struct value *evaluate_subexp (st
 extern struct value *evaluate_subexpression_type (struct expression *exp,
 						  int subexp);
 
+extern void fetch_subexp_value (struct expression *exp, int *pc,
+				struct value **valp, struct value **resultp,
+				struct value **val_chain);
+
 extern char *extract_field_op (struct expression *exp, int *subexp);
 
 extern struct value *evaluate_subexp_with_coercion (struct expression *,
@@ -635,6 +639,8 @@ extern void value_free (struct value *va
 
 extern void free_all_values (void);
 
+extern void free_value_chain (struct value *v);
+
 extern void release_value (struct value *val);
 
 extern int record_latest_value (struct value *val);

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 2/4] Hardware accelerated watchpoint conditions
  2010-07-06 22:22                         ` Thiago Jung Bauermann
@ 2010-07-07 12:25                           ` Ulrich Weigand
  2010-07-07 16:21                             ` Thiago Jung Bauermann
  0 siblings, 1 reply; 17+ messages in thread
From: Ulrich Weigand @ 2010-07-07 12:25 UTC (permalink / raw)
  To: Thiago Jung Bauermann
  Cc: Joel Brobecker, gdb-patches, Luis Machado, Matt Tyrlik

Thiago Jung Bauermann wrote:

> 2010-07-06  Sergio Durigan Junior  <sergiodj@linux.vnet.ibm.com>
> 	    Thiago Jung Bauermann  <bauerman@br.ibm.com>
> 
> 	* breakpoint.c (fetch_watchpoint_value): Rename to fetch_subexp_value
> 	and move to eval.c.  Change callers.
> 	(insert_bp_location): Pass watchpoint condition in
> 	target_insert_watchpoint.
> 	(remove_breakpoint_1) Pass watchpoint condition in
> 	target_remove_watchpoint.
> 	(watchpoint_locations_match): Call
> 	target_can_accel_watchpoint_condition.
> 	* eval.c: Include wrapper.h.
> 	(fetch_subexp_value): Moved from breakpoint.c.
> 	* ppc-linux-nat.c (ppc_linux_region_ok_for_hw_watchpoint):
> 	Formatting fix.
> 	(can_use_watchpoint_cond_accel): New function.
> 	(calculate_dvc): Likewise.
> 	(num_memory_accesses): Likewise.
> 	(check_condition): Likewise.
> 	(ppc_linux_can_accel_watchpoint_condition): Likewise
> 	(ppc_linux_insert_watchpoint): Call can_use_watchpoint_cond_accel,
> 	check_condition and calculate_dvc.
> 	(ppc_linux_remove_watchpoint): Likewise.
> 	(_initialize_ppc_linux_nat): Set to_can_accel_watchpoint_condition to
> 	ppc_linux_can_accel_watchpoint_condition
> 	* target.c (debug_to_insert_watchpoint): Add argument for watchpoint
> 	condition.
> 	(debug_to_remove_watchpoint): Likewise.
> 	(debug_to_can_accel_watchpoint_condition): New function.
> 	(update_current_target): Set to_can_accel_watchpoint_condition.
> 	(setup_target_debug): Set to_can_accel_watchpoint_condition.
> 	* target.h: Add opaque declaration for struct expression.
> 	(struct target_ops) <to_insert_watchpoint>,
> 	<to_remove_watchpoint>: Add new arguments to pass the watchpoint
> 	<to_can_accel_watchpoint_condition>: New member.
> 	condition.  Update all callers and implementations.
> 	(target_can_accel_watchpoint_condition): New macro.
> 	* value.c (free_value_chain): New function.
> 	* value.h (fetch_subexp_value): New prototype.
> 	(free_value_chain): Likewise.

This is OK.

Thanks,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 2/4] Hardware accelerated watchpoint conditions
  2010-07-07 12:25                           ` Ulrich Weigand
@ 2010-07-07 16:21                             ` Thiago Jung Bauermann
  2010-07-07 16:45                               ` Joel Brobecker
  0 siblings, 1 reply; 17+ messages in thread
From: Thiago Jung Bauermann @ 2010-07-07 16:21 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: Joel Brobecker, gdb-patches, Luis Machado, Matt Tyrlik

On Wed, 2010-07-07 at 14:24 +0200, Ulrich Weigand wrote:
> Thiago Jung Bauermann wrote:
> 
> > 2010-07-06  Sergio Durigan Junior  <sergiodj@linux.vnet.ibm.com>
> > 	    Thiago Jung Bauermann  <bauerman@br.ibm.com>
> > 
> > 	* breakpoint.c (fetch_watchpoint_value): Rename to fetch_subexp_value
> > 	and move to eval.c.  Change callers.
> > 	(insert_bp_location): Pass watchpoint condition in
> > 	target_insert_watchpoint.
> > 	(remove_breakpoint_1) Pass watchpoint condition in
> > 	target_remove_watchpoint.
> > 	(watchpoint_locations_match): Call
> > 	target_can_accel_watchpoint_condition.
> > 	* eval.c: Include wrapper.h.
> > 	(fetch_subexp_value): Moved from breakpoint.c.
> > 	* ppc-linux-nat.c (ppc_linux_region_ok_for_hw_watchpoint):
> > 	Formatting fix.
> > 	(can_use_watchpoint_cond_accel): New function.
> > 	(calculate_dvc): Likewise.
> > 	(num_memory_accesses): Likewise.
> > 	(check_condition): Likewise.
> > 	(ppc_linux_can_accel_watchpoint_condition): Likewise
> > 	(ppc_linux_insert_watchpoint): Call can_use_watchpoint_cond_accel,
> > 	check_condition and calculate_dvc.
> > 	(ppc_linux_remove_watchpoint): Likewise.
> > 	(_initialize_ppc_linux_nat): Set to_can_accel_watchpoint_condition to
> > 	ppc_linux_can_accel_watchpoint_condition
> > 	* target.c (debug_to_insert_watchpoint): Add argument for watchpoint
> > 	condition.
> > 	(debug_to_remove_watchpoint): Likewise.
> > 	(debug_to_can_accel_watchpoint_condition): New function.
> > 	(update_current_target): Set to_can_accel_watchpoint_condition.
> > 	(setup_target_debug): Set to_can_accel_watchpoint_condition.
> > 	* target.h: Add opaque declaration for struct expression.
> > 	(struct target_ops) <to_insert_watchpoint>,
> > 	<to_remove_watchpoint>: Add new arguments to pass the watchpoint
> > 	<to_can_accel_watchpoint_condition>: New member.
> > 	condition.  Update all callers and implementations.
> > 	(target_can_accel_watchpoint_condition): New macro.
> > 	* value.c (free_value_chain): New function.
> > 	* value.h (fetch_subexp_value): New prototype.
> > 	(free_value_chain): Likewise.
> 
> This is OK.

Committed, thanks!

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 2/4] Hardware accelerated watchpoint conditions
  2010-07-07 16:21                             ` Thiago Jung Bauermann
@ 2010-07-07 16:45                               ` Joel Brobecker
  2010-07-07 20:37                                 ` Thiago Jung Bauermann
  0 siblings, 1 reply; 17+ messages in thread
From: Joel Brobecker @ 2010-07-07 16:45 UTC (permalink / raw)
  To: Thiago Jung Bauermann
  Cc: Ulrich Weigand, gdb-patches, Luis Machado, Matt Tyrlik

> > > 2010-07-06  Sergio Durigan Junior  <sergiodj@linux.vnet.ibm.com>
> > > 	    Thiago Jung Bauermann  <bauerman@br.ibm.com>
> > > 
> > > 	* breakpoint.c (fetch_watchpoint_value): Rename to fetch_subexp_value
> > > 	and move to eval.c.  Change callers.
> > > 	(insert_bp_location): Pass watchpoint condition in
> > > 	target_insert_watchpoint.
> > > 	(remove_breakpoint_1) Pass watchpoint condition in
> > > 	target_remove_watchpoint.
> > > 	(watchpoint_locations_match): Call
> > > 	target_can_accel_watchpoint_condition.
> > > 	* eval.c: Include wrapper.h.
> > > 	(fetch_subexp_value): Moved from breakpoint.c.
> > > 	* ppc-linux-nat.c (ppc_linux_region_ok_for_hw_watchpoint):
> > > 	Formatting fix.
> > > 	(can_use_watchpoint_cond_accel): New function.
> > > 	(calculate_dvc): Likewise.
> > > 	(num_memory_accesses): Likewise.
> > > 	(check_condition): Likewise.
> > > 	(ppc_linux_can_accel_watchpoint_condition): Likewise
> > > 	(ppc_linux_insert_watchpoint): Call can_use_watchpoint_cond_accel,
> > > 	check_condition and calculate_dvc.
> > > 	(ppc_linux_remove_watchpoint): Likewise.
> > > 	(_initialize_ppc_linux_nat): Set to_can_accel_watchpoint_condition to
> > > 	ppc_linux_can_accel_watchpoint_condition
> > > 	* target.c (debug_to_insert_watchpoint): Add argument for watchpoint
> > > 	condition.
> > > 	(debug_to_remove_watchpoint): Likewise.
> > > 	(debug_to_can_accel_watchpoint_condition): New function.
> > > 	(update_current_target): Set to_can_accel_watchpoint_condition.
> > > 	(setup_target_debug): Set to_can_accel_watchpoint_condition.
> > > 	* target.h: Add opaque declaration for struct expression.
> > > 	(struct target_ops) <to_insert_watchpoint>,
> > > 	<to_remove_watchpoint>: Add new arguments to pass the watchpoint
> > > 	<to_can_accel_watchpoint_condition>: New member.
> > > 	condition.  Update all callers and implementations.
> > > 	(target_can_accel_watchpoint_condition): New macro.
> > > 	* value.c (free_value_chain): New function.
> > > 	* value.h (fetch_subexp_value): New prototype.
> > > 	(free_value_chain): Likewise.
> > 
> > This is OK.
> 
> Committed, thanks!

I am a little nervous about including this in 7.2 given that it changes
the interface of target_ops functions.  But at the same time, it's been
WIP for so long that I feel that everyone who contributed to getting
this piece of code in deserves to see this code in 7.2. We can work out
any missing API updates, if any during the branch stabilization phase.

Any objection, please yell.

-- 
Joel

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 2/4] Hardware accelerated watchpoint conditions
  2010-07-07 16:45                               ` Joel Brobecker
@ 2010-07-07 20:37                                 ` Thiago Jung Bauermann
  0 siblings, 0 replies; 17+ messages in thread
From: Thiago Jung Bauermann @ 2010-07-07 20:37 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: Ulrich Weigand, gdb-patches, Luis Machado, Matt Tyrlik

On Wed, 2010-07-07 at 09:44 -0700, Joel Brobecker wrote:
> > > > 2010-07-06  Sergio Durigan Junior  <sergiodj@linux.vnet.ibm.com>
> > > > 	    Thiago Jung Bauermann  <bauerman@br.ibm.com>
> > > > 
> > > > 	* breakpoint.c (fetch_watchpoint_value): Rename to fetch_subexp_value
> > > > 	and move to eval.c.  Change callers.
> > > > 	(insert_bp_location): Pass watchpoint condition in
> > > > 	target_insert_watchpoint.
> > > > 	(remove_breakpoint_1) Pass watchpoint condition in
> > > > 	target_remove_watchpoint.
> > > > 	(watchpoint_locations_match): Call
> > > > 	target_can_accel_watchpoint_condition.
> > > > 	* eval.c: Include wrapper.h.
> > > > 	(fetch_subexp_value): Moved from breakpoint.c.
> > > > 	* ppc-linux-nat.c (ppc_linux_region_ok_for_hw_watchpoint):
> > > > 	Formatting fix.
> > > > 	(can_use_watchpoint_cond_accel): New function.
> > > > 	(calculate_dvc): Likewise.
> > > > 	(num_memory_accesses): Likewise.
> > > > 	(check_condition): Likewise.
> > > > 	(ppc_linux_can_accel_watchpoint_condition): Likewise
> > > > 	(ppc_linux_insert_watchpoint): Call can_use_watchpoint_cond_accel,
> > > > 	check_condition and calculate_dvc.
> > > > 	(ppc_linux_remove_watchpoint): Likewise.
> > > > 	(_initialize_ppc_linux_nat): Set to_can_accel_watchpoint_condition to
> > > > 	ppc_linux_can_accel_watchpoint_condition
> > > > 	* target.c (debug_to_insert_watchpoint): Add argument for watchpoint
> > > > 	condition.
> > > > 	(debug_to_remove_watchpoint): Likewise.
> > > > 	(debug_to_can_accel_watchpoint_condition): New function.
> > > > 	(update_current_target): Set to_can_accel_watchpoint_condition.
> > > > 	(setup_target_debug): Set to_can_accel_watchpoint_condition.
> > > > 	* target.h: Add opaque declaration for struct expression.
> > > > 	(struct target_ops) <to_insert_watchpoint>,
> > > > 	<to_remove_watchpoint>: Add new arguments to pass the watchpoint
> > > > 	<to_can_accel_watchpoint_condition>: New member.
> > > > 	condition.  Update all callers and implementations.
> > > > 	(target_can_accel_watchpoint_condition): New macro.
> > > > 	* value.c (free_value_chain): New function.
> > > > 	* value.h (fetch_subexp_value): New prototype.
> > > > 	(free_value_chain): Likewise.
> > > 
> > > This is OK.
> > 
> > Committed, thanks!
> 
> I am a little nervous about including this in 7.2 given that it changes
> the interface of target_ops functions.  But at the same time, it's been
> WIP for so long that I feel that everyone who contributed to getting
> this piece of code in deserves to see this code in 7.2. We can work out
> any missing API updates, if any during the branch stabilization phase.

Thanks!

The patch adds an argument to to_insert_watchpoint and
to_remove_watchpoint, and adds a new target function
(to_can_accel_watchpoint_condition) with a default implementation
(return_zero). If this patch doesn't make GDB fail to compile on a
platform (I didn't try to compile it on all platforms which it touches),
then it shouldn't have any impact.
-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2010-07-07 20:37 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <200912232231.01798.bauerman@br.ibm.com>
2010-01-04 17:33 ` [PATCH 2/4] Hardware accelerated watchpoint conditions Thiago Jung Bauermann
2010-01-12 10:51   ` Joel Brobecker
2010-02-04 21:48     ` Thiago Jung Bauermann
2010-02-05  5:16       ` Joel Brobecker
2010-02-08 20:01         ` Thiago Jung Bauermann
2010-02-11 18:24           ` Ulrich Weigand
2010-06-09  4:02             ` Thiago Jung Bauermann
2010-06-09 13:28               ` Ulrich Weigand
2010-06-23 17:21                 ` Thiago Jung Bauermann
2010-06-23 19:57                   ` Ulrich Weigand
2010-07-01 14:51                     ` Thiago Jung Bauermann
2010-07-02 13:20                       ` Ulrich Weigand
2010-07-06 22:22                         ` Thiago Jung Bauermann
2010-07-07 12:25                           ` Ulrich Weigand
2010-07-07 16:21                             ` Thiago Jung Bauermann
2010-07-07 16:45                               ` Joel Brobecker
2010-07-07 20:37                                 ` Thiago Jung Bauermann

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).