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


Adds support for the following types of watchpoints:

  * Range Hardware Watchpoints: Monitors accesses to an interval of data
    addresses.  For the 476, a single Range Hardware Watchpoint can be
    used provided that no Simple/Mask watchpoints are being used.

    Available GDB commands:

      watch-range <address1>, <address2>
      watch-range <address1>, +<length>

    Similarly for awatch-range and rwatch-range.

    Examples: 
      watch-range &i,&k
      awatch-range 0xbffff8e8,0xbffff8f8
      rwatch-range 0xbffff8e8,+8

  * Mask Hardware Watchpoints: Monitors accesses to data addresses that
    match a specific pattern.  For the 476, a single Mask Hardware
    Watchpoint can be used provided that no Simple/Range watchpoints are
    being used.  Due to the processor's design, the precise data address
    of the watchpoint trigger is not available, so the user must check the
    instruction that caused the trigger (usually at PC - 4) to obtain
    such data address.  With such data address in hand, it's possible to
    tell if its contents have changed.

    Available GDB commands:

      watch <variable | address> mask <mask_value>

    Similarly for awatch-range and rwatch-range.

    Examples:

      watch i mask 0xffffff00
      awatch *0xbffff8e8 mask 0xffffff00

Since the Simple/Range/Mask Hardware Watchpoints share the same register
set, the allowed combinations are as follows:

  - 2 Simple Hardware Watchpoints with/without data value check
  - 1 Range Hardware Watchpoint
  - 1 Mask Hardware Watchpoint
-- 
[]'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): Add variables to save/restore
	new fields for the new types of hardware breakpoints/watchpoints.
	(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 triggering of a hardware masked
	watchpoint.
	(watchpoint_check): Handle the case of a hardware mased watchpoint
	trigger.
	(hw_watchpoint_used_count): Call to target-specific function
	that will tell how many extra slots a hardware watchpoint needs.
	(mention): Handle mentioning of 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 and ranged watchpoints.
	(ppc_linux_insert_mask_watchpoint): New function.
	(ppc_linux_remove_mask_watchpoint): New function.
	(ppc_linux_insert_watchpoint): Handle ranged watchpoints.
	(ppc_linux_remove_watchpoint): Handle ranged watchpoints.
	(ppc_linux_hw_point_extra_slot_count): New function.
	(_initialize_ppc_linux_nat): Initialize to_insert_mask_watchpoint,
	to_remove_mask_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 and to_hw_point_extra_slot_count.
	* target.h (struct target_ops <to_insert_mask_watchpoint>,
	<to_remove_mask_watchpoint>, <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_hw_point_extra_slot_count): Ditto.
	* value.h (parse_addr_range): Declare.
Index: gdb/gdb/breakpoint.c
===================================================================
--- gdb.orig/gdb/breakpoint.c	2009-12-23 17:07:34.000000000 -0200
+++ gdb/gdb/breakpoint.c	2009-12-23 17:14:52.000000000 -0200
@@ -1059,6 +1059,8 @@ update_watchpoint (struct breakpoint *b,
   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,18 @@ update_watchpoint (struct breakpoint *b,
   if (!watchpoint_in_thread_scope (b))
     return;
 
+  /* We've got to save some special fields before updating
+     this watchpoint.  */
+  switch (b->hw_point_flag)
+    {
+    case HW_POINT_MASKED_WATCH:
+      mask = b->loc->hw_wp_mask;
+      break;
+    case HW_POINT_RANGED_WATCH:
+      range = b->loc->ranged_hw_bp_length;
+      break;
+    }
+
   /* 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.  */
@@ -1262,6 +1276,13 @@ in which its expression is valid.\n"),
       b->disposition = disp_del_at_next_stop;
     }
 
+  /* Restoring some special fields.  */
+  if (b->loc)
+    {
+      b->loc->hw_wp_mask = mask;
+      b->loc->ranged_hw_bp_length = range;
+    }
+
   /* Restore the selected frame.  */
   if (frame_saved)
     select_frame (frame_find_by_id (saved_frame_id));
@@ -1492,7 +1513,12 @@ Note: automatically using hardware break
 	      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_COND_HW_ACCEL)
 	val = target_insert_cond_accel_watchpoint (bpt->address,
 						   bpt->length,
 						   bpt->watchpoint_type,
@@ -2126,7 +2152,11 @@ remove_breakpoint_1 (struct bp_location 
       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);
@@ -2918,13 +2948,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;
@@ -2936,10 +2972,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;
@@ -2953,24 +2997,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 = ");
+	    }
+	}
+      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);
 	}
