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


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

Re: [PATCH 2/4] Hardware accelerated watchpoint conditions


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.


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 ? \

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