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 3/4] Support ranged and masked watchpoints


On Wed 23 Dec 2009 22:31:06 Thiago Jung Bauermann wrote:
> Adds support for the following types of watchpoints:

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): Add variables to save/restore
	new fields for the new types of hardware breakpoints/watchpoints.
	Call target_hw_point_extra_slot_count.
	(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.
	(print_it_typical): Handle printing of masked watchpoints.
	(watchpoints_triggered): Handle the case of a hardware masked
	watchpoint trigger.
	(watchpoint_check): Handle the case of a hardware masked watchpoint
	trigger.
	(hw_watchpoint_used_count): Call target-specific function that will
	tell how many extra slots a hardware watchpoint needs.
	(mention): Mention masked watchpoints.
	(watch_command_1): Add a routine to check for the existence of the
	`mask' parameter when the user creates a watchpoint.
	(can_use_hardware_watchpoint): Add code to check if the memory
	that is going to be watched is big, i.e., it needs a hardware ranged
	watchpoint.
	(watch_range_command_1): New function.
	(watch_range_command): Ditto.
	(awatch_range_command): Ditto.
	(rwatch_range_command): Ditto.
	(_initialize_breakpoint): Register watch-range, awatch-range and
	rwatch-range commands.
	* breakpoint.h (struct bp_location) <ranged_hw_bp_length>,
	<hw_wp_mask>: New fields.
	(hw_point_flag) <HW_POINT_RANGED_WATCH>, <HW_POINT_MASKED_WATCH>: New values.
	* findcmd.c (parse_addr_range): New function.
	(parse_find_args): Call `parse_addr_range'.
	* i386-nat.c (i386_region_ok_for_watchpoint): Add `is_big_blob'
	parameter.
	* spu-multiarch.c (spu_region_ok_for_hw_watchpoint): Ditto.
	* ppc-linux-nat.c (ppc_linux_can_use_special_hw_point_p): Handle
	HW_POINT_RANGED_WATCH and HW_POINT_MASKED_WATCH cases.
	(ppc_linux_region_ok_for_hw_watchpoint): Add the `is_big_blob'
	parameter.
	(ppc_linux_insert_mask_watchpoint): New function.
	(ppc_linux_remove_mask_watchpoint): New function.
	(ppc_linux_insert_ranged_watchpoint): New function.
	(ppc_linux_remove_ranged_watchpoint): New function.
	(ppc_linux_hw_point_extra_slot_count): New function.
	(_initialize_ppc_linux_nat): Initialize to_insert_mask_watchpoint,
	to_remove_mask_watchpoint, to_insert_ranged_watchpoint,
	to_remove_ranged_watchpoint and hw_point_extra_slot_count.
	* target.c (default_region_ok_for_hw_watchpoint): Add `is_big_blob'
	parameter.
	(debug_to_region_ok_for_hw_watchpoint): Ditto.
	(update_current_target): Insert to_insert_mask_watchpoint,
	to_remove_mask_watchpoint, to_insert_ranged_watchpoint,
	to_remove_ranged_watchpoint  and to_hw_point_extra_slot_count.
	* target.h (struct target_ops <to_insert_mask_watchpoint>,
	<to_remove_mask_watchpoint>, <to_insert_ranged_watchpoint>,
	<to_remove_ranged_watchpoint> and <to_hw_point_extra_slot_count>): New
	callbacks.
	(target_region_ok_for_hw_watchpoint): Add `is_big_blob' parameter.
	(target_insert_mask_watchpoint): New define.
	(target_remove_mask_watchpoint): Ditto.
	(target_insert_ranged_watchpoint): New define.
	(target_remove_ranged_watchpoint): Ditto.
	(target_hw_point_extra_slot_count): Ditto.
	* value.h (parse_addr_range): Declare.
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index cdd2997..66e0c8e 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -1059,6 +1059,8 @@ update_watchpoint (struct breakpoint *b, int reparse)
   struct bp_location *loc;
   int frame_saved;
   bpstat bs;
+  CORE_ADDR mask = 0;
+  ULONGEST range = 0;
 
   /* If this is a local watchpoint, we only want to check if the
      watchpoint frame is in scope if the current thread is the thread
@@ -1066,6 +1068,11 @@ update_watchpoint (struct breakpoint *b, int reparse)
   if (!watchpoint_in_thread_scope (b))
     return;
 
+  if (b->loc)
+    /* We've got to save the mask field before updating this watchpoint
+       (and consequently busting b->loc).  */
+    mask = b->loc->hw_wp_mask;
+
   /* We don't free locations.  They are stored in bp_location array and
      update_global_locations will eventually delete them and remove
      breakpoints if needed.  */
@@ -1167,8 +1174,11 @@ update_watchpoint (struct breakpoint *b, int reparse)
 	      b->type = bp_watchpoint;
 	    else
 	      {
-		int target_resources_ok = target_can_use_hardware_watchpoint
-		  (bp_hardware_watchpoint, i + mem_cnt, other_type_used);
+		int target_resources_ok;
+
+		mem_cnt += target_hw_point_extra_slot_count (b->hw_point_flag);
+		target_resources_ok =  target_can_use_hardware_watchpoint
+		  (bp_hardware_watchpoint, i + mem_cnt, other_type_used)
 		if (target_resources_ok <= 0)
 		  b->type = bp_watchpoint;
 		else
@@ -1260,6 +1270,10 @@ in which its expression is valid.\n"),
       b->disposition = disp_del_at_next_stop;
     }
 
+  /* Restoring hw_wp_mask.  */
+  if (b->loc)
+    b->loc->hw_wp_mask = mask;
+
   /* Restore the selected frame.  */
   if (frame_saved)
     select_frame (frame_find_by_id (saved_frame_id));
@@ -1490,7 +1504,16 @@ 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)
     {
-      if (bpt->owner->hw_point_flag == HW_POINT_COND_HW_ACCEL)
+      if (bpt->owner->hw_point_flag == HW_POINT_MASKED_WATCH)
+	val = target_insert_mask_watchpoint (bpt->address,
+					     bpt->length,
+					     bpt->watchpoint_type,
+					     bpt->hw_wp_mask);
+      else if (bpt->owner->hw_point_flag == HW_POINT_RANGED_WATCH)
+	val = target_insert_ranged_watchpoint (bpt->address,
+					       bpt->length,
+					       bpt->watchpoint_type);
+      else if (bpt->owner->hw_point_flag == HW_POINT_COND_HW_ACCEL)
 	val = target_insert_cond_accel_watchpoint (bpt->address,
 						   bpt->length,
 						   bpt->watchpoint_type,
@@ -2124,10 +2147,17 @@ remove_breakpoint_1 (struct bp_location *b, insertion_state_t is)
       struct value *n;
 
       b->inserted = (is == mark_inserted);
-      if (b->owner->hw_point_flag == HW_POINT_COND_HW_ACCEL)
+      if (b->owner->hw_point_flag == HW_POINT_MASKED_WATCH)
+	val = target_remove_mask_watchpoint (b->address, b->length,
+					     b->watchpoint_type,
+					     b->hw_wp_mask);
+      else 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 if (b->owner->hw_point_flag == HW_POINT_RANGED_WATCH)
+	val = target_remove_ranged_watchpoint (b->address, b->length,
+					       b->watchpoint_type);
       else
 	val = target_remove_watchpoint (b->address, b->length,
 					b->watchpoint_type);
@@ -2916,13 +2946,19 @@ print_it_typical (bpstat bs)
 	  (uiout, "reason",
 	   async_reason_lookup (EXEC_ASYNC_WATCHPOINT_TRIGGER));
       mention (b);
-      make_cleanup_ui_out_tuple_begin_end (uiout, "value");
-      ui_out_text (uiout, "\nOld value = ");
-      watchpoint_value_print (bs->old_val, stb->stream);
-      ui_out_field_stream (uiout, "old", stb);
-      ui_out_text (uiout, "\nNew value = ");
-      watchpoint_value_print (b->val, stb->stream);
-      ui_out_field_stream (uiout, "new", stb);
+      if (b->hw_point_flag == HW_POINT_MASKED_WATCH)
+	ui_out_text (uiout, "\nCheck the underlying instruction \
+at PC for address and value related to this watchpoint trigger.\n");
+      else
+	{
+	  make_cleanup_ui_out_tuple_begin_end (uiout, "value");
+	  ui_out_text (uiout, "\nOld value = ");
+	  watchpoint_value_print (bs->old_val, stb->stream);
+	  ui_out_field_stream (uiout, "old", stb);
+	  ui_out_text (uiout, "\nNew value = ");
+	  watchpoint_value_print (b->val, stb->stream);
+	  ui_out_field_stream (uiout, "new", stb);
+	}
       ui_out_text (uiout, "\n");
       /* More than one watchpoint may have been triggered.  */
       result = PRINT_UNKNOWN;
@@ -2934,10 +2970,18 @@ print_it_typical (bpstat bs)
 	  (uiout, "reason",
 	   async_reason_lookup (EXEC_ASYNC_READ_WATCHPOINT_TRIGGER));
       mention (b);
-      make_cleanup_ui_out_tuple_begin_end (uiout, "value");
-      ui_out_text (uiout, "\nValue = ");
-      watchpoint_value_print (b->val, stb->stream);
-      ui_out_field_stream (uiout, "value", stb);
+
+      if (b->hw_point_flag == HW_POINT_MASKED_WATCH)
+	ui_out_text (uiout, "\nCheck the underlying instruction\
+ at PC for address and value related to this watchpoint trigger.\n");
+      else
+	{
+	  make_cleanup_ui_out_tuple_begin_end (uiout, "value");
+	  ui_out_text (uiout, "\nValue = ");
+	  watchpoint_value_print (b->val, stb->stream);
+	  ui_out_field_stream (uiout, "value", stb);
+	}
+
       ui_out_text (uiout, "\n");
       result = PRINT_UNKNOWN;
       break;
@@ -2951,24 +2995,39 @@ print_it_typical (bpstat bs)
 	      (uiout, "reason",
 	       async_reason_lookup (EXEC_ASYNC_ACCESS_WATCHPOINT_TRIGGER));
 	  mention (b);
-	  make_cleanup_ui_out_tuple_begin_end (uiout, "value");
-	  ui_out_text (uiout, "\nOld value = ");
-	  watchpoint_value_print (bs->old_val, stb->stream);
-	  ui_out_field_stream (uiout, "old", stb);
-	  ui_out_text (uiout, "\nNew value = ");
+
+	  if (b->hw_point_flag != HW_POINT_MASKED_WATCH)
+	    {
+	      make_cleanup_ui_out_tuple_begin_end (uiout, "value");
+	      ui_out_text (uiout, "\nOld value = ");
+	      watchpoint_value_print (bs->old_val, stb->stream);
+	      ui_out_field_stream (uiout, "old", stb);
+	      ui_out_text (uiout, "\nNew value = ");
+	    }
 	}
       else 
 	{
 	  mention (b);
-	  if (ui_out_is_mi_like_p (uiout))
-	    ui_out_field_string
-	      (uiout, "reason",
-	       async_reason_lookup (EXEC_ASYNC_ACCESS_WATCHPOINT_TRIGGER));
-	  make_cleanup_ui_out_tuple_begin_end (uiout, "value");
-	  ui_out_text (uiout, "\nValue = ");
+
+	  if (b->hw_point_flag != HW_POINT_MASKED_WATCH)
+	    {
+	      if (ui_out_is_mi_like_p (uiout))
+		ui_out_field_string
+		  (uiout, "reason",
+		   async_reason_lookup (EXEC_ASYNC_ACCESS_WATCHPOINT_TRIGGER));
+	      make_cleanup_ui_out_tuple_begin_end (uiout, "value");
+	      ui_out_text (uiout, "\nValue = ");
+	    }
 	}
-      watchpoint_value_print (b->val, stb->stream);
-      ui_out_field_stream (uiout, "new", stb);
+      if (b->hw_point_flag == HW_POINT_MASKED_WATCH)
+	ui_out_text (uiout, "\nCheck the underlying instruction\
+ at PC for address and value related to this watchpoint trigger.\n");
+      else
+	{
+	  watchpoint_value_print (b->val, stb->stream);
+	  ui_out_field_stream (uiout, "new", stb);
+	}
+
       ui_out_text (uiout, "\n");
       result = PRINT_UNKNOWN;
       break;
@@ -3177,15 +3236,30 @@ watchpoints_triggered (struct target_waitstatus *ws)
 
 	b->watchpoint_triggered = watch_triggered_no;
 	for (loc = b->loc; loc; loc = loc->next)
-	  /* Exact match not required.  Within range is
-	     sufficient.  */
-	  if (target_watchpoint_addr_within_range (&current_target,
-						   addr, loc->address,
-						   loc->length))
-	    {
-	      b->watchpoint_triggered = watch_triggered_yes;
-	      break;
-	    }
+	  {
+	    CORE_ADDR newaddr, start;
+
+	    if (loc->owner->hw_point_flag == HW_POINT_MASKED_WATCH)
+	      {
+		newaddr = addr & loc->hw_wp_mask;
+		start = loc->address & loc->hw_wp_mask;
+	      }
+	    else
+	      {
+		newaddr = addr;
+		start = loc->address;
+	      }
+
+	    /* Exact match not required.  Within range is
+	       sufficient.  */
+	    if (target_watchpoint_addr_within_range (&current_target,
+						     newaddr, start,
+						     loc->length))
+	      {
+		b->watchpoint_triggered = watch_triggered_yes;
+		break;
+	      }
+	  }
       }
 
   return 1;