-      watchpoint_value_print (b->val, stb->stream);
-      ui_out_field_stream (uiout, "new", stb);
+
       ui_out_text (uiout, "\n");
       result = PRINT_UNKNOWN;
       break;
@@ -3179,15 +3238,30 @@ watchpoints_triggered (struct target_wai
 
 	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;
@@ -3290,6 +3364,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.  */
@@ -5821,10 +5900,15 @@ hw_watchpoint_used_count (enum bptype ty
     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;
       }
   }
@@ -6041,6 +6125,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);
@@ -6049,6 +6137,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);
@@ -6057,6 +6149,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);
@@ -7121,74 +7217,143 @@ watch_command_1 (char *arg, int accessfl
   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;
+
+  do {
+      /* 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;
+
+	  /* 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;
+
+	  /* 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;
+
+	  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;
 
-  /* 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;
-
-      /* 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;
-
-      /* 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;
-
-      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;
-
-      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);
+
+	      if (len_addr <= 0)
+		error (_("The mask address is invalid."));
+
+	      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;
@@ -7240,6 +7405,11 @@ watch_command_1 (char *arg, int accessfl
     error (_("Expression cannot be implemented with read/access watchpoint."));
   if (mem_cnt != 0)
     {
+      /* 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);
+
       i = hw_watchpoint_used_count (bp_type, &other_type_used);
       target_resources_ok = 
 	target_can_use_hardware_watchpoint (bp_type, i + mem_cnt, 
@@ -7254,7 +7424,14 @@ watch_command_1 (char *arg, int accessfl
   /* 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);
 
@@ -7302,6 +7479,12 @@ watch_command_1 (char *arg, int accessfl
   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;
+    }
+
   if (cond_start)
     b->cond_string = savestring (cond_start, cond_end - cond_start);
   else
@@ -7387,21 +7570,25 @@ can_use_hardware_watchpoint (struct valu
 	      /* 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));
+		  int ret;
 
-		  if (!target_region_ok_for_hw_watchpoint (vaddr, len))
+		  ret = target_region_ok_for_hw_watchpoint (vaddr, len,
+							    is_big_blob);
+		  if (!ret)
 		    return 0;
 		  else
-		    found_memory_cnt++;
+		    found_memory_cnt += ret;
 		}
 	    }
 	}
@@ -7452,6 +7639,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 can't be watched.  Either the target watchpoint resources\n\
+don't 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,
+						   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
@@ -10852,7 +11134,40 @@ inferior in all-stop mode, gdb behaves a
 			   &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 that range."));
+  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 that range."));
+  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 that range."));
+  set_cmd_completer (c, expression_completer);
+
   automatic_hardware_breakpoints = 1;
 
   observer_attach_about_to_proceed (breakpoint_about_to_proceed);
Index: gdb/gdb/breakpoint.h
===================================================================
--- gdb.orig/gdb/breakpoint.h	2009-12-23 17:04:23.000000000 -0200
+++ gdb/gdb/breakpoint.h	2009-12-23 17:14:52.000000000 -0200
@@ -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.  */
 };
Index: gdb/gdb/findcmd.c
===================================================================
--- gdb.orig/gdb/findcmd.c	2009-12-23 17:04:23.000000000 -0200
+++ gdb/gdb/findcmd.c	2009-12-23 17:09:38.000000000 -0200
@@ -45,6 +45,75 @@ put_bits (bfd_uint64_t data, char *buf, 
     }
 }
 
+/* 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 *m
     }
 
   /* 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.  */
 
Index: gdb/gdb/i386-nat.c
===================================================================
--- gdb.orig/gdb/i386-nat.c	2009-12-23 17:04:23.000000000 -0200
+++ gdb/gdb/i386-nat.c	2009-12-23 17:09:38.000000000 -0200
@@ -530,8 +530,8 @@ i386_remove_watchpoint (CORE_ADDR addr, 
 /* 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;
 
Index: gdb/gdb/ppc-linux-nat.c
===================================================================
--- gdb.orig/gdb/ppc-linux-nat.c	2009-12-23 17:04:23.000000000 -0200
+++ gdb/gdb/ppc-linux-nat.c	2009-12-23 17:14:52.000000000 -0200
@@ -1461,6 +1461,10 @@ ppc_linux_can_use_special_hw_point_p (en
 
   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.  */
@@ -1472,7 +1476,7 @@ ppc_linux_can_use_special_hw_point_p (en
 }
 
 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)
