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


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

[PATCH 2/4] Hardware accelerated watchpoint conditions


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.
-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center


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

	* breakpoint.c (update_watchpoint): Disabled watchpoints before
	checking the used count.  Handled the case when the hardware supports
	the acceleration of the watchpoint's condition evaluation.
	(insert_bp_location): Calling the correct insertion method according
	to the type of the hardware watchpoint.
	(remove_breakpoint_1): Calling the correct deletion method according
	to the type of the hardware watchpoint.
	(set_raw_breakpoint_without_location): Setting the flag to zero.
	(watch_command_1): Handling the creation of hardware-accelerated
	condition watchpoint.
	(update_breakpoint_locations):  Handling 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, co_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, co_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.
Index: gdb/gdb/breakpoint.c
===================================================================
--- gdb.orig/gdb/breakpoint.c	2009-12-23 15:14:03.000000000 -0200
+++ gdb/gdb/breakpoint.c	2009-12-23 17:07:34.000000000 -0200
@@ -1151,6 +1151,13 @@ update_watchpoint (struct breakpoint *b,
 	    && reparse)
 	  {
 	    int i, mem_cnt, other_type_used;
+	    enum enable_state e;
+
+	    /* We have to temporary disable this watchpoint, otherwise
+	       we will count it twice (once as being inserted, and once
+	       as a watchpoint that we want to insert).  */
+	    e = b->enable_state;
+	    b->enable_state = bp_disabled;
 
 	    i = hw_watchpoint_used_count (bp_hardware_watchpoint,
 					  &other_type_used);
@@ -1167,6 +1174,8 @@ update_watchpoint (struct breakpoint *b,
 		else
 		  b->type = bp_hardware_watchpoint;
 	      }
+	    /* Restoring the original state.  */
+	    b->enable_state = e;
 	  }
 
       frame_pspace = get_frame_program_space (get_selected_frame (NULL));
@@ -1229,6 +1238,17 @@ update_watchpoint (struct breakpoint *b,
 	{
 	  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)
@@ -1472,9 +1492,15 @@ Note: automatically using hardware break
 	      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);
     }
 
@@ -2100,8 +2126,13 @@ remove_breakpoint_1 (struct bp_location 
       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))
@@ -4850,6 +4881,7 @@ set_raw_breakpoint_without_location (str
   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
@@ -7300,6 +7332,10 @@ watch_command_1 (char *arg, int accessfl
      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);
 }
@@ -8854,6 +8890,18 @@ update_breakpoint_locations (struct brea
 		       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)
@@ -10019,6 +10067,242 @@ tracepoint_save_command (char *args, int
   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 ("Addresses in location and condition are different.\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 ("Addresses in location and condition are different.\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 ("Addresses in location and condition are different.\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 ("Addresses in location and condition are different.\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) *
Index: gdb/gdb/breakpoint.h
===================================================================
--- gdb.orig/gdb/breakpoint.h	2009-12-23 15:14:03.000000000 -0200
+++ gdb/gdb/breakpoint.h	2009-12-23 17:04:23.000000000 -0200
@@ -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
    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) */
Index: gdb/gdb/ppc-linux-nat.c
===================================================================
--- gdb.orig/gdb/ppc-linux-nat.c	2009-12-23 15:15:13.000000000 -0200
+++ gdb/gdb/ppc-linux-nat.c	2009-12-23 17:04:23.000000000 -0200
@@ -1452,6 +1452,26 @@ ppc_linux_can_use_hw_breakpoint (int typ
 }
 
 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.  */
@@ -1657,6 +1677,76 @@ ppc_linux_remove_hw_breakpoint (struct g
     t = PPC_BREAKPOINT_TRIGGER_READ | PPC_BREAKPOINT_TRIGGER_WRITE;
 
 static int
+ppc_linux_insert_cond_accel_watchpoint (CORE_ADDR addr, int len, int rw,
+					  CORE_ADDR cond)
+{
+  struct ppc_hw_breakpoint p;
+  uint32_t trigger;
+  unsigned long a = (unsigned long) addr,
+		c = (unsigned long) cond;
+  struct lwp_info *lp;
+  ptid_t ptid;
+  int byte_to_enable;
+
+  if (!have_ptrace_new_debug_booke)
+    return -1;
+
+  HW_WATCH_RW_TRIGGER (trigger, rw);
+
+  byte_to_enable = a % 4;
+  c >>= (byte_to_enable * 8);
+
+  p.version         = PPC_DEBUG_CURRENT_VERSION;
+  p.trigger_type    = trigger;
+  p.addr_mode       = PPC_BREAKPOINT_MODE_EXACT;
+  p.condition_mode  = 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;
+  uint32_t trigger;
+  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;
+
+  HW_WATCH_RW_TRIGGER (trigger, rw);
+
+  byte_to_enable = a % 4;
+  c >>= (byte_to_enable * 8);
+
+  p.version         = PPC_DEBUG_CURRENT_VERSION;
+  p.trigger_type    = trigger;
+  p.addr_mode       = PPC_BREAKPOINT_MODE_EXACT;
+  p.condition_mode  = 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;
@@ -1872,6 +1962,52 @@ ppc_linux_watchpoint_addr_within_range (
   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)
@@ -2094,11 +2230,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;
Index: gdb/gdb/target.c
===================================================================
--- gdb.orig/gdb/target.c	2009-12-23 15:14:03.000000000 -0200
+++ gdb/gdb/target.c	2009-12-23 17:04:23.000000000 -0200
@@ -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);
Index: gdb/gdb/target.h
===================================================================
--- gdb.orig/gdb/target.h	2009-12-23 15:14:03.000000000 -0200
+++ gdb/gdb/target.h	2009-12-23 17:06:07.000000000 -0200
@@ -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 p
 #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 p
 #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)
 

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