@@ -3295,6 +3369,11 @@ watchpoint_check (void *p)
 	  /* We will stop here */
 	  return WP_VALUE_CHANGED;
 	}
+      else if (b->hw_point_flag == HW_POINT_MASKED_WATCH)
+	/* Since we don't know the exact trigger address (from
+	   stopped_data_address) Just tell the user we've triggered
+	   a mask watchpoint.  */
+	return WP_VALUE_CHANGED;
       else
 	{
 	  /* Nothing changed, don't do anything.  */
@@ -5839,10 +5918,15 @@ hw_watchpoint_used_count (enum bptype type, int *other_type_used)
     if (breakpoint_enabled (b))
       {
 	if (b->type == type)
-	  i++;
-	else if ((b->type == bp_hardware_watchpoint
-		  || b->type == bp_read_watchpoint
-		  || b->type == bp_access_watchpoint))
+	  {
+	    i++;
+	    /* Special types of hardware watchpoints can use more
+	       than one slot.  */
+	    i += target_hw_point_extra_slot_count (b->hw_point_flag);
+	  }
+	else if ((b->type == bp_hardware_watchpoint ||
+		  b->type == bp_read_watchpoint ||
+		  b->type == bp_access_watchpoint))
 	  *other_type_used = 1;
       }
   }