@@ -1483,9 +1487,14 @@ ppc_linux_region_ok_for_hw_watchpoint (C
      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 arbitrary lengths.  This takes
+	 two hardware watchpoints though.  */
+      if (ppc_linux_can_use_special_hw_point_p (HW_POINT_RANGED_WATCH))
+	return is_big_blob ? 2 : 1;
+      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
@@ -1677,6 +1686,65 @@ ppc_linux_remove_hw_breakpoint (struct g
     t = PPC_BREAKPOINT_TRIGGER_READ | PPC_BREAKPOINT_TRIGGER_WRITE;
 
 static int
+ppc_linux_insert_mask_watchpoint (CORE_ADDR addr, int len, int rw,
+				    CORE_ADDR mask)
+{
+  struct ppc_hw_breakpoint p;
+  uint32_t trigger;
+  unsigned long a = (unsigned long) addr,
+		m = (unsigned long) mask;
+  struct lwp_info *lp;
+  ptid_t ptid;
+
+  if (!have_ptrace_new_debug_booke)
+    return -1;
+
+  HW_WATCH_RW_TRIGGER (trigger, rw);
+
+  p.version         = PPC_DEBUG_CURRENT_VERSION;
+  p.trigger_type    = trigger;
+  p.addr_mode       = PPC_BREAKPOINT_MODE_MASK;
+  p.condition_mode  = PPC_BREAKPOINT_CONDITION_NONE;
+  p.addr            = (uint64_t) a;
+  p.addr2           = (uint64_t) m;
+  p.condition_value = 0;
+
+  ALL_LWPS (lp, ptid)
+    booke_insert_point (&p, TIDGET (ptid));
+
+  return 0;
+}
+
+static int
+ppc_linux_remove_mask_watchpoint (CORE_ADDR addr, int len, int rw,
+				    CORE_ADDR mask)
+{
+  struct ppc_hw_breakpoint p;
+  uint32_t trigger;
+  unsigned long a = (unsigned long) addr,
+		m = (unsigned long) mask;
+  struct lwp_info *lp;
+  ptid_t ptid;
+
+  if (!have_ptrace_new_debug_booke)
+    return -1;
+
+  HW_WATCH_RW_TRIGGER (trigger, rw);
+
+  p.version         = PPC_DEBUG_CURRENT_VERSION;
+  p.trigger_type    = trigger;
+  p.addr_mode       = PPC_BREAKPOINT_MODE_MASK;
+  p.condition_mode  = PPC_BREAKPOINT_CONDITION_NONE;
+  p.addr            = (uint64_t) a;
+  p.addr2           = (uint64_t) m;
+  p.condition_value = 0;
+
+  ALL_LWPS (lp, ptid)
+    booke_remove_point (&p, TIDGET (ptid));
+
+  return 0;
+}
+static int
 ppc_linux_insert_cond_accel_watchpoint (CORE_ADDR addr, int len, int rw,
 					  CORE_ADDR cond)
 {
@@ -1755,12 +1823,12 @@ ppc_linux_insert_watchpoint (CORE_ADDR a
 
   if (have_ptrace_new_debug_booke)
     {
+      struct ppc_hw_breakpoint p;
+      uint32_t trigger;
+
       if (len <= 4)
 	ALL_LWPS (lp, ptid)
 	  {
-	    struct ppc_hw_breakpoint p;
-	    uint32_t trigger;
-
 	    HW_WATCH_RW_TRIGGER (trigger, rw);
 
 	    p.version         = PPC_DEBUG_CURRENT_VERSION;
@@ -1773,6 +1841,21 @@ ppc_linux_insert_watchpoint (CORE_ADDR a
 
 	    booke_insert_point (&p, TIDGET (ptid));
 	  }
+      else
+	ALL_LWPS (lp, ptid)
+	  {
+	    HW_WATCH_RW_TRIGGER (trigger, rw);
+
+	    p.version         = PPC_DEBUG_CURRENT_VERSION;
+	    p.trigger_type    = trigger;
+	    p.addr_mode       = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
+	    p.condition_mode  = PPC_BREAKPOINT_CONDITION_NONE;
+	    p.addr            = (uint64_t) addr;
+	    p.addr2           = (uint64_t) addr + len;
+	    p.condition_value = 0;
+
+	    booke_insert_point (&p, TIDGET (ptid));
+	  }
 
       ret = 0;
     }
@@ -1834,12 +1917,12 @@ ppc_linux_remove_watchpoint (CORE_ADDR a
 
   if (have_ptrace_new_debug_booke)
     {
+      struct ppc_hw_breakpoint p;
+      uint32_t trigger;
+
       if (len <= 4)
 	ALL_LWPS (lp, ptid)
 	  {
-	    struct ppc_hw_breakpoint p;
-	    uint32_t trigger;
-
 	    HW_WATCH_RW_TRIGGER (trigger, rw);
 
 	    p.version         = PPC_DEBUG_CURRENT_VERSION;
@@ -1852,6 +1935,21 @@ ppc_linux_remove_watchpoint (CORE_ADDR a
 
 	    booke_remove_point (&p, TIDGET (ptid));
 	  }
+      else
+	ALL_LWPS (lp, ptid)
+	  {
+	    HW_WATCH_RW_TRIGGER (trigger, rw);
+
+	    p.version         = PPC_DEBUG_CURRENT_VERSION;
+	    p.trigger_type    = trigger;
+	    p.addr_mode       = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
+	    p.condition_mode  = PPC_BREAKPOINT_CONDITION_NONE;
+	    p.addr            = (uint64_t) addr;
+	    p.addr2           = (uint64_t) addr + len;
+	    p.condition_value = 0;
+
+	    booke_remove_point (&p, TIDGET (ptid));
+	  }
 
       ret = 0;
     }
@@ -2008,6 +2106,30 @@ ppc_linux_can_use_watchpoint_cond_accel_
   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)
@@ -2240,11 +2362,14 @@ _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_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;
Index: gdb/gdb/target.c
===================================================================
--- gdb.orig/gdb/target.c	2009-12-23 17:04:23.000000000 -0200
+++ gdb/gdb/target.c	2009-12-23 17:09:38.000000000 -0200
@@ -53,7 +53,7 @@ static void default_terminal_info (char 
 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
 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,8 @@ update_current_target (void)
       INHERIT (to_remove_hw_breakpoint, t);
       INHERIT (to_insert_watchpoint, t);
       INHERIT (to_remove_watchpoint, t);
+      INHERIT (to_insert_mask_watchpoint, t);
+      INHERIT (to_remove_mask_watchpoint, t);
       INHERIT (to_insert_cond_accel_watchpoint, t);
       INHERIT (to_remove_cond_accel_watchpoint, t);
       INHERIT (to_get_watchpoint_cond_accel_addr, t);
@@ -635,6 +637,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 +751,12 @@ update_current_target (void)
   de_fault (to_remove_watchpoint,
 	    (int (*) (CORE_ADDR, int, int))
 	    return_minus_one);
+  de_fault (to_insert_mask_watchpoint,
+            (int (*) (CORE_ADDR, int, int, CORE_ADDR))
+            return_minus_one);
+  de_fault (to_remove_mask_watchpoint,
+            (int (*) (CORE_ADDR, int, int, CORE_ADDR))
+            return_minus_one);
   de_fault (to_insert_cond_accel_watchpoint,
 	    (int (*) (CORE_ADDR, int, int, CORE_ADDR))
 	    return_minus_one);
@@ -764,6 +773,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 +2630,7 @@ Can't determine the current address spac
 }
 
 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 +3160,11 @@ debug_to_can_use_hw_breakpoint (int type
 }
 
 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",
Index: gdb/gdb/target.h
===================================================================
--- gdb.orig/gdb/target.h	2009-12-23 17:06:07.000000000 -0200
+++ gdb/gdb/target.h	2009-12-23 17:09:38.000000000 -0200
@@ -411,6 +411,8 @@ 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_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 +423,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 +1199,8 @@ extern char *normal_pid_to_str (ptid_t p
  (*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 +1232,17 @@ 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 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 +1270,11 @@ 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)
 
+#ifndef target_hw_point_extra_slot_count
+#define target_hw_point_extra_slot_count(flag) \
+  (*current_target.to_hw_point_extra_slot_count) (flag)
+#endif
+
 /* Target can execute in reverse?  */
 #define target_can_execute_reverse \
      (current_target.to_can_execute_reverse ? \
Index: gdb/gdb/value.h
===================================================================
--- gdb.orig/gdb/value.h	2009-12-23 17:04:23.000000000 -0200
+++ gdb/gdb/value.h	2009-12-23 17:09:38.000000000 -0200
@@ -521,6 +521,9 @@ extern CORE_ADDR parse_and_eval_address_
 
 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: gdb/gdb/spu-multiarch.c
===================================================================
--- gdb.orig/gdb/spu-multiarch.c	2009-12-23 17:04:23.000000000 -0200
+++ gdb/gdb/spu-multiarch.c	2009-12-23 17:09:38.000000000 -0200
@@ -121,7 +121,7 @@ spu_thread_architecture (struct target_o
 
 /* Override the to_region_ok_for_hw_watchpoint routine.  */
 static int
-spu_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
+spu_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len, int is_big_blob)
 {
   struct target_ops *ops_beneath = find_target_beneath (&spu_ops);
   while (ops_beneath && !ops_beneath->to_region_ok_for_hw_watchpoint)
@@ -132,7 +132,8 @@ spu_region_ok_for_hw_watchpoint (CORE_AD
     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;
 }

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