@@ -6059,6 +6143,10 @@ mention (struct breakpoint *b)
 	do_cleanups (ui_out_chain);
 	break;
       case bp_hardware_watchpoint:
+	if (b->hw_point_flag == HW_POINT_MASKED_WATCH)
+	  ui_out_text (uiout, "Mask ");
+	else if (b->hw_point_flag == HW_POINT_RANGED_WATCH)
+	  ui_out_text (uiout, "Range ");
 	ui_out_text (uiout, "Hardware watchpoint ");
 	ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt");
 	ui_out_field_int (uiout, "number", b->number);
@@ -6067,6 +6155,10 @@ mention (struct breakpoint *b)
 	do_cleanups (ui_out_chain);
 	break;
       case bp_read_watchpoint:
+	if (b->hw_point_flag == HW_POINT_MASKED_WATCH)
+	  ui_out_text (uiout, "Mask ");
+	else if (b->hw_point_flag == HW_POINT_RANGED_WATCH)
+	  ui_out_text (uiout, "Range ");
 	ui_out_text (uiout, "Hardware read watchpoint ");
 	ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-rwpt");
 	ui_out_field_int (uiout, "number", b->number);
@@ -6075,6 +6167,10 @@ mention (struct breakpoint *b)
 	do_cleanups (ui_out_chain);
 	break;
       case bp_access_watchpoint:
+	if (b->hw_point_flag == HW_POINT_MASKED_WATCH)
+	  ui_out_text (uiout, "Mask ");
+	else if (b->hw_point_flag == HW_POINT_RANGED_WATCH)
+	  ui_out_text (uiout, "Range ");
 	ui_out_text (uiout, "Hardware access (read/write) watchpoint ");
 	ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-awpt");
 	ui_out_field_int (uiout, "number", b->number);
@@ -7139,74 +7235,142 @@ watch_command_1 (char *arg, int accessflag, int from_tty)
   char *exp_start = NULL;
   char *exp_end = NULL;
   char *tok, *id_tok_start, *end_tok;
-  int toklen;
+  int toklen = -1;
   char *cond_start = NULL;
   char *cond_end = NULL;
   int i, other_type_used, target_resources_ok = 0;
   enum bptype bp_type;
   int mem_cnt = 0;
   int thread = -1;
+  /* Flag to indicate whether we are going to use masks for
+     the hardware watchpoint.  */
+  int use_mask = 0;
+  CORE_ADDR hw_wp_mask = 0;
+  /* Whether we are watching an array or struct and hence we will
+     try to use ranged hardware watchpoints, if available.  */
+  int use_ranged = 0;
+
+  do {
+      /* Make sure that we actually have parameters to parse.  */
+      if (arg != NULL && arg[0] != '\0')
+	{
+	  toklen = strlen (arg); /* Size of argument list.  */
 
-  /* Make sure that we actually have parameters to parse.  */
-  if (arg != NULL && arg[0] != '\0')
-    {
-      toklen = strlen (arg); /* Size of argument list.  */
+	  /* Points tok to the end of the argument list.  */
+	  tok = arg + toklen - 1;
 
-      /* Points tok to the end of the argument list.  */
-      tok = arg + toklen - 1;
+	  /* Go backwards in the parameters list. Skip the last parameter.
+	     If we're expecting a 'thread <thread_num>' parameter, this should
+	     be the thread identifier.  */
+	  while (tok > arg && (*tok == ' ' || *tok == '\t'))
+	    tok--;
+	  while (tok > arg && (*tok != ' ' && *tok != '\t'))
+	    tok--;
 
-      /* Go backwards in the parameters list. Skip the last parameter.
-         If we're expecting a 'thread <thread_num>' parameter, this should
-         be the thread identifier.  */
-      while (tok > arg && (*tok == ' ' || *tok == '\t'))
-        tok--;
-      while (tok > arg && (*tok != ' ' && *tok != '\t'))
-        tok--;
+	  /* Points end_tok to the beginning of the last token.  */
+	  id_tok_start = tok + 1;
 
-      /* Points end_tok to the beginning of the last token.  */
-      id_tok_start = tok + 1;
+	  /* Go backwards in the parameters list. Skip one more parameter.
+	     If we're expecting a 'thread <thread_num>' parameter, we should
+	     reach a "thread" token.  */
+	  while (tok > arg && (*tok == ' ' || *tok == '\t'))
+	    tok--;
 
-      /* Go backwards in the parameters list. Skip one more parameter.
-         If we're expecting a 'thread <thread_num>' parameter, we should
-         reach a "thread" token.  */
-      while (tok > arg && (*tok == ' ' || *tok == '\t'))
-        tok--;
+	  end_tok = tok;
 
-      end_tok = tok;
+	  while (tok > arg && (*tok != ' ' && *tok != '\t'))
+	    tok--;
 
-      while (tok > arg && (*tok != ' ' && *tok != '\t'))
-        tok--;
+	  /* Move the pointer forward to skip the whitespace and
+	     calculate the length of the token.  */
+	  tok++;
+	  toklen = end_tok - tok;
 
-      /* Move the pointer forward to skip the whitespace and
-         calculate the length of the token.  */
-      tok++;
-      toklen = end_tok - tok;
-
-      if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0)
-        {
-          /* At this point we've found a "thread" token, which means
-             the user is trying to set a watchpoint that triggers
-             only in a specific thread.  */
-          char *endp;
-
-          /* Extract the thread ID from the next token.  */
-          thread = strtol (id_tok_start, &endp, 0);
-
-          /* Check if the user provided a valid numeric value for the
-             thread ID.  */
-          if (*endp != ' ' && *endp != '\t' && *endp != '\0')
-            error (_("Invalid thread ID specification %s."), id_tok_start);
-
-          /* Check if the thread actually exists.  */
-          if (!valid_thread_id (thread))
-            error (_("Unknown thread %d."), thread);
-
-          /* Truncate the string and get rid of the thread <thread_num>
-             parameter before the parameter list is parsed by the
-             evaluate_expression() function.  */
-          *tok = '\0';
-        }
-    }
+	  if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0)
+	    {
+	      /* At this point we've found a "thread" token, which means
+		 the user is trying to set a watchpoint that triggers
+		 only in a specific thread.  */
+	      char *endp;
+
+	      /* Extract the thread ID from the next token.  */
+	      thread = strtol (id_tok_start, &endp, 0);
+
+	      /* Check if the user provided a valid numeric value for the
+		 thread ID.  */
+	      if (*endp != ' ' && *endp != '\t' && *endp != '\0')
+		error (_("Invalid thread ID specification %s."),
+		       id_tok_start);
+
+	      /* Check if the thread actually exists.  */
+	      if (!valid_thread_id (thread))
+		error (_("Unknown thread %d."), thread);
+
+	      /* Truncate the string and get rid of the thread <thread_num>
+		 parameter before the parameter list is parsed by the
+		 evaluate_expression() function.  */
+	      *tok = '\0';
+	    }
+	  else if (toklen >= 1 && strncmp (tok, "mask", toklen) == 0)
+	    {
+	      /* We've found a "mask" token, which means the user wants to
+		 create a hardware watchpoint that is going to have the mask
+		 facility.  */
+	      char *tokp = tok;
+	      char *addr_p;
+	      char *endp;
+	      char *mask_addr;
+	      int len_addr;
+	      struct value *mask_value;
+	      struct cleanup *clean_mask_addr;
+
+	      /* Does the target support masked watchpoints?  */
+	      if (!target_can_use_special_hw_point_p (HW_POINT_MASKED_WATCH))
+		error (_("This target does not support the usage of masks \
+with hardware watchpoints."));
+
+	      use_mask = 1;
+
+	      /* Skipping the token "mask", and possible spaces.  */
+	      while (!isspace (*tokp) && *tokp != '\0')
+		tokp++;
+	      while (isspace (*tokp))
+		tokp++;
+
+	      if (*tokp == '\0')
+		error (_("You must supply the address that is going to be\n\
+used in the mask."));
+	      addr_p = tokp;
+
+	      while (!isspace (*addr_p) && *addr_p != '\0')
+		addr_p++;
+
+	      len_addr = addr_p - tokp;
+
+	      strtol (tokp, &endp, 16);
+	      /* Check if the user provided a valid numeric value for the
+		 mask address.  */
+	      if (*endp != ' ' && *endp != '\t' && *endp != '\0')
+		error (_("Invalid mask address specification `%s'."), tokp);
+
+	      mask_addr = xstrndup (tokp, len_addr);
+	      clean_mask_addr = make_cleanup (xfree, mask_addr);
+
+	      mask_value = parse_to_comma_and_eval (&mask_addr);
+	      hw_wp_mask = value_as_address (mask_value);
+
+	      /* Truncate the string and get rid of the "mask <address>"
+		 parameter before the parameter list is parsed by the
+		 evaluate_expression() function.  */
+	      *tok = '\0';
+	      do_cleanups (clean_mask_addr);
+	    }
+	  else if (toklen >= 1)
+	    /* There is a token, but it is not recognized.  We should
+	       stop here.  */
+	    break;
+	}
+  } while (toklen >= 1);
 
   /* Parse the rest of the arguments.  */
   innermost_block = NULL;
@@ -7258,6 +7422,22 @@ watch_command_1 (char *arg, int accessflag, int from_tty)
     error (_("Expression cannot be implemented with read/access watchpoint."));
   if (mem_cnt != 0)
     {
+      struct type *vtype = check_typedef (value_type (val));
+
+      /* If we are going to use masks, then we may need more
+	 slots in order to use the hardware watchpoint.  */
+      if (use_mask)
+	mem_cnt += target_hw_point_extra_slot_count (HW_POINT_MASKED_WATCH);
+      /* If we are watching an array or struct, we may be able to do it using
+         a ranged watchpoint.  */
+      else if ((TYPE_CODE (vtype) == TYPE_CODE_STRUCT
+		|| TYPE_CODE (vtype) == TYPE_CODE_ARRAY)
+	       && target_can_use_special_hw_point_p (HW_POINT_RANGED_WATCH))
+	{
+	  use_ranged = 1;
+	  mem_cnt += target_hw_point_extra_slot_count (HW_POINT_RANGED_WATCH);
+	}
+
       i = hw_watchpoint_used_count (bp_type, &other_type_used);
       target_resources_ok = 
 	target_can_use_hardware_watchpoint (bp_type, i + mem_cnt, 
@@ -7272,7 +7452,14 @@ watch_command_1 (char *arg, int accessflag, int from_tty)
   /* Change the type of breakpoint to an ordinary watchpoint if a hardware
      watchpoint could not be set.  */
   if (!mem_cnt || target_resources_ok <= 0)
-    bp_type = bp_watchpoint;
+    {
+      if (use_mask)
+	/* No way to implement a watchpoint that uses mask without
+	   hardware support.  */
+	error (_("Cannot use masks without hardware watchpoints."));
+      else
+	bp_type = bp_watchpoint;
+    }
 
   frame = block_innermost_frame (exp_valid_block);
 
@@ -7320,6 +7507,14 @@ watch_command_1 (char *arg, int accessflag, int from_tty)
   b->exp_string = savestring (exp_start, exp_end - exp_start);
   b->val = val;
   b->val_valid = 1;
+  if (use_mask)
+    {
+      b->loc->hw_wp_mask = hw_wp_mask;
+      b->hw_point_flag = HW_POINT_MASKED_WATCH;
+    }
+  else if (use_ranged)
+      b->hw_point_flag = HW_POINT_RANGED_WATCH;
+
   if (cond_start)
     b->cond_string = savestring (cond_start, cond_end - cond_start);
   else
@@ -7405,18 +7600,20 @@ can_use_hardware_watchpoint (struct value *v)
 	      /* Ahh, memory we actually used!  Check if we can cover
                  it with hardware watchpoints.  */
 	      struct type *vtype = check_typedef (value_type (v));
+	      /* Is the value a struct or array?  */
+	      int is_big_blob = TYPE_CODE (vtype) == TYPE_CODE_STRUCT
+				|| TYPE_CODE (vtype) == TYPE_CODE_ARRAY;
 
 	      /* We only watch structs and arrays if user asked for it
 		 explicitly, never if they just happen to appear in a
 		 middle of some value chain.  */
-	      if (v == head
-		  || (TYPE_CODE (vtype) != TYPE_CODE_STRUCT
-		      && TYPE_CODE (vtype) != TYPE_CODE_ARRAY))
+	      if (v == head || !is_big_blob)
 		{
 		  CORE_ADDR vaddr = value_address (v);
 		  int       len   = TYPE_LENGTH (value_type (v));
 
-		  if (!target_region_ok_for_hw_watchpoint (vaddr, len))
+		  if (!target_region_ok_for_hw_watchpoint (vaddr, len,
+							   is_big_blob))
 		    return 0;
 		  else
 		    found_memory_cnt++;
@@ -7470,6 +7667,101 @@ awatch_command (char *arg, int from_tty)
 {
   watch_command_1 (arg, hw_access, from_tty);
 }
+
+static void
+watch_range_command_1 (char *arg, int accessflag, int from_tty)
+{
+  char *exp_string, *string_p;
+  struct gdbarch *gdbarch = get_current_arch ();
+  int wp_count, other_type_used, can_use_wp, ret, err, mem_cnt;
+  CORE_ADDR start_addr;
+  ULONGEST length;
+  struct breakpoint *b;
+  struct expression *exp;
+  struct symtab_and_line sal;
+  struct value *val;
+  struct cleanup *cleanups;
+  enum bptype type;
+
+  /* Do we support ranged hardware watchpoints?  */
+  if (!target_can_use_special_hw_point_p (HW_POINT_RANGED_WATCH))
+    error (_("This target does not support ranged hardware watchpoints."));
+
+  parse_addr_range (&arg, &start_addr, &length);
+
+  exp_string = string_p = xstrprintf ("{char[%s]} %s", pulongest (length),
+				      paddress (gdbarch, start_addr));
+  exp = parse_exp_1 (&string_p, 0, 0);
+  fetch_watchpoint_value (exp, &val, NULL, NULL);
+  if (val != NULL)
+    release_value (val);
+  cleanups = make_cleanup (xfree, exp_string);
+
+  mem_cnt = can_use_hardware_watchpoint (val);
+  if (mem_cnt < 0)
+    error (_("\
+Provided range cannot be watched.  Either the target watchpoint resources\n\
+do not support it, or hardware watchpoints are disabled in GDB\n\
+(see \"set can-use-hw-watchpoints\")."));
+
+  if (accessflag == hw_read)
+    type = bp_read_watchpoint;
+  else if (accessflag == hw_access)
+    type = bp_access_watchpoint;
+  else
+    type = bp_hardware_watchpoint;
+
+  wp_count = hw_watchpoint_used_count (type,
+				       &other_type_used);
+  can_use_wp = target_can_use_hardware_watchpoint (type,
+						   wp_count + mem_cnt + 1,
+						   other_type_used);
+  if (can_use_wp < 0)
+    error (_("Not enough hardware resources for specified watchpoint."));
+
+  init_sal (&sal);		/* initialize to zeroes */
+  sal.pspace = current_program_space;
+
+  /* Now set up the breakpoint.  */
+  b = set_raw_breakpoint (gdbarch, sal, accessflag);
+  set_breakpoint_count (breakpoint_count + 1);
+  b->number = breakpoint_count;
+  b->thread = -1;
+  b->disposition = disp_donttouch;
+  b->exp = exp;
+  b->exp_string = exp_string;
+  b->hw_point_flag = HW_POINT_RANGED_WATCH;
+  if (val)
+    {
+      b->val = val;
+      b->val_valid = 1;
+    }
+  b->watchpoint_frame = null_frame_id;
+
+  mention (b);
+  update_global_location_list (1);
+
+  discard_cleanups (cleanups);
+}
+
+static void
+watch_range_command (char *arg, int from_tty)
+{
+  watch_range_command_1 (arg, bp_hardware_watchpoint, from_tty);
+}
+
+static void
+awatch_range_command (char *arg, int from_tty)
+{
+  watch_range_command_1 (arg, bp_access_watchpoint, from_tty);
+}
+
+static void
+rwatch_range_command (char *arg, int from_tty)
+{
+  watch_range_command_1 (arg, bp_read_watchpoint, from_tty);
+}
+
 
 
 /* Helper routines for the until_command routine in infcmd.c.  Here
@@ -10878,7 +11170,41 @@ inferior in all-stop mode, gdb behaves as if always-inserted mode is off."),
 			   &show_always_inserted_mode,
 			   &breakpoint_set_cmdlist,
 			   &breakpoint_show_cmdlist);
-  
+
+  c = add_com ("watch-range", class_breakpoint, watch_range_command, _("\
+Set a WRITE hardware watchpoint for an address range.\n\
+The address range should be specified in one of the following formats:\n\
+\n\
+   start-address, end-address\n\
+   start-address, +length\n\
+\n\
+The watchpoint will stop execution of your program whenever the inferior\n\
+writes to any address within the [start-address, end-address] interval."));
+  set_cmd_completer (c, expression_completer);
+
+  c = add_com ("awatch-range", class_breakpoint, awatch_range_command, _("\
+Set an ACCESS hardware watchpoint for an address range.\n\
+The address range should be specified in one of the following formats:\n\
+\n\
+   start-address, end-address\n\
+   start-address, +length\n\
+\n\
+The watchpoint will stop execution of your program whenever the inferior\n\
+accesses (reads from or writes to) any address within the\n\
+[start-address, end-address] interval."));
+  set_cmd_completer (c, expression_completer);
+
+  c = add_com ("rwatch-range", class_breakpoint, rwatch_range_command, _("\
+Set a READ hardware watchpoint for an address range.\n\
+The address range should be specified in one of the following formats:\n\
+\n\
+   start-address, end-address\n\
+   start-address, +length\n\
+\n\
+The watchpoint will stop execution of your program whenever the inferior\n\
+reads any address within the [start-address, end-address] interval."));
+  set_cmd_completer (c, expression_completer);
+
   automatic_hardware_breakpoints = 1;
 
   observer_attach_about_to_proceed (breakpoint_about_to_proceed);
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index d0c52a9..48b6264 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -262,6 +262,14 @@ struct bp_location
      properly set the evaluation via hardware.  */
   CORE_ADDR cond_hw_addr;
 
+  /* If we are inserting a ranged hardware breakpoint, then we must
+     set its length here.  */
+  ULONGEST ranged_hw_bp_length;
+
+  /* The mask address for this hardware watchpoint.  It is valid only
+    if `hw_wp_use_mask' is 1.  */
+  CORE_ADDR hw_wp_mask;
+
   /* 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.  */
@@ -392,6 +400,8 @@ DEF_VEC_P(bp_location_p);
 /* Special flags for hardware breakpoints/watchpoints.  */
 enum hw_point_flag {
 	HW_POINT_NONE = 0,
+	HW_POINT_RANGED_WATCH, /* Hardware ranged watchpoint.  */
+	HW_POINT_MASKED_WATCH, /* Hardware masked watchpoint.  */
 	HW_POINT_COND_HW_ACCEL,   /* Hardware watchpoint with condition
 				  hardware-accelerated.  */
 };
diff --git a/gdb/findcmd.c b/gdb/findcmd.c
index 1d28914..85f229c 100644
--- a/gdb/findcmd.c
+++ b/gdb/findcmd.c
@@ -45,6 +45,75 @@ put_bits (bfd_uint64_t data, char *buf, int bits, bfd_boolean big_p)
     }
 }
 
+/* Reads an address range, in one of the following formats:
+
+   start-address, end-address
+   start-address, +length
+
+   ARGS will be set to the first character after the end-address or length,
+   or if that character is a comma, the character following it.  If a parser
+   error occurs, an exception is thrown and none of the arguments is
+   touched.  */
+
+void
+parse_addr_range (char **args, CORE_ADDR *start_addrp,
+		  ULONGEST *search_space_lenp)
+{
+  char *s = *args;
+  CORE_ADDR start_addr;
+  ULONGEST search_space_len;
+  struct value *v;
+
+  v = parse_to_comma_and_eval (&s);
+  start_addr = value_as_address (v);
+
+  if (*s == ',')
+    ++s;
+  while (isspace (*s))
+    ++s;
+
+  if (*s == '+')
+    {
+      LONGEST len;
+      ++s;
+      v = parse_to_comma_and_eval (&s);
+      len = value_as_long (v);
+
+      if (len == 0)
+	error (_("Empty search range."));
+      else if (len < 0)
+	error (_("Invalid length."));
+      /* Watch for overflows.  */
+      else if (len > CORE_ADDR_MAX
+	  || (start_addr + len - 1) < start_addr)
+	error (_("Search space too large."));
+
+      search_space_len = len;
+    }
+  else
+    {
+      CORE_ADDR end_addr;
+
+      v = parse_to_comma_and_eval (&s);
+      end_addr = value_as_address (v);
+      if (start_addr > end_addr)
+	error (_("Invalid search space, end preceeds start."));
+      search_space_len = end_addr - start_addr + 1;
+      /* We don't support searching all of memory
+	 (i.e. start=0, end = 0xff..ff).
+	 Bail to avoid overflows later on.  */
+      if (search_space_len == 0)
+	error (_("Overflow in address range computation, choose smaller range."));
+    }
+
+  if (*s == ',')
+    ++s;
+
+  *args = s;
+  *start_addrp = start_addr;
+  *search_space_lenp = search_space_len;
+}
+
 /* Subroutine of find_command to simplify it.
    Parse the arguments of the "find" command.  */
 
@@ -114,51 +183,7 @@ parse_find_args (char *args, ULONGEST *max_countp,
     }
 
   /* Get the search range.  */
-
-  v = parse_to_comma_and_eval (&s);
-  start_addr = value_as_address (v);
-
-  if (*s == ',')
-    ++s;
-  while (isspace (*s))
-    ++s;
-
-  if (*s == '+')
-    {
-      LONGEST len;
-      ++s;
-      v = parse_to_comma_and_eval (&s);
-      len = value_as_long (v);
-      if (len == 0)
-	{
-	  printf_filtered (_("Empty search range.\n"));
-	  return;
-	}
-      if (len < 0)
-	error (_("Invalid length."));
-      /* Watch for overflows.  */
-      if (len > CORE_ADDR_MAX
-	  || (start_addr + len - 1) < start_addr)
-	error (_("Search space too large."));
-      search_space_len = len;
-    }
-  else
-    {
-      CORE_ADDR end_addr;
-      v = parse_to_comma_and_eval (&s);
-      end_addr = value_as_address (v);
-      if (start_addr > end_addr)
-	error (_("Invalid search space, end preceeds start."));
-      search_space_len = end_addr - start_addr + 1;
-      /* We don't support searching all of memory
-	 (i.e. start=0, end = 0xff..ff).
-	 Bail to avoid overflows later on.  */
-      if (search_space_len == 0)
-	error (_("Overflow in address range computation, choose smaller range."));
-    }
-
-  if (*s == ',')
-    ++s;
+  parse_addr_range (&s, &start_addr, &search_space_len);
 
   /* Fetch the search string.  */
 
diff --git a/gdb/i386-nat.c b/gdb/i386-nat.c
index edb78bf..d065c74 100644
--- a/gdb/i386-nat.c
+++ b/gdb/i386-nat.c
@@ -530,8 +530,8 @@ i386_remove_watchpoint (CORE_ADDR addr, int len, int type)
 /* Return non-zero if we can watch a memory region that starts at
    address ADDR and whose length is LEN bytes.  */
 
-static int
-i386_region_ok_for_watchpoint (CORE_ADDR addr, int len)
+int
+i386_region_ok_for_watchpoint (CORE_ADDR addr, int len, int is_big_blob)
 {
   int nregs;
 
diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c
index 4697164..1d072e5 100644
--- a/gdb/ppc-linux-nat.c
+++ b/gdb/ppc-linux-nat.c
@@ -1454,6 +1454,10 @@ ppc_linux_can_use_special_hw_point_p (enum hw_point_flag flag)
 
   switch (flag)
     {
+    case HW_POINT_RANGED_WATCH:
+      return features & PPC_DEBUG_FEATURE_DATA_BP_RANGE;
+    case HW_POINT_MASKED_WATCH:
+      return features & PPC_DEBUG_FEATURE_DATA_BP_MASK;
     case HW_POINT_COND_HW_ACCEL:
       return booke_debug_info.num_condition_regs > 0;
     /* We also accept non-special *points.  */
@@ -1465,7 +1469,7 @@ ppc_linux_can_use_special_hw_point_p (enum hw_point_flag flag)
 }
 
 static int
-ppc_linux_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
+ppc_linux_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len, int is_big_blob)
 {
   /* Handle sub-8-byte quantities.  */
   if (len <= 0)
@@ -1476,9 +1480,20 @@ ppc_linux_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
      to determine the hardcoded watchable region for watchpoints.  */
   if (have_ptrace_new_debug_booke)
     {
-      if (booke_debug_info.data_bp_alignment
-	  && (addr + len > (addr & ~(booke_debug_info.data_bp_alignment - 1))
-	      + booke_debug_info.data_bp_alignment))
+      /* DAC-based processors (i.e., embedded processors), like the PowerPC 440
+	 have ranged watchpoints and can watch any access within an arbitrary
+	 memory region.  This is useful to watch arrays and structs, for
+	 instance.  It takes two hardware watchpoints though.  */
+      if (is_big_blob)
+	{
+	  if (ppc_linux_can_use_special_hw_point_p (HW_POINT_RANGED_WATCH))
+	    return 2;
+	  else
+	    return 0;
+	}
+      else 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;
     }
   /* addr+len must fall in the 8 byte watchable region for DABR-based
@@ -1675,6 +1690,59 @@ static int get_trigger_type (int rw)
 }
 
 static int
+ppc_linux_insert_mask_watchpoint (CORE_ADDR addr, int len, int rw,
+				    CORE_ADDR mask)
+{
+  struct ppc_hw_breakpoint p;
+  unsigned long a = (unsigned long) addr,
+		m = (unsigned long) mask;
+  struct lwp_info *lp;
+  ptid_t ptid;
+
+  if (!have_ptrace_new_debug_booke)
+    return -1;
+
+  p.version         = PPC_DEBUG_CURRENT_VERSION;
+  p.trigger_type    = get_trigger_type (rw);
+  p.addr_mode       = PPC_BREAKPOINT_MODE_MASK;
+  p.condition_mode  = PPC_BREAKPOINT_CONDITION_NONE;
+  p.addr            = (uint64_t) a;
+  p.addr2           = (uint64_t) m;
+  p.condition_value = 0;
+
+  ALL_LWPS (lp, ptid)
+    booke_insert_point (&p, TIDGET (ptid));
+
+  return 0;
+}
+
+static int
+ppc_linux_remove_mask_watchpoint (CORE_ADDR addr, int len, int rw,
+				    CORE_ADDR mask)
+{
+  struct ppc_hw_breakpoint p;
+  unsigned long a = (unsigned long) addr,
+		m = (unsigned long) mask;
+  struct lwp_info *lp;
+  ptid_t ptid;
+
+  if (!have_ptrace_new_debug_booke)
+    return -1;
+
+  p.version         = PPC_DEBUG_CURRENT_VERSION;
+  p.trigger_type    = get_trigger_type (rw);
+  p.addr_mode       = PPC_BREAKPOINT_MODE_MASK;
+  p.condition_mode  = PPC_BREAKPOINT_CONDITION_NONE;
+  p.addr            = (uint64_t) a;
+  p.addr2           = (uint64_t) m;
+  p.condition_value = 0;
+
+  ALL_LWPS (lp, ptid)
+    booke_remove_point (&p, TIDGET (ptid));
+
+  return 0;
+}
+static int
 ppc_linux_insert_cond_accel_watchpoint (CORE_ADDR addr, int len, int rw,
 					  CORE_ADDR cond)
 {
@@ -1739,6 +1807,50 @@ ppc_linux_remove_cond_accel_watchpoint (CORE_ADDR addr, int len, int rw,
 }
 
 static int
+ppc_linux_insert_ranged_watchpoint (CORE_ADDR addr, int len, int rw)
+{
+  struct lwp_info *lp;
+  ptid_t ptid;
+  int ret = -1;
+  struct ppc_hw_breakpoint p;
+
+  p.version         = PPC_DEBUG_CURRENT_VERSION;
+  p.trigger_type    = get_trigger_type (rw);
+  p.addr_mode       = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
+  p.condition_mode  = PPC_BREAKPOINT_CONDITION_NONE;
+  p.addr            = (uint64_t) addr;
+  p.addr2           = (uint64_t) addr + len;
+  p.condition_value = 0;
+
+  ALL_LWPS (lp, ptid)
+    booke_insert_point (&p, TIDGET (ptid));
+
+  return 0;
+} 
+
+static int
+ppc_linux_remove_ranged_watchpoint (CORE_ADDR addr, int len, int rw)
+{
+  struct lwp_info *lp;
+  ptid_t ptid;
+  int ret = -1;
+  struct ppc_hw_breakpoint p;
+
+  p.version         = PPC_DEBUG_CURRENT_VERSION;
+  p.trigger_type    = get_trigger_type (rw);
+  p.addr_mode       = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
+  p.condition_mode  = PPC_BREAKPOINT_CONDITION_NONE;
+  p.addr            = (uint64_t) addr;
+  p.addr2           = (uint64_t) addr + len;
+  p.condition_value = 0;
+
+  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;
@@ -1984,6 +2096,30 @@ ppc_linux_can_use_watchpoint_cond_accel_p (struct bp_location *b)
   return ppc_linux_get_watchpoint_cond_accel_addr (b, &tmp_value);
 }
 
+static int
+ppc_linux_hw_point_extra_slot_count (enum hw_point_flag flag)
+{
+  /* If this *point is a:
+
+     - Masked hardware watchpoint,
+     - Ranged hardware watchpoint
+
+     then it uses 1 extra slot.  */
+  switch (flag)
+    {
+    case HW_POINT_MASKED_WATCH:
+    case HW_POINT_RANGED_WATCH:
+      return 1;
+    default:
+      return 0;
+    }
+
+  /* Otherwise, it is a normal *point and does not use
+     extra slots.  */
+  return 0;
+}
+
+
 static void
 ppc_linux_store_inferior_registers (struct target_ops *ops,
 				    struct regcache *regcache, int regno)
@@ -2216,11 +2352,16 @@ _initialize_ppc_linux_nat (void)
     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_ranged_watchpoint = ppc_linux_insert_ranged_watchpoint;
+  t->to_remove_ranged_watchpoint = ppc_linux_remove_ranged_watchpoint;
+  t->to_insert_mask_watchpoint = ppc_linux_insert_mask_watchpoint;
+  t->to_remove_mask_watchpoint = ppc_linux_remove_mask_watchpoint;
   t->to_insert_cond_accel_watchpoint = ppc_linux_insert_cond_accel_watchpoint;
   t->to_remove_cond_accel_watchpoint = ppc_linux_remove_cond_accel_watchpoint;
   t->to_stopped_by_watchpoint = ppc_linux_stopped_by_watchpoint;
   t->to_stopped_data_address = ppc_linux_stopped_data_address;
   t->to_watchpoint_addr_within_range = ppc_linux_watchpoint_addr_within_range;
+  t->to_hw_point_extra_slot_count = ppc_linux_hw_point_extra_slot_count;
 
   t->to_read_description = ppc_linux_read_description;
   t->to_auxv_parse = ppc_linux_auxv_parse;
diff --git a/gdb/spu-multiarch.c b/gdb/spu-multiarch.c
index cb6b305..87a8974 100644
--- a/gdb/spu-multiarch.c
+++ b/gdb/spu-multiarch.c
@@ -119,7 +119,7 @@ spu_thread_architecture (struct target_ops *ops, ptid_t ptid)
 
 /* Override the to_region_ok_for_hw_watchpoint routine.  */
 static int
-spu_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
+spu_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len, int is_big_blob)
 {
   struct target_ops *ops_beneath = find_target_beneath (&spu_ops);
   while (ops_beneath && !ops_beneath->to_region_ok_for_hw_watchpoint)
@@ -130,7 +130,8 @@ spu_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
     return 0;
 
   if (ops_beneath)
-    return ops_beneath->to_region_ok_for_hw_watchpoint (addr, len);
+    return ops_beneath->to_region_ok_for_hw_watchpoint (addr, len,
+		    is_big_blob);
 
   return 0;
 }
diff --git a/gdb/target.c b/gdb/target.c
index 3b1476d..aff4822 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -53,7 +53,7 @@ static void default_terminal_info (char *, int);
 static int default_watchpoint_addr_within_range (struct target_ops *,
 						 CORE_ADDR, CORE_ADDR, int);
 
-static int default_region_ok_for_hw_watchpoint (CORE_ADDR, int);
+static int default_region_ok_for_hw_watchpoint (CORE_ADDR, int, int);
 
 static int nosymbol (char *, CORE_ADDR *);
 
@@ -131,7 +131,7 @@ static int debug_to_stopped_data_address (struct target_ops *, CORE_ADDR *);
 static int debug_to_watchpoint_addr_within_range (struct target_ops *,
 						  CORE_ADDR, CORE_ADDR, int);
 
-static int debug_to_region_ok_for_hw_watchpoint (CORE_ADDR, int);
+static int debug_to_region_ok_for_hw_watchpoint (CORE_ADDR, int, int);
 
 static void debug_to_terminal_init (void);
 
@@ -626,6 +626,10 @@ update_current_target (void)
       INHERIT (to_remove_hw_breakpoint, t);
       INHERIT (to_insert_watchpoint, t);
       INHERIT (to_remove_watchpoint, t);
+      INHERIT (to_insert_ranged_watchpoint, t);
+      INHERIT (to_remove_ranged_watchpoint, t);
+      INHERIT (to_insert_mask_watchpoint, t);
+      INHERIT (to_remove_mask_watchpoint, t);
       INHERIT (to_insert_cond_accel_watchpoint, t);
       INHERIT (to_remove_cond_accel_watchpoint, t);
       INHERIT (to_get_watchpoint_cond_accel_addr, t);
@@ -635,6 +639,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_hw_point_extra_slot_count, t);
       INHERIT (to_terminal_init, t);
       INHERIT (to_terminal_inferior, t);
       INHERIT (to_terminal_ours_for_output, t);
@@ -748,6 +753,18 @@ update_current_target (void)
   de_fault (to_remove_watchpoint,
 	    (int (*) (CORE_ADDR, int, int))
 	    return_minus_one);
+  de_fault (to_insert_ranged_watchpoint,
+            (int (*) (CORE_ADDR, int, int))
+            return_minus_one);
+  de_fault (to_remove_ranged_watchpoint,
+            (int (*) (CORE_ADDR, int, int))
+            return_minus_one);
+  de_fault (to_insert_mask_watchpoint,
+            (int (*) (CORE_ADDR, int, int, CORE_ADDR))
+            return_minus_one);
+  de_fault (to_remove_mask_watchpoint,
+            (int (*) (CORE_ADDR, int, int, CORE_ADDR))
+            return_minus_one);
   de_fault (to_insert_cond_accel_watchpoint,
 	    (int (*) (CORE_ADDR, int, int, CORE_ADDR))
 	    return_minus_one);
@@ -764,6 +781,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_hw_point_extra_slot_count,
+            (int (*) (enum hw_point_flag))
+            return_zero);
   de_fault (to_get_watchpoint_cond_accel_addr,
 	    (int (*) (struct bp_location *, CORE_ADDR *))
 	    return_zero);
@@ -2618,7 +2638,7 @@ Can't determine the current address space of thread %s\n",
 }
 
 static int
-default_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
+default_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len, int is_big_blob)
 {
   return (len <= gdbarch_ptr_bit (target_gdbarch) / TARGET_CHAR_BIT);
 }
@@ -3148,11 +3168,11 @@ debug_to_can_use_hw_breakpoint (int type, int cnt, int from_tty)
 }
 
 static int
-debug_to_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
+debug_to_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len, int is_big_blob)
 {
   CORE_ADDR retval;
 
-  retval = debug_target.to_region_ok_for_hw_watchpoint (addr, len);
+  retval = debug_target.to_region_ok_for_hw_watchpoint (addr, len, is_big_blob);
 
   fprintf_unfiltered (gdb_stdlog,
 		      "target_region_ok_for_hw_watchpoint (%ld, %ld) = 0x%lx\n",
diff --git a/gdb/target.h b/gdb/target.h
index c604846..f53e655 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -411,6 +411,10 @@ struct target_ops
     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_ranged_watchpoint) (CORE_ADDR, int, int);
+    int (*to_remove_ranged_watchpoint) (CORE_ADDR, int, int);
+    int (*to_insert_mask_watchpoint) (CORE_ADDR, int, int, CORE_ADDR);
+    int (*to_remove_mask_watchpoint) (CORE_ADDR, int, int, CORE_ADDR);
     int (*to_insert_cond_accel_watchpoint) (CORE_ADDR, int, int, CORE_ADDR);
     int (*to_remove_cond_accel_watchpoint) (CORE_ADDR, int, int, CORE_ADDR);
     int (*to_stopped_by_watchpoint) (void);
@@ -421,7 +425,8 @@ 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);
+    int (*to_region_ok_for_hw_watchpoint) (CORE_ADDR, int, int);
+    int (*to_hw_point_extra_slot_count) (enum hw_point_flag);
     void (*to_terminal_init) (void);
     void (*to_terminal_inferior) (void);
     void (*to_terminal_ours_for_output) (void);
@@ -1196,8 +1201,8 @@ extern char *normal_pid_to_str (ptid_t ptid);
  (*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)
+#define target_region_ok_for_hw_watchpoint(addr, len, is_big_blob) \
+    (*current_target.to_region_ok_for_hw_watchpoint) (addr, len, is_big_blob)
 #endif
 
 /* Returns non-zero if the target supports the special type of hardware
@@ -1229,6 +1234,28 @@ 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 ranged watchpoints.  */
+#ifndef target_insert_ranged_watchpoint
+#define target_insert_ranged_watchpoint(addr, len, type) \
+  (*current_target.to_insert_ranged_watchpoint) (addr, len, type)
+#endif
+
+#ifndef target_remove_ranged_watchpoint
+#define target_remove_ranged_watchpoint(addr, len, type) \
+  (*current_target.to_remove_ranged_watchpoint) (addr, len, type)
+#endif
+
+/* Hardware watchpoints with a mask associated.  */
+#ifndef target_insert_mask_watchpoint
+#define target_insert_mask_watchpoint(addr, len, type, mask) \
+  (*current_target.to_insert_mask_watchpoint) (addr, len, type, mask)
+#endif
+
+#ifndef target_remove_mask_watchpoint
+#define target_remove_mask_watchpoint(addr, len, type, mask) \
+  (*current_target.to_remove_mask_watchpoint) (addr, len, type, mask)
+#endif
+
 /* Hardware watchpoint with a condition associated (to be
    hardware-accelerated).  */
 #ifndef target_insert_cond_accel_watchpoint
@@ -1256,6 +1283,11 @@ extern char *normal_pid_to_str (ptid_t ptid);
 #define target_watchpoint_addr_within_range(target, addr, start, length) \
   (*target.to_watchpoint_addr_within_range) (target, addr, start, length)
 
+#ifndef target_hw_point_extra_slot_count
+#define target_hw_point_extra_slot_count(flag) \
+  (*current_target.to_hw_point_extra_slot_count) (flag)
+#endif
+
 /* Target can execute in reverse?  */
 #define target_can_execute_reverse \
      (current_target.to_can_execute_reverse ? \
diff --git a/gdb/value.h b/gdb/value.h
index c0acccd..efef318 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -521,6 +521,9 @@ extern CORE_ADDR parse_and_eval_address_1 (char **expptr);
 
 extern LONGEST parse_and_eval_long (char *exp);
 
+void parse_addr_range (char **args, CORE_ADDR *start_addrp,
+		       ULONGEST *search_space_lenp);
+
 extern void unop_promote (const struct language_defn *language,
 			  struct gdbarch *gdbarch,
 			  struct value **arg1);

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