public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [patch 2/2] Implement support for PowerPC BookE masked and ranged watchpoints
@ 2010-08-17 19:42 Thiago Jung Bauermann
  2010-10-07 14:48 ` Thiago Jung Bauermann
  2010-10-23  4:23 ` Thiago Jung Bauermann
  0 siblings, 2 replies; 19+ messages in thread
From: Thiago Jung Bauermann @ 2010-08-17 19:42 UTC (permalink / raw)
  To: gdb-patches ml

Adds support for the following types of watchpoints:

  * Range Hardware Watchpoints: Monitors accesses to an interval of data
    addresses.  For BookE processors, 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

    (gdb) watch-range 0x10094354,+79
    Ranged hardware watchpoint 4: range: [0x10094354, 0x100943a2]
    (gdb) info breakpoints 
    Num     Type           Disp Enb Address    What
    4       hw watchpoint  keep y              range: [0x10094354, 0x100943a2]

    Also, when the user adds a watchpoint to a structure or array, GDB
    will see if it can automatically set a ranged watchpoint instead:

    (gdb) ptype b
    type = char [79]
    (gdb) watch b
    Ranged hardware watchpoint 2: b
    (gdb) info breakpoints 
    Num     Type           Disp Enb Address    What
    2       hw watchpoint  keep y              b
            memory range: [0x10094354, 0x100943a2]

  * Mask Hardware Watchpoints: Monitors accesses to data addresses that
    match a specific pattern.  For BookE processors, 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

    (gdb) watch a mask 0xffffff00
    Masked hardware watchpoint 5: a
    (gdb) info breakpoints 
    Num     Type           Disp Enb Address    What
    5       hw watchpoint  keep y              a
            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

I could have added a "range" parameter to the watchpoint command instead
of creating a new watch-range command. I don't have a real preference
except. The watch-range command has a slight advantage in that the
syntax used to specify a range is the same already used by the find
command, whereas the other option would be non-standard:

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

Also, Joel made a comment about this patch:

> In this instance as well, I would like to see if we could push all
> the logic to the target, by providing all the information the target
> needs in order to make that decision.
> 
> One nice upside is that this will allow the target to use both range
> watchpoint and condition hardware acceleration if the target allows
> it.
> Or if it doesn't, not separating the two types of features with
> separate target watchpoint_insert/remove routines allows the target
> to choose which one makes most sense if a choice needs to be made.

I prefer to keep the generic GDB code aware of these types of
watchpoints for some reasons:

- I think it's important that GDB reports to the user which type of
  watchpoint was created.
- The user should be able to explicitly create a ranged watchpoint.
- Ditto for masked watchpoints. I don't see how we could automatically
  create those.
- These new types of watchpoints consume 2 debug registers each, so
  there would still have to be some special handling of those when
  counting available hardware resources to see if there's space for one
  more hardware watchpoint (probably new bptypes, but that would mean
  many changes to make these bptypes be handled across GDB, making the
  patch more invasive than this one).

The hunks which change the parsing of parameters in watch_command_1 are
a bit confusing in the diff because of the indentation changes, so I
post below the same hunks without considering whitespace. This makes it
clear what really changed in the code.

Tested on ppc-linux, ppc64-linux and i686-linux with no regressions.
Ok?

===== start of diff ignoring whitespace =====

@@ -8052,8 +8423,8 @@ watch_command_1 (char *arg, int accessflag, int from_tty, int just_location)
   struct frame_info *frame;
   char *exp_start = NULL;
   char *exp_end = NULL;
-  char *tok, *id_tok_start, *end_tok;
-  int toklen;
+  char *tok, *end_tok;
+  int toklen = -1;
   char *cond_start = NULL;
   char *cond_end = NULL;
   int i, other_type_used, target_resources_ok = 0;
@@ -8061,64 +8432,96 @@ watch_command_1 (char *arg, int accessflag, int from_tty, int just_location)
   int mem_cnt = 0;
   int thread = -1;
   int pc = 0;
+  /* 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;
 
   /* 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;
+      char *value_start;
 
-      /* 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.  */
+      /* Look for "parameter value" pairs at the end
+	 of the arguments string.  */
+      for (tok = arg + strlen (arg) - 1; tok > arg; tok--)
+	{
+	  /* Skip whitespace at the end of the argument list.  */
       while (tok > arg && (*tok == ' ' || *tok == '\t'))
         tok--;
+
+	  /* Find the beginning of the last token.
+	     This is the value of the parameter.  */
       while (tok > arg && (*tok != ' ' && *tok != '\t'))
         tok--;
+	  value_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.  */
+	  /* Skip whitespace.  */
       while (tok > arg && (*tok == ' ' || *tok == '\t'))
         tok--;
 
       end_tok = tok;
 
+	  /* Find the beginning of the second to last token.
+	     This is the parameter itself.  */
       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;
+	  toklen = end_tok - tok + 1;
 
-      if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0)
+	  if (toklen == 6 && !strncmp (tok, "thread", 6))
         {
           /* 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;
 
+	      if (thread != -1)
+		error(_("You can specify only one thread."));
+
           /* Extract the thread ID from the next token.  */
-          thread = strtol (id_tok_start, &endp, 0);
+	      thread = strtol (value_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);
+		error (_("Invalid thread ID specification %s."), value_start);
 
           /* Check if the thread actually exists.  */
           if (!valid_thread_id (thread))
             error (_("Unknown thread %d."), thread);
+	    }
+	  else if (toklen == 4 && !strncmp (tok, "mask", 4))
+	    {
+	      /* We've found a "mask" token, which means the user wants to
+		 create a hardware watchpoint that is going to have the mask
+		 facility.  */
+	      struct value *mask_value, *mark;
+
+	      /* Does the target support masked watchpoints?  */
+	      if (!target_can_use_special_hw_point (HW_POINT_MASKED_WATCH))
+		error (_("\
+This target does not support the usage of masks with hardware watchpoints."));
+
+	      if (use_mask)
+		error(_("You can specify only one mask."));
+
+	      use_mask = 1;
 
-          /* Truncate the string and get rid of the thread <thread_num>
-             parameter before the parameter list is parsed by the
-             evaluate_expression() function.  */
+	      mark = value_mark ();
+	      mask_value = parse_to_comma_and_eval (&value_start);
+	      hw_wp_mask = value_as_address (mask_value);
+	      value_free_to_mark (mark);
+	    }
+	  else
+	    /* We didn't recognize what we found.  We should stop here.  */
+	    break;
+
+	  /* Truncate the string and get rid of the "parameter value" pair before
+	     the arguments string is parsed by the parse_exp_1 function.  */
           *tok = '\0';
         }
     }

===== end of diff ignoring whitespace =====

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


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

	Implement support for PowerPC BookE masked and ranged watchpoints.

gdb/
	* breakpoint.c (update_watchpoint): Call breakpoint's
	breakpoint_ops.extra_resources_needed if available.
	(watchpoints_triggered): Handle the case of a hardware masked
	watchpoint trigger.
	(watchpoint_check): Handle the case of a hardware masked watchpoint
	trigger.
	(print_one_breakpoint_location): Call breakpoint's
	breakpoint_ops.print_one_detail if available.
	(hw_watchpoint_used_count): Call breakpoint's
	breakpoint_ops.extra_resources_needed if available.
	(insert_ranged_watchpoint, remove_ranged_watchpoint)
	(extra_resources_needed_ranged_watchpoint)
	(print_one_detail_ranged_watchpoint, print_mention_ranged_watchpoint)
	(print_recreate_ranged_watchpoint): New functions.
	(ranged_watchpoint_breakpoint_ops): New structure.
	(insert_masked_watchpoint, remove_masked_watchpoint)
	(extra_resources_needed_masked_watchpoint, print_it_masked_watchpoint)
	(print_one_detail_masked_watchpoint, print_mention_masked_watchpoint)
	(print_recreate_masked_watchpoint, is_masked_watchpoint): New functions.
	(masked_watchpoint_breakpoint_ops): New structure.
	(watch_command_1): Check for the existence of the `mask' parameter.
	Check whether a ranged hardware watchpoint can be used. Set b->ops
	according to the type of hardware watchpoint being created.
	(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 breakpoint_ops) <extra_resources_needed>,
	<print_one_detail>: New methods.  Initialize them to NULL in all
	existing breakpoint_ops instances.
	(struct breakpoint_ops) <print_stop_action>: Add OLD_VAL parameter.
	Update all implementations of the method.
	(enum hw_point_flag): New enumeration.
	(struct breakpoint) <hw_wp_mask>: New field.
	* findcmd.c (parse_addr_range): New function.
	(parse_find_args): Call `parse_addr_range'.
	* ppc-linux-nat.c (ppc_linux_can_use_special_hw_point): New function.
	(ppc_linux_region_ok_for_hw_watchpoint): Always handle regions when
	ranged watchpoints are available.
	(ppc_linux_insert_mask_watchpoint, ppc_linux_remove_mask_watchpoint)
	(ppc_linux_insert_ranged_watchpoint, ppc_linux_remove_ranged_watchpoint)
	(ppc_linux_hw_point_extra_slot_count): New functions.
	(_initialize_ppc_linux_nat): Initialize to_insert_mask_watchpoint,
	to_remove_mask_watchpoint, to_insert_ranged_watchpoint,
	to_remove_ranged_watchpoint, hw_point_extra_slot_count and
	to_can_use_special_hw_point.
	* target.c (update_current_target): Insert to_insert_mask_watchpoint,
	to_remove_mask_watchpoint, to_insert_ranged_watchpoint,
	to_remove_ranged_watchpoint, to_hw_point_extra_slot_count
	and to_can_use_special_hw_point.
	* target.h (enum hw_point_flag): New opaque declaration.
	(struct target_ops) <to_insert_mask_watchpoint>,
	<to_remove_mask_watchpoint>, <to_insert_ranged_watchpoint>,
	<to_remove_ranged_watchpoint>, <to_hw_point_extra_slot_count>,
	<to_can_use_special_hw_point>: New callbacks.
	(target_insert_mask_watchpoint, target_remove_mask_watchpoint)
	(target_insert_ranged_watchpoint, target_remove_ranged_watchpoint)
	(target_hw_point_extra_slot_count, target_can_use_special_hw_point): New
	defines.
	* ui-out.c (ui_out_field_range_core_addr): New function.
	* ui-out.h (ui_out_field_range_core_addr): Declare.
	* value.h (parse_addr_range): Declare.

gdb/doc/
	* gdb.texinfo (Set Watchpoints): Document mask parameter.
	(PowerPC Embedded): Document masked watchpoints and ranged watchpoints.

Index: gdb.git/gdb/ada-lang.c
===================================================================
--- gdb.git.orig/gdb/ada-lang.c	2010-08-17 12:22:54.000000000 -0300
+++ gdb.git/gdb/ada-lang.c	2010-08-17 12:31:28.000000000 -0300
@@ -10620,7 +10620,7 @@ print_recreate_exception (enum exception
 /* Virtual table for "catch exception" breakpoints.  */
 
 static enum print_stop_action
-print_it_catch_exception (struct breakpoint *b)
+print_it_catch_exception (struct breakpoint *b, const struct value *old_val)
 {
   return print_it_exception (ex_catch_exception, b);
 }
@@ -10648,8 +10648,10 @@ static struct breakpoint_ops catch_excep
   NULL, /* insert */
   NULL, /* remove */
   NULL, /* breakpoint_hit */
+  NULL, /* extra_resources_needed */
   print_it_catch_exception,
   print_one_catch_exception,
+  NULL, /* print_one_detail */
   print_mention_catch_exception,
   print_recreate_catch_exception
 };
@@ -10657,7 +10659,8 @@ static struct breakpoint_ops catch_excep
 /* Virtual table for "catch exception unhandled" breakpoints.  */
 
 static enum print_stop_action
-print_it_catch_exception_unhandled (struct breakpoint *b)
+print_it_catch_exception_unhandled (struct breakpoint *b,
+				    const struct value *old_val)
 {
   return print_it_exception (ex_catch_exception_unhandled, b);
 }
@@ -10686,8 +10689,10 @@ static struct breakpoint_ops catch_excep
   NULL, /* insert */
   NULL, /* remove */
   NULL, /* breakpoint_hit */
+  NULL, /* extra_resources_needed */
   print_it_catch_exception_unhandled,
   print_one_catch_exception_unhandled,
+  NULL, /* print_one_detail */
   print_mention_catch_exception_unhandled,
   print_recreate_catch_exception_unhandled
 };
@@ -10695,7 +10700,7 @@ static struct breakpoint_ops catch_excep
 /* Virtual table for "catch assert" breakpoints.  */
 
 static enum print_stop_action
-print_it_catch_assert (struct breakpoint *b)
+print_it_catch_assert (struct breakpoint *b, const struct value *old_val)
 {
   return print_it_exception (ex_catch_assert, b);
 }
@@ -10722,8 +10727,10 @@ static struct breakpoint_ops catch_asser
   NULL, /* insert */
   NULL, /* remove */
   NULL, /* breakpoint_hit */
+  NULL, /* extra_resources_needed */
   print_it_catch_assert,
   print_one_catch_assert,
+  NULL, /* print_one_detail */
   print_mention_catch_assert,
   print_recreate_catch_assert
 };
Index: gdb.git/gdb/breakpoint.c
===================================================================
--- gdb.git.orig/gdb/breakpoint.c	2010-08-17 12:31:24.000000000 -0300
+++ gdb.git/gdb/breakpoint.c	2010-08-17 12:31:28.000000000 -0300
@@ -222,6 +222,8 @@ static void disable_trace_command (char 
 
 static void trace_pass_command (char *, int);
 
+static int is_masked_watchpoint (const struct breakpoint *b);
+
 /* Assuming we're creating a static tracepoint, does S look like a
    static tracepoint marker spec ("-m MARKER_ID")?  */
 #define is_marker_spec(s)						\
@@ -1422,8 +1424,15 @@ update_watchpoint (struct breakpoint *b,
 	      }
 	    else
 	      {
-		int target_resources_ok = target_can_use_hardware_watchpoint
-		  (bp_hardware_watchpoint, i + mem_cnt, other_type_used);
+		int target_resources_ok;
+
+		if (b->ops && b->ops->extra_resources_needed)
+		  mem_cnt += b->ops->extra_resources_needed (b);
+		else if (b->old_ops && b->old_ops->extra_resources_needed)
+		  mem_cnt += b->old_ops->extra_resources_needed (b);
+
+		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;
@@ -3379,7 +3388,7 @@ print_bp_stop_message (bpstat bs)
 	   print_it_typical.  */
 	/* FIXME: how breakpoint can ever be NULL here?  */
 	if (b != NULL && b->ops != NULL && b->ops->print_it != NULL)
-	  return b->ops->print_it (b);
+	  return b->ops->print_it (b, bs->old_val);
 	else
 	  return print_it_typical (bs);
       }
@@ -3511,15 +3520,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 (is_masked_watchpoint (loc->owner))
+	      {
+		newaddr = addr & loc->owner->hw_wp_mask;
+		start = loc->address & loc->owner->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;
@@ -3634,6 +3658,11 @@ watchpoint_check (void *p)
 	  b->val_valid = 1;
 	  return WP_VALUE_CHANGED;
 	}
+      else if (is_masked_watchpoint (b))
+	/* 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.  */
@@ -4688,9 +4717,12 @@ print_one_breakpoint_location (struct br
 	  ui_out_field_int (uiout, "task", b->task);
 	}
     }
-  
+
   ui_out_text (uiout, "\n");
-  
+
+  if (!part_of_multiple && b->ops && b->ops->print_one_detail)
+    b->ops->print_one_detail (b, uiout);
+
   if (!part_of_multiple && b->static_trace_marker_id)
     {
       gdb_assert (b->type == bp_static_tracepoint);
@@ -5851,7 +5883,7 @@ breakpoint_hit_catch_fork (struct breakp
 /* Implement the "print_it" breakpoint_ops method for fork catchpoints.  */
 
 static enum print_stop_action
-print_it_catch_fork (struct breakpoint *b)
+print_it_catch_fork (struct breakpoint *b, const struct value *old_val)
 {
   annotate_catchpoint (b->number);
   printf_filtered (_("\nCatchpoint %d (forked process %d), "),
@@ -5909,8 +5941,10 @@ static struct breakpoint_ops catch_fork_
   insert_catch_fork,
   remove_catch_fork,
   breakpoint_hit_catch_fork,
+  NULL, /* extra_resources_needed */
   print_it_catch_fork,
   print_one_catch_fork,
+  NULL, /* print_one_detail */
   print_mention_catch_fork,
   print_recreate_catch_fork
 };
@@ -5943,7 +5977,7 @@ breakpoint_hit_catch_vfork (struct break
 /* Implement the "print_it" breakpoint_ops method for vfork catchpoints.  */
 
 static enum print_stop_action
-print_it_catch_vfork (struct breakpoint *b)
+print_it_catch_vfork (struct breakpoint *b, const struct value *old_val)
 {
   annotate_catchpoint (b->number);
   printf_filtered (_("\nCatchpoint %d (vforked process %d), "),
@@ -6000,8 +6034,10 @@ static struct breakpoint_ops catch_vfork
   insert_catch_vfork,
   remove_catch_vfork,
   breakpoint_hit_catch_vfork,
+  NULL, /* extra_resources_needed */
   print_it_catch_vfork,
   print_one_catch_vfork,
+  NULL, /* print_one_detail */
   print_mention_catch_vfork,
   print_recreate_catch_vfork
 };
@@ -6121,7 +6157,7 @@ breakpoint_hit_catch_syscall (struct bre
    catchpoints.  */
 
 static enum print_stop_action
-print_it_catch_syscall (struct breakpoint *b)
+print_it_catch_syscall (struct breakpoint *b, const struct value *old_val)
 {
   /* These are needed because we want to know in which state a
      syscall is.  It can be in the TARGET_WAITKIND_SYSCALL_ENTRY
@@ -6281,8 +6317,10 @@ static struct breakpoint_ops catch_sysca
   insert_catch_syscall,
   remove_catch_syscall,
   breakpoint_hit_catch_syscall,
+  NULL, /* extra_resources_needed */
   print_it_catch_syscall,
   print_one_catch_syscall,
+  NULL, /* print_one_detail */
   print_mention_catch_syscall,
   print_recreate_catch_syscall
 };
@@ -6384,7 +6422,7 @@ breakpoint_hit_catch_exec (struct breakp
 }
 
 static enum print_stop_action
-print_it_catch_exec (struct breakpoint *b)
+print_it_catch_exec (struct breakpoint *b, const struct value *old_val)
 {
   annotate_catchpoint (b->number);
   printf_filtered (_("\nCatchpoint %d (exec'd %s), "), b->number,
@@ -6434,8 +6472,10 @@ static struct breakpoint_ops catch_exec_
   insert_catch_exec,
   remove_catch_exec,
   breakpoint_hit_catch_exec,
+  NULL, /* extra_resources_needed */
   print_it_catch_exec,
   print_one_catch_exec,
+  NULL, /* print_one_detail */
   print_mention_catch_exec,
   print_recreate_catch_exec
 };
@@ -6483,7 +6523,14 @@ hw_watchpoint_used_count (enum bptype ty
     if (breakpoint_enabled (b))
       {
 	if (b->type == type)
-	  i++;
+	  {
+	    i++;
+
+	    /* Special types of hardware watchpoints can use more than
+	       one register.  */
+	    if (b->ops && b->ops->extra_resources_needed)
+	      i += b->ops->extra_resources_needed (b);
+	  }
 	else if (is_hardware_watchpoint (b))
 	  *other_type_used = 1;
       }
@@ -8025,12 +8072,336 @@ static struct breakpoint_ops watchpoint_
   insert_watchpoint,
   remove_watchpoint,
   NULL, /* breakpoint_hit */
+  NULL, /* extra_resources_needed */
   NULL, /* print_it */
   NULL, /* print_one */
+  NULL, /* print_one_detail */
   NULL, /* print_mention */
   NULL  /* print_recreate */
 };
 
+/* Implement the "insert" breakpoint_ops method for
+   ranged hardware watchpoints.  */
+
+static int
+insert_ranged_watchpoint (struct bp_location *bpt)
+{
+  return target_insert_ranged_watchpoint (bpt->address,
+					  bpt->length,
+					  bpt->watchpoint_type);
+}
+
+/* Implement the "remove" breakpoint_ops method for
+   ranged hardware watchpoints.  */
+
+static int
+remove_ranged_watchpoint (struct bp_location *bpt)
+{
+  return target_remove_ranged_watchpoint (bpt->address, bpt->length,
+					  bpt->watchpoint_type);
+}
+
+/* Implement the "extra_resources_needed" breakpoint_ops method for
+   ranged hardware watchpoints.  */
+
+static int
+extra_resources_needed_ranged_watchpoint (const struct breakpoint *b)
+{
+  return target_hw_point_extra_slot_count (HW_POINT_RANGED_WATCH);
+}
+
+/* Implement the "print_one_detail" breakpoint_ops method for
+   ranged hardware watchpoints.  */
+
+static void
+print_one_detail_ranged_watchpoint (const struct breakpoint *b, struct ui_out *uiout)
+{
+  /* If there's a separate expression for reparsing, then exp_string is already
+     a nice text set by watch_range_command_1 and was printed earlier.  */
+  if (b->exp_string_reparse)
+    return;
+
+  gdb_assert (b->loc);
+
+  ui_out_text (uiout, "\tmemory range: ");
+  ui_out_field_range_core_addr (uiout, "addr", b->loc->gdbarch,
+				b->loc->address, b->loc->length);
+  ui_out_text (uiout, "\n");
+}
+
+/* Implement the "print_mention" breakpoint_ops method for
+   ranged hardware watchpoints.  */
+
+static void
+print_mention_ranged_watchpoint (struct breakpoint *b)
+{
+  struct cleanup *ui_out_chain;
+
+  switch (b->type)
+    {
+    case bp_hardware_watchpoint:
+      ui_out_text (uiout, "Ranged hardware watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt");
+      break;
+    case bp_read_watchpoint:
+      ui_out_text (uiout, "Ranged hardware read watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-rwpt");
+      break;
+    case bp_access_watchpoint:
+      ui_out_text (uiout, "Ranged hardware access (read/write) watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-awpt");
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  ui_out_field_int (uiout, "number", b->number);
+  ui_out_text (uiout, ": ");
+  ui_out_field_string (uiout, "exp", b->exp_string);
+  do_cleanups (ui_out_chain);
+}
+
+static void
+print_recreate_ranged_watchpoint (struct breakpoint *b, struct ui_file *fp)
+{
+  switch (b->type)
+    {
+    case bp_hardware_watchpoint:
+      if (b->exp_string_reparse)
+	fprintf_unfiltered (fp, "watch-range");
+      else
+	fprintf_unfiltered (fp, "watch");
+      break;
+    case bp_read_watchpoint:
+      if (b->exp_string_reparse)
+	fprintf_unfiltered (fp, "rwatch-range");
+      else
+	fprintf_unfiltered (fp, "rwatch");
+      break;
+    case bp_access_watchpoint:
+      if (b->exp_string_reparse)
+	fprintf_unfiltered (fp, "awatch-range");
+      else
+	fprintf_unfiltered (fp, "awatch");
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  if (b->exp_string_reparse)
+    {
+      char start_addr[40], length[40];
+
+      /* watch_range_command_1 creates the following expression to represent
+	 internally a ranged watchpoint.  */
+      sscanf (b->exp_string_reparse, "{char[ %39s ]} %39s", length, start_addr);
+
+      fprintf_unfiltered (fp, " %s, +%s", start_addr, length);
+    }
+  else
+    fprintf_unfiltered (fp, " %s", b->exp_string);
+}
+
+/* The breakpoint_ops structure to be used in ranged hardware watchpoints.  */
+
+static struct breakpoint_ops ranged_watchpoint_breakpoint_ops =
+{
+  insert_ranged_watchpoint,
+  remove_ranged_watchpoint,
+  NULL, /* breakpoint_hit */
+  extra_resources_needed_ranged_watchpoint,
+  NULL, /* print_it */
+  NULL, /* print_one */
+  print_one_detail_ranged_watchpoint,
+  print_mention_ranged_watchpoint,
+  print_recreate_ranged_watchpoint
+};
+
+/* Implement the "insert" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static int
+insert_masked_watchpoint (struct bp_location *bpt)
+{
+  return target_insert_mask_watchpoint (bpt->address, bpt->owner->hw_wp_mask,
+					bpt->watchpoint_type);
+}
+
+/* Implement the "remove" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static int
+remove_masked_watchpoint (struct bp_location *bpt)
+{
+  return target_remove_mask_watchpoint (bpt->address, bpt->owner->hw_wp_mask,
+				        bpt->watchpoint_type);
+}
+
+/* Implement the "extra_resources_needed" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static int
+extra_resources_needed_masked_watchpoint (const struct breakpoint *b)
+{
+  return target_hw_point_extra_slot_count (HW_POINT_MASKED_WATCH);
+}
+
+/* Implement the "print_it" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+enum print_stop_action
+print_it_masked_watchpoint (struct breakpoint *b, const struct value *old_val)
+{
+  struct ui_stream *stb;
+  struct cleanup *old_chain;
+
+  stb = ui_out_stream_new (uiout);
+  old_chain = make_cleanup_ui_out_stream_delete (stb);
+
+  switch (b->type)
+    {
+    case bp_hardware_watchpoint:
+      annotate_watchpoint (b->number);
+      if (ui_out_is_mi_like_p (uiout))
+	ui_out_field_string
+	  (uiout, "reason",
+	   async_reason_lookup (EXEC_ASYNC_WATCHPOINT_TRIGGER));
+      break;
+
+    case bp_read_watchpoint:
+      if (ui_out_is_mi_like_p (uiout))
+	ui_out_field_string
+	  (uiout, "reason",
+	   async_reason_lookup (EXEC_ASYNC_READ_WATCHPOINT_TRIGGER));
+      break;
+
+    case bp_access_watchpoint:
+      if (old_val != NULL)
+	{
+	  annotate_watchpoint (b->number);
+	  if (ui_out_is_mi_like_p (uiout))
+	    ui_out_field_string
+	      (uiout, "reason",
+	       async_reason_lookup (EXEC_ASYNC_ACCESS_WATCHPOINT_TRIGGER));
+	}
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  mention (b);
+  ui_out_text (uiout, "\nCheck the underlying instruction \
+at PC for address and value related to this watchpoint trigger.\n");
+  ui_out_text (uiout, "\n");
+
+  do_cleanups (old_chain);
+
+  /* More than one watchpoint may have been triggered.  */
+  return PRINT_UNKNOWN;
+}
+
+/* Implement the "print_one_detail" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static void
+print_one_detail_masked_watchpoint (const struct breakpoint *b, struct ui_out *uiout)
+{
+  ui_out_text (uiout, "\tmask ");
+
+  /* I don't know whether it's possible to get here without a b->loc,
+     but we can handle the situation.  */
+  if (b->loc)
+    ui_out_field_core_addr (uiout, "mask", b->loc->gdbarch, b->hw_wp_mask);
+  else
+    ui_out_field_string (uiout, "mask", core_addr_to_string (b->hw_wp_mask));
+
+  ui_out_text (uiout, "\n");
+}
+
+/* Implement the "print_mention" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static void
+print_mention_masked_watchpoint (struct breakpoint *b)
+{
+  struct cleanup *ui_out_chain;
+
+  switch (b->type)
+    {
+    case bp_hardware_watchpoint:
+      ui_out_text (uiout, "Masked hardware watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt");
+      break;
+    case bp_read_watchpoint:
+      ui_out_text (uiout, "Masked hardware read watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-rwpt");
+      break;
+    case bp_access_watchpoint:
+      ui_out_text (uiout, "Masked hardware access (read/write) watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-awpt");
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  ui_out_field_int (uiout, "number", b->number);
+  ui_out_text (uiout, ": ");
+  ui_out_field_string (uiout, "exp", b->exp_string);
+  do_cleanups (ui_out_chain);
+}
+
+static void
+print_recreate_masked_watchpoint (struct breakpoint *b, struct ui_file *fp)
+{
+  char tmp[40];
+
+  switch (b->type)
+    {
+    case bp_hardware_watchpoint:
+      fprintf_unfiltered (fp, "watch");
+      break;
+    case bp_read_watchpoint:
+      fprintf_unfiltered (fp, "rwatch");
+      break;
+    case bp_access_watchpoint:
+      fprintf_unfiltered (fp, "awatch");
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  sprintf_vma (tmp, b->hw_wp_mask);
+  fprintf_unfiltered (fp, " %s mask 0x%s", b->exp_string, tmp);
+}
+
+/* The breakpoint_ops structure to be used in masked hardware watchpoints.  */
+
+static struct breakpoint_ops masked_watchpoint_breakpoint_ops =
+{
+  insert_masked_watchpoint,
+  remove_masked_watchpoint,
+  NULL, /* breakpoint_hit */
+  extra_resources_needed_masked_watchpoint,
+  print_it_masked_watchpoint,
+  NULL, /* print_one */
+  print_one_detail_masked_watchpoint,
+  print_mention_masked_watchpoint,
+  print_recreate_masked_watchpoint
+};
+
+/* Tells whether the given watchpoint is a masked hardware watchpoint.  */
+
+static int
+is_masked_watchpoint (const struct breakpoint *b)
+{
+  return b->ops == &masked_watchpoint_breakpoint_ops;
+}
+
 /* accessflag:  hw_write:  watch write, 
                 hw_read:   watch read, 
 		hw_access: watch access (read or write) */
@@ -8044,8 +8415,8 @@ watch_command_1 (char *arg, int accessfl
   struct frame_info *frame;
   char *exp_start = NULL;
   char *exp_end = NULL;
-  char *tok, *id_tok_start, *end_tok;
-  int toklen;
+  char *tok, *end_tok;
+  int toklen = -1;
   char *cond_start = NULL;
   char *cond_end = NULL;
   int i, other_type_used, target_resources_ok = 0;
@@ -8053,66 +8424,98 @@ watch_command_1 (char *arg, int accessfl
   int mem_cnt = 0;
   int thread = -1;
   int pc = 0;
+  /* 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;
 
   /* Make sure that we actually have parameters to parse.  */
   if (arg != NULL && arg[0] != '\0')
     {
-      toklen = strlen (arg); /* Size of argument list.  */
+      char *value_start;
 
-      /* Points tok to the end of the argument list.  */
-      tok = arg + toklen - 1;
+      /* Look for "parameter value" pairs at the end
+	 of the arguments string.  */
+      for (tok = arg + strlen (arg) - 1; tok > arg; tok--)
+	{
+	  /* Skip whitespace at the end of the argument list.  */
+	  while (tok > arg && (*tok == ' ' || *tok == '\t'))
+	    tok--;
+
+	  /* Find the beginning of the last token.
+	     This is the value of the parameter.  */
+	  while (tok > arg && (*tok != ' ' && *tok != '\t'))
+	    tok--;
+	  value_start = tok + 1;
+
+	  /* Skip whitespace.  */
+	  while (tok > arg && (*tok == ' ' || *tok == '\t'))
+	    tok--;
+
+	  end_tok = tok;
+
+	  /* Find the beginning of the second to last token.
+	     This is the parameter itself.  */
+	  while (tok > arg && (*tok != ' ' && *tok != '\t'))
+	    tok--;
+	  tok++;
+	  toklen = end_tok - tok + 1;
+
+	  if (toklen == 6 && !strncmp (tok, "thread", 6))
+	    {
+	      /* 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;
+
+	      if (thread != -1)
+		error(_("You can specify only one thread."));
+
+	      /* Extract the thread ID from the next token.  */
+	      thread = strtol (value_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."), value_start);
+
+	      /* Check if the thread actually exists.  */
+	      if (!valid_thread_id (thread))
+		error (_("Unknown thread %d."), thread);
+	    }
+	  else if (toklen == 4 && !strncmp (tok, "mask", 4))
+	    {
+	      /* We've found a "mask" token, which means the user wants to
+		 create a hardware watchpoint that is going to have the mask
+		 facility.  */
+	      struct value *mask_value, *mark;
 
-      /* 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--;
+	      /* Does the target support masked watchpoints?  */
+	      if (!target_can_use_special_hw_point (HW_POINT_MASKED_WATCH))
+		error (_("\
+This target does not support the usage of masks with hardware watchpoints."));
 
-      end_tok = tok;
+	      if (use_mask)
+		error(_("You can specify only one mask."));
 
-      while (tok > arg && (*tok != ' ' && *tok != '\t'))
-        tok--;
+	      use_mask = 1;
 
-      /* Move the pointer forward to skip the whitespace and
-         calculate the length of the token.  */
-      tok++;
-      toklen = end_tok - tok;
+	      mark = value_mark ();
+	      mask_value = parse_to_comma_and_eval (&value_start);
+	      hw_wp_mask = value_as_address (mask_value);
+	      value_free_to_mark (mark);
+	    }
+	  else
+	    /* We didn't recognize what we found.  We should stop here.  */
+	    break;
 
-      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';
-        }
+	  /* Truncate the string and get rid of the "parameter value" pair before
+	     the arguments string is parsed by the parse_exp_1 function.  */
+	  *tok = '\0';
+	}
     }
 
   /* Parse the rest of the arguments.  */
@@ -8190,6 +8593,22 @@ watch_command_1 (char *arg, int accessfl
     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 (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, 
@@ -8201,10 +8620,22 @@ watch_command_1 (char *arg, int accessfl
 	error (_("Target can only support one kind of HW watchpoint at a time."));
     }
 
-  /* 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 && !mem_cnt)
+	error (_("Cannot use masks with the given expression."));
+      else if (use_mask && target_resources_ok <= 0)
+	error (_("\
+Cannot use masks without enough available hardware watchpoints (need %d)."),
+	       mem_cnt);
+      else
+	{
+	  /* Change the type of breakpoint to an ordinary watchpoint if a
+	     hardware watchpoint could not be set.  */
+	  bp_type = bp_watchpoint;
+	  use_ranged = 0;
+	}
+    }
 
   frame = block_innermost_frame (exp_valid_block);
 
@@ -8273,7 +8704,16 @@ watch_command_1 (char *arg, int accessfl
     b->exp_string = savestring (exp_start, exp_end - exp_start);
   b->val = val;
   b->val_valid = 1;
-  b->ops = &watchpoint_breakpoint_ops;
+
+  if (use_mask)
+    {
+      b->hw_wp_mask = hw_wp_mask;
+      b->ops = &masked_watchpoint_breakpoint_ops;
+    }
+  else if (use_ranged)
+    b->ops = &ranged_watchpoint_breakpoint_ops;
+  else
+    b->ops = &watchpoint_breakpoint_ops;
 
   if (cond_start)
     b->cond_string = savestring (cond_start, cond_end - cond_start);
@@ -8458,6 +8898,92 @@ awatch_command (char *arg, int from_tty)
 {
   watch_maybe_just_location (arg, hw_access, from_tty);
 }
+
+static void
+watch_range_command_1 (char *arg, enum bptype type, int from_tty)
+{
+  char *exp_string, *string_p;
+  struct gdbarch *gdbarch = get_current_arch ();
+  int wp_count, other_type_used, can_use_wp, mem_cnt, pc = 0;
+  CORE_ADDR start_addr;
+  ULONGEST length;
+  struct breakpoint *b;
+  struct expression *exp;
+  struct symtab_and_line sal;
+  struct value *val;
+  struct cleanup *cleanups;
+
+  /* Do we support ranged hardware watchpoints?  */
+  if (!target_can_use_special_hw_point (HW_POINT_RANGED_WATCH))
+    error (_("This target does not support ranged hardware watchpoints."));
+  /* Did the user specifically forbid us to use hardware watchpoints? */
+  else if (!can_use_hw_watchpoints)
+    error (_("\
+Hardware watchpoints are disabled (see \"set can-use-hw-watchpoints\")."));
+
+  parse_addr_range (&arg, &start_addr, &length);
+
+  /* We need spaces around the brackets in the expression below so that
+     print_it_recreate_ranged_watchpoint can use scanf on it.  */
+  exp_string = string_p = xstrprintf ("{char[ %s ]} %s", pulongest (length),
+				      paddress (gdbarch, start_addr));
+  exp = parse_exp_1 (&string_p, 0, 0);
+  fetch_subexp_value (exp, &pc, &val, NULL, NULL);
+  if (val != NULL)
+    release_value (val);
+  cleanups = make_cleanup (xfree, exp_string);
+
+  mem_cnt = target_hw_point_extra_slot_count (HW_POINT_RANGED_WATCH) + 1;
+
+  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 available hardware watchpoints (need %d)."), mem_cnt);
+
+  init_sal (&sal);		/* initialize to zeroes */
+  sal.pspace = current_program_space;
+
+  /* Now set up the breakpoint.  */
+  b = set_raw_breakpoint (gdbarch, sal, type);
+  set_breakpoint_count (breakpoint_count + 1);
+  b->number = breakpoint_count;
+  b->thread = -1;
+  b->disposition = disp_donttouch;
+  b->exp = exp;
+  b->exp_string_reparse = exp_string;
+  b->exp_string = xstrprintf (_("range [%s, %s]"),
+			      paddress (gdbarch, start_addr),
+			      paddress (gdbarch, start_addr + length - 1));
+  b->ops = &ranged_watchpoint_breakpoint_ops;
+  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);
+}
+
 \f
 
 /* Helper routines for the until_command routine in infcmd.c.  Here
@@ -8695,7 +9221,7 @@ catch_exec_command_1 (char *arg, int fro
 }
 
 static enum print_stop_action
-print_exception_catchpoint (struct breakpoint *b)
+print_exception_catchpoint (struct breakpoint *b, const struct value *old_val)
 {
   int bp_temp, bp_throw;
 
@@ -8784,8 +9310,10 @@ static struct breakpoint_ops gnu_v3_exce
   NULL, /* insert */
   NULL, /* remove */
   NULL, /* breakpoint_hit */
+  NULL, /* extra_resources_needed */
   print_exception_catchpoint,
   print_one_exception_catchpoint,
+  NULL, /* print_one_detail */
   print_mention_exception_catchpoint,
   print_recreate_exception_catchpoint
 };
@@ -12159,7 +12687,41 @@ 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 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 from 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);
Index: gdb.git/gdb/breakpoint.h
===================================================================
--- gdb.git.orig/gdb/breakpoint.h	2010-08-17 12:31:24.000000000 -0300
+++ gdb.git/gdb/breakpoint.h	2010-08-17 12:31:28.000000000 -0300
@@ -26,6 +26,7 @@
 
 struct value;
 struct block;
+struct ui_out;
 
 /* This is the maximum number of bytes a breakpoint instruction can take.
    Feel free to increase it.  It's just used in a few places to size
@@ -356,13 +357,23 @@ struct breakpoint_ops
      breakpoint was hit.  */
   int (*breakpoint_hit) (struct breakpoint *);
 
+  /* Tell how many additional hardware resources (debug registers) are needed
+     for this breakpoint.  We always count at least one resource.  If this
+     element is NULL, then no additional resource is accounted for.  */
+  int (*extra_resources_needed) (const struct breakpoint *);
+
   /* The normal print routine for this breakpoint, called when we
      hit it.  */
-  enum print_stop_action (*print_it) (struct breakpoint *);
+  enum print_stop_action (*print_it) (struct breakpoint *,
+				      const struct value *old_val);
 
   /* Display information about this breakpoint, for "info breakpoints".  */
   void (*print_one) (struct breakpoint *, struct bp_location **);
 
+  /* Display one line of extra information about this breakpoint,
+     for "info breakpoints".  */
+  void (*print_one_detail) (const struct breakpoint *, struct ui_out *);
+
   /* Display information about this breakpoint after setting it (roughly
      speaking; this is called from "mention").  */
   void (*print_mention) (struct breakpoint *);
@@ -395,6 +406,12 @@ DEF_VEC_P(bp_location_p);
    detail to the breakpoints module.  */
 struct counted_command_line;
 
+/* Special types of hardware breakpoints/watchpoints.  */
+enum hw_point_flag {
+	HW_POINT_RANGED_WATCH, /* Hardware ranged watchpoint.  */
+	HW_POINT_MASKED_WATCH  /* Hardware masked watchpoint.  */
+};
+
 /* Note that the ->silent field is not currently used by any commands
    (though the code is in there if it was to be, and set_raw_breakpoint
    does set it to 0).  I implemented it because I thought it would be
@@ -559,6 +576,9 @@ struct breakpoint
        breakpoints, we will use this index to try to find the same
        marker again.  */
     int static_trace_marker_id_idx;
+
+    /* The mask address for a hardware watchpoint.  */
+    CORE_ADDR hw_wp_mask;
   };
 
 typedef struct breakpoint *breakpoint_p;
Index: gdb.git/gdb/doc/gdb.texinfo
===================================================================
--- gdb.git.orig/gdb/doc/gdb.texinfo	2010-08-17 12:30:34.000000000 -0300
+++ gdb.git/gdb/doc/gdb.texinfo	2010-08-17 12:31:28.000000000 -0300
@@ -3711,7 +3711,7 @@ watchpoints, which do not slow down the 
 
 @table @code
 @kindex watch
-@item watch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]}
+@item watch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} @r{[}mask @var{maskvalue}@r{]}
 Set a watchpoint for an expression.  @value{GDBN} will break when the
 expression @var{expr} is written into by the program and its value
 changes.  The simplest (and the most popular) use of this command is
@@ -3728,6 +3728,11 @@ change the value of @var{expr}, @value{G
 that watchpoints restricted to a single thread in this way only work
 with Hardware Watchpoints.
 
+The @code{@r{[}mask @var{maskvalue}@r{]}} clause is used to create a masked
+watchpoint if the current architecture supports the feature (currently,
+only available in the PowerPC Embedded architecture.
+See @ref{PowerPC Embedded}).
+
 Ordinarily a watchpoint respects the scope of variables in @var{expr}
 (see below).  The @code{-location} argument tells @value{GDBN} to
 instead watch the memory referred to by @var{expr}.  In this case,
@@ -3738,12 +3743,12 @@ result does not have an address, then @v
 error.
 
 @kindex rwatch
-@item rwatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]}
+@item rwatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} @r{[}mask @var{maskvalue}@r{]}
 Set a watchpoint that will break when the value of @var{expr} is read
 by the program.
 
 @kindex awatch
-@item awatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]}
+@item awatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} @r{[}mask @var{maskvalue}@r{]}
 Set a watchpoint that will break when @var{expr} is either read from
 or written into by the program.
 
@@ -18483,9 +18488,41 @@ The DVC register will be automatically u
 such pattern in a condition expression.  This feature is available in native
 @value{GDBN} running on a Linux kernel version 2.6.34 or newer.
 
+PowerPC embedded processors support additional types of hardware watchpoints,
+namely masked watchpoints and ranged watchpoints.
+
+A @dfn{masked watchpoint} is defined by an address and a mask.  It triggers
+when the address of a memory access matches the watchpoint address when both
+are masked by the watchpoint mask.  That is, the bits set in the mask determine
+which bits are relevant in the address comparison.  To set a masked watchpoint
+in @value{GDBN}, use the @code{mask} parameter in the @code{watch} command
+(see @ref{Set Watchpoints}), as in:
+
+@smallexample
+(@value{GDBP}) watch *0xdeadbeef mask 0xffffff00
+@end smallexample
+
+A @dfn{ranged watchpoint} is defined by a start address and an end address
+specifying a region of memory inside which any access will trigger the
+watchpoint.  Both the start and end addresses are within the memory region.
+To set a ranged watchpoint in @value{GDBN}, use the @code{watch-range} command.
+
 @value{GDBN} provides the following PowerPC-specific commands:
 
 @table @code
+@kindex watch-range
+@item watch-range @var{start-address, +length}
+@itemx watch-range @var{start-address, end-address}
+@item rwatch-range @var{start-address, +length}
+@itemx rwatch-range @var{start-address, end-address}
+@item awatch-range @var{start-address, +length}
+@itemx awatch-range @var{start-address, end-address}
+Set a hardware watchpoint for an address range.
+The watchpoint will stop execution of your program whenever the inferior
+writes, reads, or accesses (respectively for watch-range, awatch-range
+and rwatch-range) any address within the @code{[start-address, end-address]}
+interval.
+
 @kindex set powerpc
 @item set powerpc soft-float
 @itemx show powerpc soft-float
Index: gdb.git/gdb/findcmd.c
===================================================================
--- gdb.git.orig/gdb/findcmd.c	2010-08-17 12:22:54.000000000 -0300
+++ gdb.git/gdb/findcmd.c	2010-08-17 12:31:28.000000000 -0300
@@ -45,6 +45,79 @@ 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.  Returns 1 on success, or 0 if an empty address range was given.  */
+
+int
+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)
+	{
+	  printf_filtered (_("Empty search range.\n"));
+	  return 0;
+	}
+      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;
+
+  *args = s;
+  *start_addrp = start_addr;
+  *search_space_lenp = search_space_len;
+
+  return 1;
+}
+
 /* Subroutine of find_command to simplify it.
    Parse the arguments of the "find" command.  */
 
@@ -114,53 +187,8 @@ 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;
+  if (!parse_addr_range (&s, &start_addr, &search_space_len))
+    return;
 
   /* Fetch the search string.  */
 
Index: gdb.git/gdb/ppc-linux-nat.c
===================================================================
--- gdb.git.orig/gdb/ppc-linux-nat.c	2010-08-17 12:22:54.000000000 -0300
+++ gdb.git/gdb/ppc-linux-nat.c	2010-08-17 12:31:28.000000000 -0300
@@ -1478,6 +1478,28 @@ ppc_linux_can_use_hw_breakpoint (int typ
 }
 
 static int
+ppc_linux_can_use_special_hw_point (enum hw_point_flag flag)
+{
+  uint64_t features;
+
+  if (!have_ptrace_booke_interface ())
+    return 0;
+
+  features = booke_debug_info.features;
+
+  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;
+      default:
+	internal_error (__FILE__, __LINE__,
+			_("Unknown hardware breakpoint/watchpoint type."));
+    }
+}
+
+static int
 ppc_linux_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
 {
   /* Handle sub-8-byte quantities.  */
@@ -1489,9 +1511,15 @@ ppc_linux_region_ok_for_hw_watchpoint (C
      to determine the hardcoded watchable region for watchpoints.  */
   if (have_ptrace_booke_interface ())
     {
-      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 (ppc_linux_can_use_special_hw_point (HW_POINT_RANGED_WATCH))
+	return 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
@@ -1685,6 +1713,106 @@ get_trigger_type (int rw)
   return t;
 }
 
+static int
+ppc_linux_insert_mask_watchpoint (CORE_ADDR addr, CORE_ADDR mask, int rw)
+{
+  ptid_t ptid;
+  struct lwp_info *lp;
+  struct ppc_hw_breakpoint p;
+
+  gdb_assert (have_ptrace_booke_interface ());
+
+  if ((mask & 0xC0000000) != 0xC0000000)
+    error (_("\
+The given mask covers kernel address space and cannot be used.\n\
+You have to delete the masked watchpoint to continue the debugging session."));
+
+  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) addr;
+  p.addr2           = (uint64_t) mask;
+  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, CORE_ADDR mask, int rw)
+{
+  ptid_t ptid;
+  struct lwp_info *lp;
+  struct ppc_hw_breakpoint p;
+
+  gdb_assert (have_ptrace_booke_interface ());
+
+  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) addr;
+  p.addr2           = (uint64_t) mask;
+  p.condition_value = 0;
+
+  ALL_LWPS (lp, ptid)
+    booke_remove_point (&p, TIDGET (ptid));
+
+  return 0;
+}
+
+static int
+ppc_linux_insert_ranged_watchpoint (CORE_ADDR addr, int len, int rw)
+{
+  ptid_t ptid;
+  struct lwp_info *lp;
+  struct ppc_hw_breakpoint p;
+
+  gdb_assert (have_ptrace_booke_interface ());
+
+  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.condition_value = 0;
+
+  /* The watchpoint will trigger if the address of the memory access is
+     within the defined range, as follows: p.addr <= address < p.addr2.  */
+  p.addr            = (uint64_t) addr;
+  p.addr2           = (uint64_t) addr + len;
+
+  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)
+{
+  ptid_t ptid;
+  struct lwp_info *lp;
+  struct ppc_hw_breakpoint p;
+
+  gdb_assert (have_ptrace_booke_interface ());
+
+  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;
+}
+
 /* Check whether we have at least one free DVC register.  */
 static int
 can_use_watchpoint_cond_accel (void)
@@ -2136,6 +2264,14 @@ ppc_linux_watchpoint_addr_within_range (
   return start <= addr + mask && start + length - 1 >= addr;
 }
 
+static int
+ppc_linux_hw_point_extra_slot_count (enum hw_point_flag flag)
+{
+  gdb_assert (flag == HW_POINT_MASKED_WATCH || flag == HW_POINT_RANGED_WATCH);
+
+  return 1;
+}
+
 static void
 ppc_linux_store_inferior_registers (struct target_ops *ops,
 				    struct regcache *regcache, int regno)
@@ -2347,12 +2483,18 @@ _initialize_ppc_linux_nat (void)
   t->to_insert_hw_breakpoint = ppc_linux_insert_hw_breakpoint;
   t->to_remove_hw_breakpoint = ppc_linux_remove_hw_breakpoint;
   t->to_region_ok_for_hw_watchpoint = ppc_linux_region_ok_for_hw_watchpoint;
+  t->to_can_use_special_hw_point = ppc_linux_can_use_special_hw_point;
   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_stopped_by_watchpoint = ppc_linux_stopped_by_watchpoint;
   t->to_stopped_data_address = ppc_linux_stopped_data_address;
   t->to_watchpoint_addr_within_range = ppc_linux_watchpoint_addr_within_range;
   t->to_can_accel_watchpoint_condition = ppc_linux_can_accel_watchpoint_condition;
+  t->to_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.git/gdb/target.c
===================================================================
--- gdb.git.orig/gdb/target.c	2010-08-17 12:31:24.000000000 -0300
+++ gdb.git/gdb/target.c	2010-08-17 12:31:28.000000000 -0300
@@ -601,11 +601,16 @@ update_current_target (void)
       INHERIT (to_files_info, t);
       INHERIT (to_insert_breakpoint, t);
       INHERIT (to_remove_breakpoint, t);
+      INHERIT (to_can_use_special_hw_point, t);
       INHERIT (to_can_use_hw_breakpoint, t);
       INHERIT (to_insert_hw_breakpoint, t);
       INHERIT (to_remove_hw_breakpoint, t);
       INHERIT (to_insert_watchpoint, t);
       INHERIT (to_remove_watchpoint, t);
+      INHERIT (to_insert_ranged_watchpoint, t);
+      INHERIT (to_remove_ranged_watchpoint, t);
+      INHERIT (to_insert_mask_watchpoint, t);
+      INHERIT (to_remove_mask_watchpoint, t);
       INHERIT (to_stopped_data_address, t);
       INHERIT (to_have_steppable_watchpoint, t);
       INHERIT (to_have_continuable_watchpoint, t);
@@ -613,6 +618,7 @@ update_current_target (void)
       INHERIT (to_watchpoint_addr_within_range, t);
       INHERIT (to_region_ok_for_hw_watchpoint, t);
       INHERIT (to_can_accel_watchpoint_condition, 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);
@@ -727,6 +733,9 @@ update_current_target (void)
   de_fault (to_can_use_hw_breakpoint,
 	    (int (*) (int, int, int))
 	    return_zero);
+  de_fault (to_can_use_special_hw_point,
+	    (int (*) (enum hw_point_flag))
+	    return_zero);
   de_fault (to_insert_hw_breakpoint,
 	    (int (*) (struct gdbarch *, struct bp_target_info *))
 	    return_minus_one);
@@ -739,6 +748,18 @@ update_current_target (void)
   de_fault (to_remove_watchpoint,
 	    (int (*) (CORE_ADDR, int, int, struct expression *))
 	    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, CORE_ADDR, int))
+            return_minus_one);
+  de_fault (to_remove_mask_watchpoint,
+            (int (*) (CORE_ADDR, CORE_ADDR, int))
+            return_minus_one);
   de_fault (to_stopped_by_watchpoint,
 	    (int (*) (void))
 	    return_zero);
@@ -752,6 +773,9 @@ update_current_target (void)
   de_fault (to_can_accel_watchpoint_condition,
             (int (*) (CORE_ADDR, int, int, struct expression *))
             return_zero);
+  de_fault (to_hw_point_extra_slot_count,
+            (int (*) (enum hw_point_flag))
+            return_zero);
   de_fault (to_terminal_init,
 	    (void (*) (void))
 	    target_ignore);
Index: gdb.git/gdb/target.h
===================================================================
--- gdb.git.orig/gdb/target.h	2010-08-17 12:31:24.000000000 -0300
+++ gdb.git/gdb/target.h	2010-08-17 12:31:28.000000000 -0300
@@ -39,6 +39,8 @@ struct static_tracepoint_marker;
 
 struct expression;
 
+enum hw_point_flag;
+
 /* This include file defines the interface between the main part
    of the debugger, and the part which is target-specific, or
    specific to the communications interface between us and the
@@ -438,6 +440,7 @@ struct target_ops
     int (*to_insert_breakpoint) (struct gdbarch *, struct bp_target_info *);
     int (*to_remove_breakpoint) (struct gdbarch *, struct bp_target_info *);
     int (*to_can_use_hw_breakpoint) (int, int, int);
+    int (*to_can_use_special_hw_point) (enum hw_point_flag);
     int (*to_insert_hw_breakpoint) (struct gdbarch *, struct bp_target_info *);
     int (*to_remove_hw_breakpoint) (struct gdbarch *, struct bp_target_info *);
 
@@ -446,6 +449,10 @@ struct target_ops
     int (*to_remove_watchpoint) (CORE_ADDR, int, int, struct expression *);
     int (*to_insert_watchpoint) (CORE_ADDR, int, int, struct expression *);
 
+    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, CORE_ADDR, int);
+    int (*to_remove_mask_watchpoint) (CORE_ADDR, CORE_ADDR, int);
     int (*to_stopped_by_watchpoint) (void);
     int to_have_steppable_watchpoint;
     int to_have_continuable_watchpoint;
@@ -455,6 +462,7 @@ struct target_ops
     int (*to_region_ok_for_hw_watchpoint) (CORE_ADDR, int);
     int (*to_can_accel_watchpoint_condition) (CORE_ADDR, int, int,
 					      struct expression *);
+    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);
@@ -1318,6 +1326,11 @@ extern char *normal_pid_to_str (ptid_t p
 #define target_region_ok_for_hw_watchpoint(addr, len) \
     (*current_target.to_region_ok_for_hw_watchpoint) (addr, len)
 
+/* Returns non-zero if the target supports the special type of hardware
+   breakpoint/watchpoint represented by FLAG.  */
+#define target_can_use_special_hw_point(flag) \
+  (*current_target.to_can_use_special_hw_point) (flag)
+
 
 /* Set/clear a hardware watchpoint starting at ADDR, for LEN bytes.
    TYPE is 0 for write, 1 for read, and 2 for read/write accesses.
@@ -1331,6 +1344,20 @@ extern char *normal_pid_to_str (ptid_t p
 #define	target_remove_watchpoint(addr, len, type, cond) \
      (*current_target.to_remove_watchpoint) (addr, len, type, cond)
 
+/* Hardware ranged watchpoints.  */
+#define target_insert_ranged_watchpoint(addr, len, type) \
+  (*current_target.to_insert_ranged_watchpoint) (addr, len, type)
+
+#define target_remove_ranged_watchpoint(addr, len, type) \
+  (*current_target.to_remove_ranged_watchpoint) (addr, len, type)
+
+/* Hardware watchpoints with an associated address mask.  */
+#define target_insert_mask_watchpoint(addr, mask, type) \
+  (*current_target.to_insert_mask_watchpoint) (addr, mask, type)
+
+#define target_remove_mask_watchpoint(addr, mask, type) \
+  (*current_target.to_remove_mask_watchpoint) (addr, mask, type)
+
 #define target_insert_hw_breakpoint(gdbarch, bp_tgt) \
      (*current_target.to_insert_hw_breakpoint) (gdbarch, bp_tgt)
 
@@ -1359,6 +1386,9 @@ extern char *normal_pid_to_str (ptid_t p
 #define target_can_accel_watchpoint_condition(addr, len, type, cond) \
   (*current_target.to_can_accel_watchpoint_condition) (addr, len, type, cond)
 
+#define target_hw_point_extra_slot_count(flag) \
+  (*current_target.to_hw_point_extra_slot_count) (flag)
+
 /* Target can execute in reverse?  */
 #define target_can_execute_reverse \
      (current_target.to_can_execute_reverse ? \
Index: gdb.git/gdb/ui-out.c
===================================================================
--- gdb.git.orig/gdb/ui-out.c	2010-08-17 12:22:54.000000000 -0300
+++ gdb.git/gdb/ui-out.c	2010-08-17 12:31:28.000000000 -0300
@@ -487,6 +487,46 @@ ui_out_field_fmt_int (struct ui_out *uio
 }
 
 void
+ui_out_field_range_core_addr (struct ui_out *uiout,
+			      const char *fldname,
+			      struct gdbarch *gdbarch,
+			      CORE_ADDR address_start,
+			      CORE_ADDR length)
+{
+  char addstr[80];
+  int addr_bit = gdbarch_addr_bit (gdbarch);
+  CORE_ADDR address_end = address_start + length - 1;
+
+  if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT))
+  {
+    address_start &= ((CORE_ADDR) 1 << addr_bit) - 1;
+    address_end &= ((CORE_ADDR) 1 << addr_bit) - 1;
+  }
+
+  /* FIXME: cagney/2002-05-03: Need local_address_string() function
+     that returns the language localized string formatted to a width
+     based on gdbarch_addr_bit.  */
+  if (addr_bit <= 32)
+  {
+    strcpy (addstr, "[");
+    strcat (addstr, hex_string_custom (address_start, 8));
+    strcat (addstr, ", ");
+    strcat (addstr, hex_string_custom (address_end, 8));
+    strcat (addstr, "]");
+  }
+  else
+  {
+    strcpy (addstr, "[");
+    strcat (addstr, hex_string_custom (address_start, 16));
+    strcat (addstr, ", ");
+    strcat (addstr, hex_string_custom (address_end, 16));
+    strcat (addstr, "]");
+  }
+
+  ui_out_field_string (uiout, fldname, addstr);
+}
+
+void
 ui_out_field_core_addr (struct ui_out *uiout,
 			const char *fldname,
 			struct gdbarch *gdbarch,
Index: gdb.git/gdb/ui-out.h
===================================================================
--- gdb.git.orig/gdb/ui-out.h	2010-08-17 12:22:54.000000000 -0300
+++ gdb.git/gdb/ui-out.h	2010-08-17 12:31:28.000000000 -0300
@@ -113,6 +113,12 @@ extern void ui_out_field_fmt_int (struct
 				  enum ui_align align, const char *fldname, 
 		 		  int value);
 
+extern void ui_out_field_range_core_addr (struct ui_out *uiout,
+					  const char *fldname,
+                                          struct gdbarch *gdbarch,
+					  CORE_ADDR address_start,
+					  CORE_ADDR length);
+
 extern void ui_out_field_core_addr (struct ui_out *uiout, const char *fldname,
 				    struct gdbarch *gdbarch, CORE_ADDR address);
 
Index: gdb.git/gdb/value.h
===================================================================
--- gdb.git.orig/gdb/value.h	2010-08-17 12:22:54.000000000 -0300
+++ gdb.git/gdb/value.h	2010-08-17 12:31:28.000000000 -0300
@@ -559,6 +559,9 @@ extern CORE_ADDR parse_and_eval_address_
 
 extern LONGEST parse_and_eval_long (char *exp);
 
+int 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);


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

* Re: [patch 2/2] Implement support for PowerPC BookE masked and ranged watchpoints
  2010-08-17 19:42 [patch 2/2] Implement support for PowerPC BookE masked and ranged watchpoints Thiago Jung Bauermann
@ 2010-10-07 14:48 ` Thiago Jung Bauermann
  2010-10-23  4:23 ` Thiago Jung Bauermann
  1 sibling, 0 replies; 19+ messages in thread
From: Thiago Jung Bauermann @ 2010-10-07 14:48 UTC (permalink / raw)
  To: gdb-patches ml

Hi,

On Tue, 2010-08-17 at 16:41 -0300, Thiago Jung Bauermann wrote:
> Tested on ppc-linux, ppc64-linux and i686-linux with no regressions.
> Ok?

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

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

* Re: [patch 2/2] Implement support for PowerPC BookE masked and ranged watchpoints
  2010-08-17 19:42 [patch 2/2] Implement support for PowerPC BookE masked and ranged watchpoints Thiago Jung Bauermann
  2010-10-07 14:48 ` Thiago Jung Bauermann
@ 2010-10-23  4:23 ` Thiago Jung Bauermann
  2010-10-23  9:07   ` Eli Zaretskii
  1 sibling, 1 reply; 19+ messages in thread
From: Thiago Jung Bauermann @ 2010-10-23  4:23 UTC (permalink / raw)
  To: gdb-patches ml

Hi,

This is a new version of the patch. It doesn't rely on an old_ops field
in struct breakpoint. Instead, it makes the breakpoint_ops methods for
ranged watchpoint accept ranged software watchpoints (this was trivial
and involved only new cases in some print methods), and adds a
works_in_software_mode method which is called by update_watchpoint if it
determines that it needs to downgrade a hardware watchpoint to a
software watchpoint. In case it can't be done, it'll throw an exception.

There are no regressions on ppc32-linux, ppc64-linux and i386-linux. Ok?
-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center


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

	Implement support for PowerPC BookE masked and ranged watchpoints.

gdb/
	* breakpoint.c (update_watchpoint): Call breakpoint's
	breakpoint_ops.extra_resources_needed and
	breakpoint_ops.works_in_software_mode if available.
	(watchpoints_triggered): Handle the case of a hardware masked
	watchpoint trigger.
	(watchpoint_check): Handle the case of a hardware masked watchpoint
	trigger.
	(print_one_breakpoint_location): Call breakpoint's
	breakpoint_ops.print_one_detail if available.
	(hw_watchpoint_used_count): Call breakpoint's
	breakpoint_ops.extra_resources_needed if available.
	(insert_ranged_watchpoint, remove_ranged_watchpoint)
	(extra_resources_needed_ranged_watchpoint)
	(print_one_detail_ranged_watchpoint, print_mention_ranged_watchpoint)
	(print_recreate_ranged_watchpoint): New functions.
	(ranged_watchpoint_breakpoint_ops): New structure.
	(insert_masked_watchpoint, remove_masked_watchpoint)
	(extra_resources_needed_masked_watchpoint)
	(works_in_software_mode_masked_watchpoint, print_it_masked_watchpoint)
	(print_one_detail_masked_watchpoint, print_mention_masked_watchpoint)
	(print_recreate_masked_watchpoint, is_masked_watchpoint): New functions.
	(masked_watchpoint_breakpoint_ops): New structure.
	(watch_command_1): Check for the existence of the `mask' parameter.
	Check whether a ranged hardware watchpoint can be used. Set b->ops
	according to the type of hardware watchpoint being created.
	(watch_range_command_1, watch_range_command)
	(awatch_range_command, rwatch_range_command): New functions.
	(_initialize_breakpoint): Register watch-range, awatch-range and
	rwatch-range commands.
	* breakpoint.h (struct ui_out): New opaque declaration.
	(struct breakpoint_ops) <extra_resources_needed>,
	<works_in_software_mode>, <print_one_detail>: New methods.  Initialize them
	to NULL in all existing breakpoint_ops instances.
	(struct breakpoint_ops) <print_it>: Add OLD_VAL parameter.  Update all
	implementations of the method.
	(enum hw_point_flag): New enumeration.
	(struct breakpoint) <hw_wp_mask>: New field.
	* findcmd.c (parse_addr_range): New function factored out of
	parse_find_args.
	(parse_find_args): Call `parse_addr_range'.
	* ppc-linux-nat.c (ppc_linux_can_use_special_hw_point): New function.
	(ppc_linux_region_ok_for_hw_watchpoint): Always handle regions when
	ranged watchpoints are available.
	(ppc_linux_insert_mask_watchpoint, ppc_linux_remove_mask_watchpoint)
	(ppc_linux_insert_ranged_watchpoint, ppc_linux_remove_ranged_watchpoint)
	(ppc_linux_hw_point_extra_slot_count): New functions.
	(_initialize_ppc_linux_nat): Initialize to_insert_mask_watchpoint,
	to_remove_mask_watchpoint, to_insert_ranged_watchpoint,
	to_remove_ranged_watchpoint, hw_point_extra_slot_count and
	to_can_use_special_hw_point.
	* target.c (update_current_target): Insert to_insert_mask_watchpoint,
	to_remove_mask_watchpoint, to_insert_ranged_watchpoint,
	to_remove_ranged_watchpoint, to_hw_point_extra_slot_count
	and to_can_use_special_hw_point.
	* target.h (enum hw_point_flag): New opaque declaration.
	(struct target_ops) <to_insert_mask_watchpoint>,
	<to_remove_mask_watchpoint>, <to_insert_ranged_watchpoint>,
	<to_remove_ranged_watchpoint>, <to_hw_point_extra_slot_count>,
	<to_can_use_special_hw_point>: New callbacks.
	(target_insert_mask_watchpoint, target_remove_mask_watchpoint)
	(target_insert_ranged_watchpoint, target_remove_ranged_watchpoint)
	(target_hw_point_extra_slot_count, target_can_use_special_hw_point): New
	defines.
	* ui-out.c (ui_out_field_range_core_addr): New function.
	* ui-out.h (ui_out_field_range_core_addr): Declare.
	* value.h (parse_addr_range): Declare.

gdb/doc/
	* gdb.texinfo (Set Watchpoints): Document mask parameter.
	(PowerPC Embedded): Document masked watchpoints and ranged watchpoints.


Index: gdb.git/gdb/ada-lang.c
===================================================================
--- gdb.git.orig/gdb/ada-lang.c	2010-10-13 15:59:11.000000000 -0300
+++ gdb.git/gdb/ada-lang.c	2010-10-22 18:41:37.000000000 -0200
@@ -10756,7 +10756,7 @@ print_recreate_exception (enum exception
 /* Virtual table for "catch exception" breakpoints.  */
 
 static enum print_stop_action
-print_it_catch_exception (struct breakpoint *b)
+print_it_catch_exception (struct breakpoint *b, const struct value *old_val)
 {
   return print_it_exception (ex_catch_exception, b);
 }
@@ -10784,8 +10784,11 @@ static struct breakpoint_ops catch_excep
   NULL, /* insert */
   NULL, /* remove */
   NULL, /* breakpoint_hit */
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_exception,
   print_one_catch_exception,
+  NULL, /* print_one_detail */
   print_mention_catch_exception,
   print_recreate_catch_exception
 };
@@ -10793,7 +10796,8 @@ static struct breakpoint_ops catch_excep
 /* Virtual table for "catch exception unhandled" breakpoints.  */
 
 static enum print_stop_action
-print_it_catch_exception_unhandled (struct breakpoint *b)
+print_it_catch_exception_unhandled (struct breakpoint *b,
+				    const struct value *old_val)
 {
   return print_it_exception (ex_catch_exception_unhandled, b);
 }
@@ -10822,8 +10826,11 @@ static struct breakpoint_ops catch_excep
   NULL, /* insert */
   NULL, /* remove */
   NULL, /* breakpoint_hit */
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_exception_unhandled,
   print_one_catch_exception_unhandled,
+  NULL, /* print_one_detail */
   print_mention_catch_exception_unhandled,
   print_recreate_catch_exception_unhandled
 };
@@ -10831,7 +10838,7 @@ static struct breakpoint_ops catch_excep
 /* Virtual table for "catch assert" breakpoints.  */
 
 static enum print_stop_action
-print_it_catch_assert (struct breakpoint *b)
+print_it_catch_assert (struct breakpoint *b, const struct value *old_val)
 {
   return print_it_exception (ex_catch_assert, b);
 }
@@ -10858,8 +10865,11 @@ static struct breakpoint_ops catch_asser
   NULL, /* insert */
   NULL, /* remove */
   NULL, /* breakpoint_hit */
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_assert,
   print_one_catch_assert,
+  NULL, /* print_one_detail */
   print_mention_catch_assert,
   print_recreate_catch_assert
 };
Index: gdb.git/gdb/breakpoint.c
===================================================================
--- gdb.git.orig/gdb/breakpoint.c	2010-10-22 18:41:34.000000000 -0200
+++ gdb.git/gdb/breakpoint.c	2010-10-22 18:41:37.000000000 -0200
@@ -219,6 +219,8 @@ static void disable_trace_command (char 
 
 static void trace_pass_command (char *, int);
 
+static int is_masked_watchpoint (const struct breakpoint *b);
+
 /* Assuming we're creating a static tracepoint, does S look like a
    static tracepoint marker spec ("-m MARKER_ID")?  */
 #define is_marker_spec(s)						\
@@ -1391,27 +1393,52 @@ update_watchpoint (struct breakpoint *b,
 	if ((b->type == bp_watchpoint || b->type == bp_hardware_watchpoint)
 	    && reparse)
 	  {
-	    int i, mem_cnt, other_type_used;
+	    int mem_cnt;
 
-	    /* We need to determine how many resources are already used
-	       for all other hardware watchpoints to see if we still have
-	       enough resources to also fit this watchpoint in as well.
-	       To avoid the hw_watchpoint_used_count call below from counting
-	       this watchpoint, make sure that it is marked as a software
-	       watchpoint.  */
-	    b->type = bp_watchpoint;
-	    i = hw_watchpoint_used_count (bp_hardware_watchpoint,
-					  &other_type_used);
 	    mem_cnt = can_use_hardware_watchpoint (val_chain);
 
 	    if (!mem_cnt)
-	      b->type = bp_watchpoint;
+	      {
+		if (b->type == bp_hardware_watchpoint
+		    && b->ops && b->ops->works_in_software_mode
+		    && !b->ops->works_in_software_mode (b))
+		  error (_("This watchpoint cannot be used in software mode."));
+		else
+		  b->type = bp_watchpoint;
+	      }
 	    else
 	      {
-		int target_resources_ok = target_can_use_hardware_watchpoint
-		  (bp_hardware_watchpoint, i + mem_cnt, other_type_used);
+		int i, other_type_used, target_resources_ok;
+		enum bptype orig_type;
+
+		if (b->ops && b->ops->extra_resources_needed)
+		  mem_cnt += b->ops->extra_resources_needed (b);
+
+		/* We need to determine how many resources are already used
+		   for all other hardware watchpoints to see if we still have
+		   enough resources to also fit this watchpoint in as well.
+		   To avoid the hw_watchpoint_used_count call below from
+		   counting this watchpoint, make sure that it is marked as a
+		   software watchpoint.  */
+		orig_type = b->type;
+		b->type = bp_watchpoint;
+		i = hw_watchpoint_used_count (bp_hardware_watchpoint,
+					      &other_type_used);
+
+		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;
+		  {
+		    if (orig_type == bp_hardware_watchpoint
+			&& b->ops && b->ops->works_in_software_mode
+			&& !b->ops->works_in_software_mode (b))
+		      {
+			b->type = bp_hardware_watchpoint;
+			error (_("This watchpoint cannot be used in software mode."));
+		      }
+		    else
+		      b->type = bp_watchpoint;
+		  }
 		else
 		  b->type = bp_hardware_watchpoint;
 	      }
@@ -3356,7 +3383,7 @@ print_bp_stop_message (bpstat bs)
 	   print_it_typical.  */
 	/* FIXME: how breakpoint can ever be NULL here?  */
 	if (b != NULL && b->ops != NULL && b->ops->print_it != NULL)
-	  return b->ops->print_it (b);
+	  return b->ops->print_it (b, bs->old_val);
 	else
 	  return print_it_typical (bs);
       }
@@ -3492,15 +3519,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 (is_masked_watchpoint (loc->owner))
+	      {
+		newaddr = addr & loc->owner->hw_wp_mask;
+		start = loc->address & loc->owner->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;
@@ -3614,6 +3656,11 @@ watchpoint_check (void *p)
 	  b->val_valid = 1;
 	  return WP_VALUE_CHANGED;
 	}
+      else if (is_masked_watchpoint (b))
+	/* 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.  */
@@ -4684,9 +4731,12 @@ print_one_breakpoint_location (struct br
 	  ui_out_field_int (uiout, "task", b->task);
 	}
     }
-  
+
   ui_out_text (uiout, "\n");
-  
+
+  if (!part_of_multiple && b->ops && b->ops->print_one_detail)
+    b->ops->print_one_detail (b, uiout);
+
   if (!part_of_multiple && b->static_trace_marker_id)
     {
       gdb_assert (b->type == bp_static_tracepoint);
@@ -5857,7 +5907,7 @@ breakpoint_hit_catch_fork (struct breakp
 /* Implement the "print_it" breakpoint_ops method for fork catchpoints.  */
 
 static enum print_stop_action
-print_it_catch_fork (struct breakpoint *b)
+print_it_catch_fork (struct breakpoint *b, const struct value *old_val)
 {
   annotate_catchpoint (b->number);
   printf_filtered (_("\nCatchpoint %d (forked process %d), "),
@@ -5915,8 +5965,11 @@ static struct breakpoint_ops catch_fork_
   insert_catch_fork,
   remove_catch_fork,
   breakpoint_hit_catch_fork,
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_fork,
   print_one_catch_fork,
+  NULL, /* print_one_detail */
   print_mention_catch_fork,
   print_recreate_catch_fork
 };
@@ -5949,7 +6002,7 @@ breakpoint_hit_catch_vfork (struct break
 /* Implement the "print_it" breakpoint_ops method for vfork catchpoints.  */
 
 static enum print_stop_action
-print_it_catch_vfork (struct breakpoint *b)
+print_it_catch_vfork (struct breakpoint *b, const struct value *old_val)
 {
   annotate_catchpoint (b->number);
   printf_filtered (_("\nCatchpoint %d (vforked process %d), "),
@@ -6006,8 +6059,11 @@ static struct breakpoint_ops catch_vfork
   insert_catch_vfork,
   remove_catch_vfork,
   breakpoint_hit_catch_vfork,
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_vfork,
   print_one_catch_vfork,
+  NULL, /* print_one_detail */
   print_mention_catch_vfork,
   print_recreate_catch_vfork
 };
@@ -6127,7 +6183,7 @@ breakpoint_hit_catch_syscall (struct bre
    catchpoints.  */
 
 static enum print_stop_action
-print_it_catch_syscall (struct breakpoint *b)
+print_it_catch_syscall (struct breakpoint *b, const struct value *old_val)
 {
   /* These are needed because we want to know in which state a
      syscall is.  It can be in the TARGET_WAITKIND_SYSCALL_ENTRY
@@ -6287,8 +6343,11 @@ static struct breakpoint_ops catch_sysca
   insert_catch_syscall,
   remove_catch_syscall,
   breakpoint_hit_catch_syscall,
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_syscall,
   print_one_catch_syscall,
+  NULL, /* print_one_detail */
   print_mention_catch_syscall,
   print_recreate_catch_syscall
 };
@@ -6390,7 +6449,7 @@ breakpoint_hit_catch_exec (struct breakp
 }
 
 static enum print_stop_action
-print_it_catch_exec (struct breakpoint *b)
+print_it_catch_exec (struct breakpoint *b, const struct value *old_val)
 {
   annotate_catchpoint (b->number);
   printf_filtered (_("\nCatchpoint %d (exec'd %s), "), b->number,
@@ -6440,8 +6499,11 @@ static struct breakpoint_ops catch_exec_
   insert_catch_exec,
   remove_catch_exec,
   breakpoint_hit_catch_exec,
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_exec,
   print_one_catch_exec,
+  NULL, /* print_one_detail */
   print_mention_catch_exec,
   print_recreate_catch_exec
 };
@@ -6489,7 +6551,14 @@ hw_watchpoint_used_count (enum bptype ty
     if (breakpoint_enabled (b))
       {
 	if (b->type == type)
-	  i++;
+	  {
+	    i++;
+
+	    /* Special types of hardware watchpoints can use more than
+	       one register.  */
+	    if (b->ops && b->ops->extra_resources_needed)
+	      i += b->ops->extra_resources_needed (b);
+	  }
 	else if (is_hardware_watchpoint (b))
 	  *other_type_used = 1;
       }
@@ -8031,12 +8100,353 @@ static struct breakpoint_ops watchpoint_
   insert_watchpoint,
   remove_watchpoint,
   NULL, /* breakpoint_hit */
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
   NULL, /* print_it */
   NULL, /* print_one */
+  NULL, /* print_one_detail */
   NULL, /* print_mention */
   NULL  /* print_recreate */
 };
 
+/* Implement the "insert" breakpoint_ops method for
+   ranged hardware watchpoints.  */
+
+static int
+insert_ranged_watchpoint (struct bp_location *bpt)
+{
+  return target_insert_ranged_watchpoint (bpt->address,
+					  bpt->length,
+					  bpt->watchpoint_type);
+}
+
+/* Implement the "remove" breakpoint_ops method for
+   ranged hardware watchpoints.  */
+
+static int
+remove_ranged_watchpoint (struct bp_location *bpt)
+{
+  return target_remove_ranged_watchpoint (bpt->address, bpt->length,
+					  bpt->watchpoint_type);
+}
+
+/* Implement the "extra_resources_needed" breakpoint_ops method for
+   ranged hardware watchpoints.  */
+
+static int
+extra_resources_needed_ranged_watchpoint (const struct breakpoint *b)
+{
+  return target_hw_point_extra_slot_count (HW_POINT_RANGED_WATCH);
+}
+
+/* Implement the "print_one_detail" breakpoint_ops method for
+   ranged hardware watchpoints.  */
+
+static void
+print_one_detail_ranged_watchpoint (const struct breakpoint *b, struct ui_out *uiout)
+{
+  /* If there's a separate expression for reparsing, then exp_string is already
+     a nice text set by watch_range_command_1 and was printed earlier.  */
+  if (b->exp_string_reparse)
+    return;
+
+  gdb_assert (b->loc);
+
+  ui_out_text (uiout, "\tmemory range: ");
+  ui_out_field_range_core_addr (uiout, "addr", b->loc->gdbarch,
+				b->loc->address, b->loc->length);
+  ui_out_text (uiout, "\n");
+}
+
+/* Implement the "print_mention" breakpoint_ops method for
+   ranged hardware watchpoints.  */
+
+static void
+print_mention_ranged_watchpoint (struct breakpoint *b)
+{
+  struct cleanup *ui_out_chain;
+
+  switch (b->type)
+    {
+    case bp_watchpoint:
+      ui_out_text (uiout, "Ranged watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt");
+      break;
+    case bp_hardware_watchpoint:
+      ui_out_text (uiout, "Ranged hardware watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt");
+      break;
+    case bp_read_watchpoint:
+      ui_out_text (uiout, "Ranged hardware read watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-rwpt");
+      break;
+    case bp_access_watchpoint:
+      ui_out_text (uiout, "Ranged hardware access (read/write) watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-awpt");
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  ui_out_field_int (uiout, "number", b->number);
+  ui_out_text (uiout, ": ");
+  ui_out_field_string (uiout, "exp", b->exp_string);
+  do_cleanups (ui_out_chain);
+}
+
+static void
+print_recreate_ranged_watchpoint (struct breakpoint *b, struct ui_file *fp)
+{
+  switch (b->type)
+    {
+    case bp_watchpoint:
+    case bp_hardware_watchpoint:
+      if (b->exp_string_reparse)
+	fprintf_unfiltered (fp, "watch-range");
+      else
+	fprintf_unfiltered (fp, "watch");
+      break;
+    case bp_read_watchpoint:
+      if (b->exp_string_reparse)
+	fprintf_unfiltered (fp, "rwatch-range");
+      else
+	fprintf_unfiltered (fp, "rwatch");
+      break;
+    case bp_access_watchpoint:
+      if (b->exp_string_reparse)
+	fprintf_unfiltered (fp, "awatch-range");
+      else
+	fprintf_unfiltered (fp, "awatch");
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  if (b->exp_string_reparse)
+    {
+      char start_addr[40], length[40];
+
+      /* watch_range_command_1 creates the following expression to represent
+	 internally a ranged watchpoint.  */
+      sscanf (b->exp_string_reparse, "{char[ %39s ]} %39s", length, start_addr);
+
+      fprintf_unfiltered (fp, " %s, +%s", start_addr, length);
+    }
+  else
+    fprintf_unfiltered (fp, " %s", b->exp_string);
+}
+
+/* The breakpoint_ops structure to be used in ranged hardware watchpoints.  */
+
+static struct breakpoint_ops ranged_watchpoint_breakpoint_ops =
+{
+  insert_ranged_watchpoint,
+  remove_ranged_watchpoint,
+  NULL, /* breakpoint_hit */
+  extra_resources_needed_ranged_watchpoint,
+  NULL, /* works_in_software_mode */
+  NULL, /* print_it */
+  NULL, /* print_one */
+  print_one_detail_ranged_watchpoint,
+  print_mention_ranged_watchpoint,
+  print_recreate_ranged_watchpoint
+};
+
+/* Implement the "insert" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static int
+insert_masked_watchpoint (struct bp_location *bpt)
+{
+  return target_insert_mask_watchpoint (bpt->address, bpt->owner->hw_wp_mask,
+					bpt->watchpoint_type);
+}
+
+/* Implement the "remove" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static int
+remove_masked_watchpoint (struct bp_location *bpt)
+{
+  return target_remove_mask_watchpoint (bpt->address, bpt->owner->hw_wp_mask,
+				        bpt->watchpoint_type);
+}
+
+/* Implement the "extra_resources_needed" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static int
+extra_resources_needed_masked_watchpoint (const struct breakpoint *b)
+{
+  return target_hw_point_extra_slot_count (HW_POINT_MASKED_WATCH);
+}
+
+/* Implement the "works_in_software_mode_masked_watchpoint" breakpoint_ops
+   method for masked hardware watchpoints.  */
+
+static int
+works_in_software_mode_masked_watchpoint (const struct breakpoint *b)
+{
+  return 0;
+}
+
+/* Implement the "print_it" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static enum print_stop_action
+print_it_masked_watchpoint (struct breakpoint *b, const struct value *old_val)
+{
+  struct ui_stream *stb;
+  struct cleanup *old_chain;
+
+  stb = ui_out_stream_new (uiout);
+  old_chain = make_cleanup_ui_out_stream_delete (stb);
+
+  switch (b->type)
+    {
+    case bp_hardware_watchpoint:
+      annotate_watchpoint (b->number);
+      if (ui_out_is_mi_like_p (uiout))
+	ui_out_field_string
+	  (uiout, "reason",
+	   async_reason_lookup (EXEC_ASYNC_WATCHPOINT_TRIGGER));
+      break;
+
+    case bp_read_watchpoint:
+      if (ui_out_is_mi_like_p (uiout))
+	ui_out_field_string
+	  (uiout, "reason",
+	   async_reason_lookup (EXEC_ASYNC_READ_WATCHPOINT_TRIGGER));
+      break;
+
+    case bp_access_watchpoint:
+      if (old_val != NULL)
+	{
+	  annotate_watchpoint (b->number);
+	  if (ui_out_is_mi_like_p (uiout))
+	    ui_out_field_string
+	      (uiout, "reason",
+	       async_reason_lookup (EXEC_ASYNC_ACCESS_WATCHPOINT_TRIGGER));
+	}
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  mention (b);
+  ui_out_text (uiout, "\nCheck the underlying instruction \
+at PC for address and value related to this watchpoint trigger.\n");
+  ui_out_text (uiout, "\n");
+
+  do_cleanups (old_chain);
+
+  /* More than one watchpoint may have been triggered.  */
+  return PRINT_UNKNOWN;
+}
+
+/* Implement the "print_one_detail" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static void
+print_one_detail_masked_watchpoint (const struct breakpoint *b, struct ui_out *uiout)
+{
+  ui_out_text (uiout, "\tmask ");
+
+  /* I don't know whether it's possible to get here without a b->loc,
+     but we can handle the situation.  */
+  if (b->loc)
+    ui_out_field_core_addr (uiout, "mask", b->loc->gdbarch, b->hw_wp_mask);
+  else
+    ui_out_field_string (uiout, "mask", core_addr_to_string (b->hw_wp_mask));
+
+  ui_out_text (uiout, "\n");
+}
+
+/* Implement the "print_mention" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static void
+print_mention_masked_watchpoint (struct breakpoint *b)
+{
+  struct cleanup *ui_out_chain;
+
+  switch (b->type)
+    {
+    case bp_hardware_watchpoint:
+      ui_out_text (uiout, "Masked hardware watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt");
+      break;
+    case bp_read_watchpoint:
+      ui_out_text (uiout, "Masked hardware read watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-rwpt");
+      break;
+    case bp_access_watchpoint:
+      ui_out_text (uiout, "Masked hardware access (read/write) watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-awpt");
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  ui_out_field_int (uiout, "number", b->number);
+  ui_out_text (uiout, ": ");
+  ui_out_field_string (uiout, "exp", b->exp_string);
+  do_cleanups (ui_out_chain);
+}
+
+static void
+print_recreate_masked_watchpoint (struct breakpoint *b, struct ui_file *fp)
+{
+  char tmp[40];
+
+  switch (b->type)
+    {
+    case bp_hardware_watchpoint:
+      fprintf_unfiltered (fp, "watch");
+      break;
+    case bp_read_watchpoint:
+      fprintf_unfiltered (fp, "rwatch");
+      break;
+    case bp_access_watchpoint:
+      fprintf_unfiltered (fp, "awatch");
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  sprintf_vma (tmp, b->hw_wp_mask);
+  fprintf_unfiltered (fp, " %s mask 0x%s", b->exp_string, tmp);
+}
+
+/* The breakpoint_ops structure to be used in masked hardware watchpoints.  */
+
+static struct breakpoint_ops masked_watchpoint_breakpoint_ops =
+{
+  insert_masked_watchpoint,
+  remove_masked_watchpoint,
+  NULL, /* breakpoint_hit */
+  extra_resources_needed_masked_watchpoint,
+  works_in_software_mode_masked_watchpoint,
+  print_it_masked_watchpoint,
+  NULL, /* print_one */
+  print_one_detail_masked_watchpoint,
+  print_mention_masked_watchpoint,
+  print_recreate_masked_watchpoint
+};
+
+/* Tells whether the given watchpoint is a masked hardware watchpoint.  */
+
+static int
+is_masked_watchpoint (const struct breakpoint *b)
+{
+  return b->ops == &masked_watchpoint_breakpoint_ops;
+}
+
 /* accessflag:  hw_write:  watch write, 
                 hw_read:   watch read, 
 		hw_access: watch access (read or write) */
@@ -8050,8 +8460,8 @@ watch_command_1 (char *arg, int accessfl
   struct frame_info *frame;
   char *exp_start = NULL;
   char *exp_end = NULL;
-  char *tok, *id_tok_start, *end_tok;
-  int toklen;
+  char *tok, *end_tok;
+  int toklen = -1;
   char *cond_start = NULL;
   char *cond_end = NULL;
   int i, other_type_used, target_resources_ok = 0;
@@ -8059,66 +8469,98 @@ watch_command_1 (char *arg, int accessfl
   int mem_cnt = 0;
   int thread = -1;
   int pc = 0;
+  /* 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;
 
   /* Make sure that we actually have parameters to parse.  */
   if (arg != NULL && arg[0] != '\0')
     {
-      toklen = strlen (arg); /* Size of argument list.  */
+      char *value_start;
 
-      /* Points tok to the end of the argument list.  */
-      tok = arg + toklen - 1;
+      /* Look for "parameter value" pairs at the end
+	 of the arguments string.  */
+      for (tok = arg + strlen (arg) - 1; tok > arg; tok--)
+	{
+	  /* Skip whitespace at the end of the argument list.  */
+	  while (tok > arg && (*tok == ' ' || *tok == '\t'))
+	    tok--;
+
+	  /* Find the beginning of the last token.
+	     This is the value of the parameter.  */
+	  while (tok > arg && (*tok != ' ' && *tok != '\t'))
+	    tok--;
+	  value_start = tok + 1;
+
+	  /* Skip whitespace.  */
+	  while (tok > arg && (*tok == ' ' || *tok == '\t'))
+	    tok--;
+
+	  end_tok = tok;
+
+	  /* Find the beginning of the second to last token.
+	     This is the parameter itself.  */
+	  while (tok > arg && (*tok != ' ' && *tok != '\t'))
+	    tok--;
+	  tok++;
+	  toklen = end_tok - tok + 1;
+
+	  if (toklen == 6 && !strncmp (tok, "thread", 6))
+	    {
+	      /* 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;
+
+	      if (thread != -1)
+		error(_("You can specify only one thread."));
+
+	      /* Extract the thread ID from the next token.  */
+	      thread = strtol (value_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."), value_start);
+
+	      /* Check if the thread actually exists.  */
+	      if (!valid_thread_id (thread))
+		error (_("Unknown thread %d."), thread);
+	    }
+	  else if (toklen == 4 && !strncmp (tok, "mask", 4))
+	    {
+	      /* We've found a "mask" token, which means the user wants to
+		 create a hardware watchpoint that is going to have the mask
+		 facility.  */
+	      struct value *mask_value, *mark;
 
-      /* 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--;
+	      /* Does the target support masked watchpoints?  */
+	      if (!target_can_use_special_hw_point (HW_POINT_MASKED_WATCH))
+		error (_("\
+This target does not support the usage of masks with hardware watchpoints."));
 
-      end_tok = tok;
+	      if (use_mask)
+		error(_("You can specify only one mask."));
 
-      while (tok > arg && (*tok != ' ' && *tok != '\t'))
-        tok--;
+	      use_mask = 1;
 
-      /* Move the pointer forward to skip the whitespace and
-         calculate the length of the token.  */
-      tok++;
-      toklen = end_tok - tok;
+	      mark = value_mark ();
+	      mask_value = parse_to_comma_and_eval (&value_start);
+	      hw_wp_mask = value_as_address (mask_value);
+	      value_free_to_mark (mark);
+	    }
+	  else
+	    /* We didn't recognize what we found.  We should stop here.  */
+	    break;
 
-      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';
-        }
+	  /* Truncate the string and get rid of the "parameter value" pair before
+	     the arguments string is parsed by the parse_exp_1 function.  */
+	  *tok = '\0';
+	}
     }
 
   /* Parse the rest of the arguments.  */
@@ -8196,6 +8638,22 @@ watch_command_1 (char *arg, int accessfl
     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 (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, 
@@ -8207,10 +8665,22 @@ watch_command_1 (char *arg, int accessfl
 	error (_("Target can only support one kind of HW watchpoint at a time."));
     }
 
-  /* 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 && !mem_cnt)
+	error (_("Cannot use masks with the given expression."));
+      else if (use_mask && target_resources_ok <= 0)
+	error (_("\
+Cannot use masks without enough available hardware watchpoints (need %d)."),
+	       mem_cnt);
+      else
+	{
+	  /* Change the type of breakpoint to an ordinary watchpoint if a
+	     hardware watchpoint could not be set.  */
+	  bp_type = bp_watchpoint;
+	  use_ranged = 0;
+	}
+    }
 
   frame = block_innermost_frame (exp_valid_block);
 
@@ -8279,7 +8749,16 @@ watch_command_1 (char *arg, int accessfl
     b->exp_string = savestring (exp_start, exp_end - exp_start);
   b->val = val;
   b->val_valid = 1;
-  b->ops = &watchpoint_breakpoint_ops;
+
+  if (use_mask)
+    {
+      b->hw_wp_mask = hw_wp_mask;
+      b->ops = &masked_watchpoint_breakpoint_ops;
+    }
+  else if (use_ranged)
+    b->ops = &ranged_watchpoint_breakpoint_ops;
+  else
+    b->ops = &watchpoint_breakpoint_ops;
 
   if (cond_start)
     b->cond_string = savestring (cond_start, cond_end - cond_start);
@@ -8466,6 +8945,92 @@ awatch_command (char *arg, int from_tty)
 {
   watch_maybe_just_location (arg, hw_access, from_tty);
 }
+
+static void
+watch_range_command_1 (char *arg, enum bptype type, int from_tty)
+{
+  char *exp_string, *string_p;
+  struct gdbarch *gdbarch = get_current_arch ();
+  int wp_count, other_type_used, can_use_wp, mem_cnt, pc = 0;
+  CORE_ADDR start_addr;
+  ULONGEST length;
+  struct breakpoint *b;
+  struct expression *exp;
+  struct symtab_and_line sal;
+  struct value *val;
+  struct cleanup *cleanups;
+
+  /* Do we support ranged hardware watchpoints?  */
+  if (!target_can_use_special_hw_point (HW_POINT_RANGED_WATCH))
+    error (_("This target does not support ranged hardware watchpoints."));
+  /* Did the user specifically forbid us to use hardware watchpoints? */
+  else if (!can_use_hw_watchpoints)
+    error (_("\
+Hardware watchpoints are disabled (see \"set can-use-hw-watchpoints\")."));
+
+  parse_addr_range (&arg, &start_addr, &length);
+
+  /* We need spaces around the brackets in the expression below so that
+     print_it_recreate_ranged_watchpoint can use scanf on it.  */
+  exp_string = string_p = xstrprintf ("{char[ %s ]} %s", pulongest (length),
+				      paddress (gdbarch, start_addr));
+  exp = parse_exp_1 (&string_p, 0, 0);
+  fetch_subexp_value (exp, &pc, &val, NULL, NULL);
+  if (val != NULL)
+    release_value (val);
+  cleanups = make_cleanup (xfree, exp_string);
+
+  mem_cnt = target_hw_point_extra_slot_count (HW_POINT_RANGED_WATCH) + 1;
+
+  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 available hardware watchpoints (need %d)."), mem_cnt);
+
+  init_sal (&sal);		/* initialize to zeroes */
+  sal.pspace = current_program_space;
+
+  /* Now set up the breakpoint.  */
+  b = set_raw_breakpoint (gdbarch, sal, type);
+  set_breakpoint_count (breakpoint_count + 1);
+  b->number = breakpoint_count;
+  b->thread = -1;
+  b->disposition = disp_donttouch;
+  b->exp = exp;
+  b->exp_string_reparse = exp_string;
+  b->exp_string = xstrprintf (_("range [%s, %s]"),
+			      paddress (gdbarch, start_addr),
+			      paddress (gdbarch, start_addr + length - 1));
+  b->ops = &ranged_watchpoint_breakpoint_ops;
+  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);
+}
+
 \f
 
 /* Helper routines for the until_command routine in infcmd.c.  Here
@@ -8703,7 +9268,8 @@ catch_exec_command_1 (char *arg, int fro
 }
 
 static enum print_stop_action
-print_exception_catchpoint (struct breakpoint *b)
+print_it_exception_catchpoint (struct breakpoint *b,
+			       const struct value *old_val)
 {
   int bp_temp, bp_throw;
 
@@ -8792,8 +9358,11 @@ static struct breakpoint_ops gnu_v3_exce
   NULL, /* insert */
   NULL, /* remove */
   NULL, /* breakpoint_hit */
-  print_exception_catchpoint,
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
+  print_it_exception_catchpoint,
   print_one_exception_catchpoint,
+  NULL, /* print_one_detail */
   print_mention_exception_catchpoint,
   print_recreate_exception_catchpoint
 };
@@ -12183,7 +12752,41 @@ 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 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 from 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);
Index: gdb.git/gdb/breakpoint.h
===================================================================
--- gdb.git.orig/gdb/breakpoint.h	2010-10-22 18:41:34.000000000 -0200
+++ gdb.git/gdb/breakpoint.h	2010-10-22 18:41:37.000000000 -0200
@@ -26,6 +26,7 @@
 
 struct value;
 struct block;
+struct ui_out;
 
 /* This is the maximum number of bytes a breakpoint instruction can take.
    Feel free to increase it.  It's just used in a few places to size
@@ -361,13 +362,28 @@ struct breakpoint_ops
      breakpoint was hit.  */
   int (*breakpoint_hit) (struct breakpoint *);
 
+  /* Tell how many additional hardware resources (debug registers) are needed
+     for this breakpoint.  We always count at least one resource.  If this
+     element is NULL, then no additional resource is accounted for.  */
+  int (*extra_resources_needed) (const struct breakpoint *);
+
+  /* Tell whether we can downgrade from a hardware watchpoint to a software
+     one.  If not, the user will not be able to enable the watchpoint when
+     there are not enough hardware resources available.  */
+  int (*works_in_software_mode) (const struct breakpoint *);
+
   /* The normal print routine for this breakpoint, called when we
      hit it.  */
-  enum print_stop_action (*print_it) (struct breakpoint *);
+  enum print_stop_action (*print_it) (struct breakpoint *,
+				      const struct value *old_val);
 
   /* Display information about this breakpoint, for "info breakpoints".  */
   void (*print_one) (struct breakpoint *, struct bp_location **);
 
+  /* Display one line of extra information about this breakpoint,
+     for "info breakpoints".  */
+  void (*print_one_detail) (const struct breakpoint *, struct ui_out *);
+
   /* Display information about this breakpoint after setting it (roughly
      speaking; this is called from "mention").  */
   void (*print_mention) (struct breakpoint *);
@@ -400,6 +416,12 @@ DEF_VEC_P(bp_location_p);
    detail to the breakpoints module.  */
 struct counted_command_line;
 
+/* Special types of hardware breakpoints/watchpoints.  */
+enum hw_point_flag {
+	HW_POINT_RANGED_WATCH, /* Hardware ranged watchpoint.  */
+	HW_POINT_MASKED_WATCH  /* Hardware masked watchpoint.  */
+};
+
 /* Note that the ->silent field is not currently used by any commands
    (though the code is in there if it was to be, and set_raw_breakpoint
    does set it to 0).  I implemented it because I thought it would be
@@ -559,6 +581,9 @@ struct breakpoint
        breakpoints, we will use this index to try to find the same
        marker again.  */
     int static_trace_marker_id_idx;
+
+    /* The mask address for a hardware watchpoint.  */
+    CORE_ADDR hw_wp_mask;
   };
 
 typedef struct breakpoint *breakpoint_p;
Index: gdb.git/gdb/doc/gdb.texinfo
===================================================================
--- gdb.git.orig/gdb/doc/gdb.texinfo	2010-10-19 21:04:59.000000000 -0200
+++ gdb.git/gdb/doc/gdb.texinfo	2010-10-22 18:41:37.000000000 -0200
@@ -3711,7 +3711,7 @@ watchpoints, which do not slow down the 
 
 @table @code
 @kindex watch
-@item watch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]}
+@item watch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} @r{[}mask @var{maskvalue}@r{]}
 Set a watchpoint for an expression.  @value{GDBN} will break when the
 expression @var{expr} is written into by the program and its value
 changes.  The simplest (and the most popular) use of this command is
@@ -3728,6 +3728,11 @@ change the value of @var{expr}, @value{G
 that watchpoints restricted to a single thread in this way only work
 with Hardware Watchpoints.
 
+The @code{@r{[}mask @var{maskvalue}@r{]}} clause is used to create a masked
+watchpoint if the current architecture supports the feature (currently,
+only available in the PowerPC Embedded architecture.
+See @ref{PowerPC Embedded}).
+
 Ordinarily a watchpoint respects the scope of variables in @var{expr}
 (see below).  The @code{-location} argument tells @value{GDBN} to
 instead watch the memory referred to by @var{expr}.  In this case,
@@ -3738,12 +3743,12 @@ result does not have an address, then @v
 error.
 
 @kindex rwatch
-@item rwatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]}
+@item rwatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} @r{[}mask @var{maskvalue}@r{]}
 Set a watchpoint that will break when the value of @var{expr} is read
 by the program.
 
 @kindex awatch
-@item awatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]}
+@item awatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} @r{[}mask @var{maskvalue}@r{]}
 Set a watchpoint that will break when @var{expr} is either read from
 or written into by the program.
 
@@ -18517,9 +18522,41 @@ The DVC register will be automatically u
 such pattern in a condition expression.  This feature is available in native
 @value{GDBN} running on a Linux kernel version 2.6.34 or newer.
 
+PowerPC embedded processors support additional types of hardware watchpoints,
+namely masked watchpoints and ranged watchpoints.
+
+A @dfn{masked watchpoint} is defined by an address and a mask.  It triggers
+when the address of a memory access matches the watchpoint address when both
+are masked by the watchpoint mask.  That is, the bits set in the mask determine
+which bits are relevant in the address comparison.  To set a masked watchpoint
+in @value{GDBN}, use the @code{mask} parameter in the @code{watch} command
+(see @ref{Set Watchpoints}), as in:
+
+@smallexample
+(@value{GDBP}) watch *0xdeadbeef mask 0xffffff00
+@end smallexample
+
+A @dfn{ranged watchpoint} is defined by a start address and an end address
+specifying a region of memory inside which any access will trigger the
+watchpoint.  Both the start and end addresses are within the memory region.
+To set a ranged watchpoint in @value{GDBN}, use the @code{watch-range} command.
+
 @value{GDBN} provides the following PowerPC-specific commands:
 
 @table @code
+@kindex watch-range
+@item watch-range @var{start-address, +length}
+@itemx watch-range @var{start-address, end-address}
+@item rwatch-range @var{start-address, +length}
+@itemx rwatch-range @var{start-address, end-address}
+@item awatch-range @var{start-address, +length}
+@itemx awatch-range @var{start-address, end-address}
+Set a hardware watchpoint for an address range.
+The watchpoint will stop execution of your program whenever the inferior
+writes, reads, or accesses (respectively for watch-range, awatch-range
+and rwatch-range) any address within the @code{[start-address, end-address]}
+interval.
+
 @kindex set powerpc
 @item set powerpc soft-float
 @itemx show powerpc soft-float
Index: gdb.git/gdb/findcmd.c
===================================================================
--- gdb.git.orig/gdb/findcmd.c	2010-08-20 16:00:16.000000000 -0300
+++ gdb.git/gdb/findcmd.c	2010-10-22 18:41:37.000000000 -0200
@@ -45,6 +45,79 @@ 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.  Returns 1 on success, or 0 if an empty address range was given.  */
+
+int
+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)
+	{
+	  printf_filtered (_("Empty search range.\n"));
+	  return 0;
+	}
+      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;
+
+  *args = s;
+  *start_addrp = start_addr;
+  *search_space_lenp = search_space_len;
+
+  return 1;
+}
+
 /* Subroutine of find_command to simplify it.
    Parse the arguments of the "find" command.  */
 
@@ -114,53 +187,8 @@ 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;
+  if (!parse_addr_range (&s, &start_addr, &search_space_len))
+    return;
 
   /* Fetch the search string.  */
 
Index: gdb.git/gdb/ppc-linux-nat.c
===================================================================
--- gdb.git.orig/gdb/ppc-linux-nat.c	2010-08-20 16:00:16.000000000 -0300
+++ gdb.git/gdb/ppc-linux-nat.c	2010-10-22 18:41:37.000000000 -0200
@@ -1478,6 +1478,28 @@ ppc_linux_can_use_hw_breakpoint (int typ
 }
 
 static int
+ppc_linux_can_use_special_hw_point (enum hw_point_flag flag)
+{
+  uint64_t features;
+
+  if (!have_ptrace_booke_interface ())
+    return 0;
+
+  features = booke_debug_info.features;
+
+  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;
+      default:
+	internal_error (__FILE__, __LINE__,
+			_("Unknown hardware breakpoint/watchpoint type."));
+    }
+}
+
+static int
 ppc_linux_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
 {
   /* Handle sub-8-byte quantities.  */
@@ -1489,9 +1511,15 @@ ppc_linux_region_ok_for_hw_watchpoint (C
      to determine the hardcoded watchable region for watchpoints.  */
   if (have_ptrace_booke_interface ())
     {
-      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 (ppc_linux_can_use_special_hw_point (HW_POINT_RANGED_WATCH))
+	return 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
@@ -1685,6 +1713,106 @@ get_trigger_type (int rw)
   return t;
 }
 
+static int
+ppc_linux_insert_mask_watchpoint (CORE_ADDR addr, CORE_ADDR mask, int rw)
+{
+  ptid_t ptid;
+  struct lwp_info *lp;
+  struct ppc_hw_breakpoint p;
+
+  gdb_assert (have_ptrace_booke_interface ());
+
+  if ((mask & 0xC0000000) != 0xC0000000)
+    error (_("\
+The given mask covers kernel address space and cannot be used.\n\
+You have to delete the masked watchpoint to continue the debugging session."));
+
+  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) addr;
+  p.addr2           = (uint64_t) mask;
+  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, CORE_ADDR mask, int rw)
+{
+  ptid_t ptid;
+  struct lwp_info *lp;
+  struct ppc_hw_breakpoint p;
+
+  gdb_assert (have_ptrace_booke_interface ());
+
+  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) addr;
+  p.addr2           = (uint64_t) mask;
+  p.condition_value = 0;
+
+  ALL_LWPS (lp, ptid)
+    booke_remove_point (&p, TIDGET (ptid));
+
+  return 0;
+}
+
+static int
+ppc_linux_insert_ranged_watchpoint (CORE_ADDR addr, int len, int rw)
+{
+  ptid_t ptid;
+  struct lwp_info *lp;
+  struct ppc_hw_breakpoint p;
+
+  gdb_assert (have_ptrace_booke_interface ());
+
+  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.condition_value = 0;
+
+  /* The watchpoint will trigger if the address of the memory access is
+     within the defined range, as follows: p.addr <= address < p.addr2.  */
+  p.addr            = (uint64_t) addr;
+  p.addr2           = (uint64_t) addr + len;
+
+  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)
+{
+  ptid_t ptid;
+  struct lwp_info *lp;
+  struct ppc_hw_breakpoint p;
+
+  gdb_assert (have_ptrace_booke_interface ());
+
+  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;
+}
+
 /* Check whether we have at least one free DVC register.  */
 static int
 can_use_watchpoint_cond_accel (void)
@@ -2136,6 +2264,14 @@ ppc_linux_watchpoint_addr_within_range (
   return start <= addr + mask && start + length - 1 >= addr;
 }
 
+static int
+ppc_linux_hw_point_extra_slot_count (enum hw_point_flag flag)
+{
+  gdb_assert (flag == HW_POINT_MASKED_WATCH || flag == HW_POINT_RANGED_WATCH);
+
+  return 1;
+}
+
 static void
 ppc_linux_store_inferior_registers (struct target_ops *ops,
 				    struct regcache *regcache, int regno)
@@ -2347,12 +2483,18 @@ _initialize_ppc_linux_nat (void)
   t->to_insert_hw_breakpoint = ppc_linux_insert_hw_breakpoint;
   t->to_remove_hw_breakpoint = ppc_linux_remove_hw_breakpoint;
   t->to_region_ok_for_hw_watchpoint = ppc_linux_region_ok_for_hw_watchpoint;
+  t->to_can_use_special_hw_point = ppc_linux_can_use_special_hw_point;
   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_stopped_by_watchpoint = ppc_linux_stopped_by_watchpoint;
   t->to_stopped_data_address = ppc_linux_stopped_data_address;
   t->to_watchpoint_addr_within_range = ppc_linux_watchpoint_addr_within_range;
   t->to_can_accel_watchpoint_condition = ppc_linux_can_accel_watchpoint_condition;
+  t->to_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.git/gdb/target.c
===================================================================
--- gdb.git.orig/gdb/target.c	2010-10-22 18:41:34.000000000 -0200
+++ gdb.git/gdb/target.c	2010-10-22 18:41:37.000000000 -0200
@@ -601,11 +601,16 @@ update_current_target (void)
       INHERIT (to_files_info, t);
       INHERIT (to_insert_breakpoint, t);
       INHERIT (to_remove_breakpoint, t);
+      INHERIT (to_can_use_special_hw_point, t);
       INHERIT (to_can_use_hw_breakpoint, t);
       INHERIT (to_insert_hw_breakpoint, t);
       INHERIT (to_remove_hw_breakpoint, t);
       INHERIT (to_insert_watchpoint, t);
       INHERIT (to_remove_watchpoint, t);
+      INHERIT (to_insert_ranged_watchpoint, t);
+      INHERIT (to_remove_ranged_watchpoint, t);
+      INHERIT (to_insert_mask_watchpoint, t);
+      INHERIT (to_remove_mask_watchpoint, t);
       INHERIT (to_stopped_data_address, t);
       INHERIT (to_have_steppable_watchpoint, t);
       INHERIT (to_have_continuable_watchpoint, t);
@@ -613,6 +618,7 @@ update_current_target (void)
       INHERIT (to_watchpoint_addr_within_range, t);
       INHERIT (to_region_ok_for_hw_watchpoint, t);
       INHERIT (to_can_accel_watchpoint_condition, 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);
@@ -727,6 +733,9 @@ update_current_target (void)
   de_fault (to_can_use_hw_breakpoint,
 	    (int (*) (int, int, int))
 	    return_zero);
+  de_fault (to_can_use_special_hw_point,
+	    (int (*) (enum hw_point_flag))
+	    return_zero);
   de_fault (to_insert_hw_breakpoint,
 	    (int (*) (struct gdbarch *, struct bp_target_info *))
 	    return_minus_one);
@@ -739,6 +748,18 @@ update_current_target (void)
   de_fault (to_remove_watchpoint,
 	    (int (*) (CORE_ADDR, int, int, struct expression *))
 	    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, CORE_ADDR, int))
+            return_minus_one);
+  de_fault (to_remove_mask_watchpoint,
+            (int (*) (CORE_ADDR, CORE_ADDR, int))
+            return_minus_one);
   de_fault (to_stopped_by_watchpoint,
 	    (int (*) (void))
 	    return_zero);
@@ -752,6 +773,9 @@ update_current_target (void)
   de_fault (to_can_accel_watchpoint_condition,
             (int (*) (CORE_ADDR, int, int, struct expression *))
             return_zero);
+  de_fault (to_hw_point_extra_slot_count,
+            (int (*) (enum hw_point_flag))
+            return_zero);
   de_fault (to_terminal_init,
 	    (void (*) (void))
 	    target_ignore);
Index: gdb.git/gdb/target.h
===================================================================
--- gdb.git.orig/gdb/target.h	2010-10-22 18:41:34.000000000 -0200
+++ gdb.git/gdb/target.h	2010-10-22 18:41:37.000000000 -0200
@@ -39,6 +39,8 @@ struct static_tracepoint_marker;
 
 struct expression;
 
+enum hw_point_flag;
+
 /* This include file defines the interface between the main part
    of the debugger, and the part which is target-specific, or
    specific to the communications interface between us and the
@@ -438,6 +440,7 @@ struct target_ops
     int (*to_insert_breakpoint) (struct gdbarch *, struct bp_target_info *);
     int (*to_remove_breakpoint) (struct gdbarch *, struct bp_target_info *);
     int (*to_can_use_hw_breakpoint) (int, int, int);
+    int (*to_can_use_special_hw_point) (enum hw_point_flag);
     int (*to_insert_hw_breakpoint) (struct gdbarch *, struct bp_target_info *);
     int (*to_remove_hw_breakpoint) (struct gdbarch *, struct bp_target_info *);
 
@@ -446,6 +449,10 @@ struct target_ops
     int (*to_remove_watchpoint) (CORE_ADDR, int, int, struct expression *);
     int (*to_insert_watchpoint) (CORE_ADDR, int, int, struct expression *);
 
+    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, CORE_ADDR, int);
+    int (*to_remove_mask_watchpoint) (CORE_ADDR, CORE_ADDR, int);
     int (*to_stopped_by_watchpoint) (void);
     int to_have_steppable_watchpoint;
     int to_have_continuable_watchpoint;
@@ -455,6 +462,7 @@ struct target_ops
     int (*to_region_ok_for_hw_watchpoint) (CORE_ADDR, int);
     int (*to_can_accel_watchpoint_condition) (CORE_ADDR, int, int,
 					      struct expression *);
+    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);
@@ -1314,6 +1322,11 @@ extern char *normal_pid_to_str (ptid_t p
 #define target_region_ok_for_hw_watchpoint(addr, len) \
     (*current_target.to_region_ok_for_hw_watchpoint) (addr, len)
 
+/* Returns non-zero if the target supports the special type of hardware
+   breakpoint/watchpoint represented by FLAG.  */
+#define target_can_use_special_hw_point(flag) \
+  (*current_target.to_can_use_special_hw_point) (flag)
+
 
 /* Set/clear a hardware watchpoint starting at ADDR, for LEN bytes.
    TYPE is 0 for write, 1 for read, and 2 for read/write accesses.
@@ -1327,6 +1340,20 @@ extern char *normal_pid_to_str (ptid_t p
 #define	target_remove_watchpoint(addr, len, type, cond) \
      (*current_target.to_remove_watchpoint) (addr, len, type, cond)
 
+/* Hardware ranged watchpoints.  */
+#define target_insert_ranged_watchpoint(addr, len, type) \
+  (*current_target.to_insert_ranged_watchpoint) (addr, len, type)
+
+#define target_remove_ranged_watchpoint(addr, len, type) \
+  (*current_target.to_remove_ranged_watchpoint) (addr, len, type)
+
+/* Hardware watchpoints with an associated address mask.  */
+#define target_insert_mask_watchpoint(addr, mask, type) \
+  (*current_target.to_insert_mask_watchpoint) (addr, mask, type)
+
+#define target_remove_mask_watchpoint(addr, mask, type) \
+  (*current_target.to_remove_mask_watchpoint) (addr, mask, type)
+
 #define target_insert_hw_breakpoint(gdbarch, bp_tgt) \
      (*current_target.to_insert_hw_breakpoint) (gdbarch, bp_tgt)
 
@@ -1355,6 +1382,9 @@ extern char *normal_pid_to_str (ptid_t p
 #define target_can_accel_watchpoint_condition(addr, len, type, cond) \
   (*current_target.to_can_accel_watchpoint_condition) (addr, len, type, cond)
 
+#define target_hw_point_extra_slot_count(flag) \
+  (*current_target.to_hw_point_extra_slot_count) (flag)
+
 /* Target can execute in reverse?  */
 #define target_can_execute_reverse \
      (current_target.to_can_execute_reverse ? \
Index: gdb.git/gdb/ui-out.c
===================================================================
--- gdb.git.orig/gdb/ui-out.c	2010-08-20 16:00:16.000000000 -0300
+++ gdb.git/gdb/ui-out.c	2010-10-22 18:41:37.000000000 -0200
@@ -487,6 +487,46 @@ ui_out_field_fmt_int (struct ui_out *uio
 }
 
 void
+ui_out_field_range_core_addr (struct ui_out *uiout,
+			      const char *fldname,
+			      struct gdbarch *gdbarch,
+			      CORE_ADDR address_start,
+			      CORE_ADDR length)
+{
+  char addstr[80];
+  int addr_bit = gdbarch_addr_bit (gdbarch);
+  CORE_ADDR address_end = address_start + length - 1;
+
+  if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT))
+  {
+    address_start &= ((CORE_ADDR) 1 << addr_bit) - 1;
+    address_end &= ((CORE_ADDR) 1 << addr_bit) - 1;
+  }
+
+  /* FIXME: cagney/2002-05-03: Need local_address_string() function
+     that returns the language localized string formatted to a width
+     based on gdbarch_addr_bit.  */
+  if (addr_bit <= 32)
+  {
+    strcpy (addstr, "[");
+    strcat (addstr, hex_string_custom (address_start, 8));
+    strcat (addstr, ", ");
+    strcat (addstr, hex_string_custom (address_end, 8));
+    strcat (addstr, "]");
+  }
+  else
+  {
+    strcpy (addstr, "[");
+    strcat (addstr, hex_string_custom (address_start, 16));
+    strcat (addstr, ", ");
+    strcat (addstr, hex_string_custom (address_end, 16));
+    strcat (addstr, "]");
+  }
+
+  ui_out_field_string (uiout, fldname, addstr);
+}
+
+void
 ui_out_field_core_addr (struct ui_out *uiout,
 			const char *fldname,
 			struct gdbarch *gdbarch,
Index: gdb.git/gdb/ui-out.h
===================================================================
--- gdb.git.orig/gdb/ui-out.h	2010-08-20 16:00:16.000000000 -0300
+++ gdb.git/gdb/ui-out.h	2010-10-22 18:41:37.000000000 -0200
@@ -113,6 +113,12 @@ extern void ui_out_field_fmt_int (struct
 				  enum ui_align align, const char *fldname, 
 		 		  int value);
 
+extern void ui_out_field_range_core_addr (struct ui_out *uiout,
+					  const char *fldname,
+                                          struct gdbarch *gdbarch,
+					  CORE_ADDR address_start,
+					  CORE_ADDR length);
+
 extern void ui_out_field_core_addr (struct ui_out *uiout, const char *fldname,
 				    struct gdbarch *gdbarch, CORE_ADDR address);
 
Index: gdb.git/gdb/value.h
===================================================================
--- gdb.git.orig/gdb/value.h	2010-10-19 21:05:00.000000000 -0200
+++ gdb.git/gdb/value.h	2010-10-22 18:41:37.000000000 -0200
@@ -559,6 +559,9 @@ extern CORE_ADDR parse_and_eval_address_
 
 extern LONGEST parse_and_eval_long (char *exp);
 
+int 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);


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

* Re: [patch 2/2] Implement support for PowerPC BookE masked and ranged watchpoints
  2010-10-23  4:23 ` Thiago Jung Bauermann
@ 2010-10-23  9:07   ` Eli Zaretskii
  2010-10-30  1:59     ` Thiago Jung Bauermann
  0 siblings, 1 reply; 19+ messages in thread
From: Eli Zaretskii @ 2010-10-23  9:07 UTC (permalink / raw)
  To: Thiago Jung Bauermann; +Cc: gdb-patches

> From: Thiago Jung Bauermann <bauerman@br.ibm.com>
> Date: Sat, 23 Oct 2010 02:22:41 -0200
> 
> This is a new version of the patch.

Thanks.

> It doesn't rely on an old_ops field
> in struct breakpoint. Instead, it makes the breakpoint_ops methods for
> ranged watchpoint accept ranged software watchpoints (this was trivial
> and involved only new cases in some print methods), and adds a
> works_in_software_mode method which is called by update_watchpoint if it
> determines that it needs to downgrade a hardware watchpoint to a
> software watchpoint. In case it can't be done, it'll throw an exception.

In what cases will the software mode be used for ranged watchpoints?
Does this mean that architectures that don't have hardware support for
such watchpoints will be able to use them in software mode?

And what about masked watchpoints -- can they also be used in software
mode?

I'm quite sure this was all mentioned in the discussions leading to
this patch, so if I can read about that elsewhere, please just point
me to the relevant thread.

> +	/* Since we don't know the exact trigger address (from
> +	   stopped_data_address) Just tell the user we've triggered
> +	   a mask watchpoint.  */

"Just" should be "just" (no capitalization).  And a comma before it
would be appropriate, too.

> +  mention (b);
> +  ui_out_text (uiout, "\nCheck the underlying instruction \
> +at PC for address and value related to this watchpoint trigger.\n");

Shouldn't this be in _() ?

> +    case bp_hardware_watchpoint:
> +      ui_out_text (uiout, "Masked hardware watchpoint ");

Isn't it better to say "Masked hardware (write) watchpoint"?

> +The watchpoint will stop execution of your program whenever the inferior\n\
> +writes to any address within the [start-address, end-address] interval."));

The literal difference between "your program" and "the inferior" could
confuse the user.  Suggest the following simplification:

  The watchpoint will stop execution of the inferior whenever it writes
  to any address within the [start-address, end-address] interval.

Also, isn't "range" better than "interval" here?

The same goes for all the other similar commands.

> +  /* Tell how many additional hardware resources (debug registers) are needed
> +     for this breakpoint.  We always count at least one resource.  If this
> +     element is NULL, then no additional resource is accounted for.  */
> +  int (*extra_resources_needed) (const struct breakpoint *);

I think the last sentence of the comment is unclear.  What does it
mean "no resource is accounted for"?  If that's to say "no additional
resources are needed", then why not say that explicitly?

> +  /* Display one line of extra information about this breakpoint,
> +     for "info breakpoints".  */
> +  void (*print_one_detail) (const struct breakpoint *, struct ui_out *);

Examples of such "extras" would be beneficial here.  Also, are there
any limitations on this extra information, like maximum length?

> +The @code{@r{[}mask @var{maskvalue}@r{]}} clause is used to create a masked
> +watchpoint if the current architecture supports the feature (currently,
> +only available in the PowerPC Embedded architecture.
> +See @ref{PowerPC Embedded}).

First, using "clause" here is suboptimal.  I would suggest "argument"
instead.  Second, the part in the parentheses is wrong: you cannot
put several sentences in a parenthesis that itself is part of a
sentence.  And third, you need a period after @ref{}, or else makeinfo
will bitch at you.  How about the following rewording (which also
avoids using the passive tense)?

  The @code{@r{[}mask @var{maskvalue}@r{]}} argument allows creation
  of masked watchpoints, if the current architecture supports this
  feature.  (Currently, this is only available on PowerPC Embedded
  architecture, see @ref{PowerPC Embedded}.)

> +PowerPC embedded processors support additional types of hardware watchpoints,
> +namely masked watchpoints and ranged watchpoints.

Suggest to reword to make more concise:

  PowerPC embedded processors support masked watchpoints and ranged
  watchpoints.

> +A @dfn{masked watchpoint} is defined by an address and a mask.  It triggers
> +when the address of a memory access matches the watchpoint address when both
> +are masked by the watchpoint mask.  That is, the bits set in the mask determine
> +which bits are relevant in the address comparison.

This description is too code-oriented.  Dopes the following catch what
you wanted to say?

  A @dfn{masked watchpoint} specifies a mask in addition to an address
  to watch.  The mask specifies that some bits of an address (the bits
  which are reset in the mask) should be ignored when matching the
  address accessed by the inferior against the watchpoint address.
  Thus, a masked watchpoint watches many addresses
  simultaneously---those addresses whose unmasked bits are identical
  to the unmasked bits in the watchpoint address.

>                                                  To set a masked watchpoint
> +in @value{GDBN}, use the @code{mask} parameter in the @code{watch} command
                                        ^^^^^^^^^
"argument"

> +(see @ref{Set Watchpoints}), as in:
   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
"(@pxref{Set Watchpoints})"

> +A @dfn{ranged watchpoint} is defined by a start address and an end address
> +specifying a region of memory inside which any access will trigger the
> +watchpoint.  Both the start and end addresses are within the memory region.

"Defined by a start address and an end address" is inaccurate, because
it can also be defined by a start address and length.  But there's no
need to go into details here, since you are about to tell them anyway.
So I would say only this:

  A @dfn{ranged watchpoint} watches a contiguous range of addresses.

> +@item watch-range @var{start-address, +length}

@var{} should be used only for a single symbol.  It's not just a
markup, it also shows where each meta-syntactic variable starts and
ends.  Portions of the test that are not part of the symbol should not
be in @var{}.  So:

  @item watch-range @var{start-address}, +@var{length}
  @itemx watch-range @var{start-address}, @var{end-address}

And the same for the rest.

> +The watchpoint will stop execution of your program whenever the inferior
> +writes, reads, or accesses (respectively for watch-range, awatch-range
> +and rwatch-range) any address within the @code{[start-address, end-address]}
> +interval.         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   ^^^^^^^^
I would say "any address within the specified range".  This is more
concise and also more accurate, since end-address is not the only
possible way of specifying a range watchpoint.

> +	  printf_filtered (_("Empty search range.\n"));

"search range" or "address range"?  The former assumes the user wanted
to search something, but with range watchpoints this is not what the
user wants.

> +	error (_("Search space too large."));

Same here.

> +	error (_("Invalid search space, end preceeds start."));

And here.

> +	error (_("Invalid length."));

"Invalid (negative) length of address range."

> +      /* We don't support searching all of memory
> +	 (i.e. start=0, end = 0xff..ff).
> +	 Bail to avoid overflows later on.  */

"Bail out", I think.

> +  /* The watchpoint will trigger if the address of the memory access is
> +     within the defined range, as follows: p.addr <= address < p.addr2.  */
> +  p.addr            = (uint64_t) addr;
> +  p.addr2           = (uint64_t) addr + len;

But the documentation says that the end address is included, not
excluded.  Can we eliminate this source of confusion?

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

* Re: [patch 2/2] Implement support for PowerPC BookE masked and ranged watchpoints
  2010-10-23  9:07   ` Eli Zaretskii
@ 2010-10-30  1:59     ` Thiago Jung Bauermann
  2010-10-30  7:13       ` Eli Zaretskii
  0 siblings, 1 reply; 19+ messages in thread
From: Thiago Jung Bauermann @ 2010-10-30  1:59 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches

On Sat, 2010-10-23 at 11:07 +0200, Eli Zaretskii wrote:
> > From: Thiago Jung Bauermann <bauerman@br.ibm.com>
> > Date: Sat, 23 Oct 2010 02:22:41 -0200
> > 
> > This is a new version of the patch.
> 
> Thanks.

Thanks for your review! And thanks for your suggestions on new wording
for the documentation part. It really helps.

> > It doesn't rely on an old_ops field
> > in struct breakpoint. Instead, it makes the breakpoint_ops methods for
> > ranged watchpoint accept ranged software watchpoints (this was trivial
> > and involved only new cases in some print methods), and adds a
> > works_in_software_mode method which is called by update_watchpoint if it
> > determines that it needs to downgrade a hardware watchpoint to a
> > software watchpoint. In case it can't be done, it'll throw an exception.
> 
> In what cases will the software mode be used for ranged watchpoints?
> Does this mean that architectures that don't have hardware support for
> such watchpoints will be able to use them in software mode?

The BookE architecture needs two hardware watchpoint registers to create
a ranged hardware watchpoint, so GDB will create a ranged software
watchpoint when there's one or no watchpoint register available.

The version of the patch you reviewed wouldn't allow other architectures
to create ranged software watchpoints (it asked the hardware whether the
capability was available), though that was an unnecessary restriction.
This version allows ranged software watchpoints for all architectures.
(The change was made in the watch_range_command_1 function).

> And what about masked watchpoints -- can they also be used in software
> mode?

AFAIK, to implement masked watchpoints in software GDB would need to
decode each instruction to see which address it was trying to access.
This patch doesn't implement that, it would be hard work. If the target
doesn't allow masked hardware watchpoints, the watch command will error
out.

> I'm quite sure this was all mentioned in the discussions leading to
> this patch, so if I can read about that elsewhere, please just point
> me to the relevant thread.

No problem, I'd have difficulty finding the relevant e-mails myself. :-)

> > +	/* Since we don't know the exact trigger address (from
> > +	   stopped_data_address) Just tell the user we've triggered
> > +	   a mask watchpoint.  */
> 
> "Just" should be "just" (no capitalization).  And a comma before it
> would be appropriate, too.

Fixed.

> > +  mention (b);
> > +  ui_out_text (uiout, "\nCheck the underlying instruction \
> > +at PC for address and value related to this watchpoint trigger.\n");
> 
> Shouldn't this be in _() ?

Oops. Fixed.

> > +    case bp_hardware_watchpoint:
> > +      ui_out_text (uiout, "Masked hardware watchpoint ");
> 
> Isn't it better to say "Masked hardware (write) watchpoint"?

Here I'm following the current GDB behaviour. It says just "Hardware
watchpoint" for a bp_hardware_watchpoint.

> > +The watchpoint will stop execution of your program whenever the inferior\n\
> > +writes to any address within the [start-address, end-address] interval."));
> 
> The literal difference between "your program" and "the inferior" could
> confuse the user.  Suggest the following simplification:
> 
>   The watchpoint will stop execution of the inferior whenever it writes
>   to any address within the [start-address, end-address] interval.

Fixed.

> Also, isn't "range" better than "interval" here?

Fixed too.

> The same goes for all the other similar commands.

Fixed the other instances.

> > +  /* Tell how many additional hardware resources (debug registers) are needed
> > +     for this breakpoint.  We always count at least one resource.  If this
> > +     element is NULL, then no additional resource is accounted for.  */
> > +  int (*extra_resources_needed) (const struct breakpoint *);
> 
> I think the last sentence of the comment is unclear.  What does it
> mean "no resource is accounted for"?  If that's to say "no additional
> resources are needed", then why not say that explicitly?

I agree. I used your wording.

> > +  /* Display one line of extra information about this breakpoint,
> > +     for "info breakpoints".  */
> > +  void (*print_one_detail) (const struct breakpoint *, struct ui_out *);
> 
> Examples of such "extras" would be beneficial here.  Also, are there
> any limitations on this extra information, like maximum length?

I changed this part to:

  /* Display extra information about this breakpoint, below the normal
     breakpoint description in "info breakpoints".  In the example below,
     the line with "memory range: [0x10094354, 0x100943a2]" was printed
     by print_one_detail_ranged_watchpoint.

     (gdb) info breakpoints
     Num     Type           Disp Enb Address    What
     2       hw watchpoint  keep y              b
             memory range: [0x10094354, 0x100943a2]

     */
  void (*print_one_detail) (const struct breakpoint *, struct ui_out *);

What do you think?

> > +The @code{@r{[}mask @var{maskvalue}@r{]}} clause is used to create a masked
> > +watchpoint if the current architecture supports the feature (currently,
> > +only available in the PowerPC Embedded architecture.
> > +See @ref{PowerPC Embedded}).
> 
> First, using "clause" here is suboptimal.  I would suggest "argument"
> instead.

I used "clause" because the paragraph immediately above about the
"thread" argument uses "clause". This patch changes both instances to
"argument".

>   Second, the part in the parentheses is wrong: you cannot
> put several sentences in a parenthesis that itself is part of a
> sentence.  And third, you need a period after @ref{}, or else makeinfo
> will bitch at you.  How about the following rewording (which also
> avoids using the passive tense)?
> 
>   The @code{@r{[}mask @var{maskvalue}@r{]}} argument allows creation
>   of masked watchpoints, if the current architecture supports this
>   feature.  (Currently, this is only available on PowerPC Embedded
>   architecture, see @ref{PowerPC Embedded}.)

Adopted your text.

> > +PowerPC embedded processors support additional types of hardware watchpoints,
> > +namely masked watchpoints and ranged watchpoints.
> 
> Suggest to reword to make more concise:
> 
>   PowerPC embedded processors support masked watchpoints and ranged
>   watchpoints.

Indeed. Adopted your version.

> > +A @dfn{masked watchpoint} is defined by an address and a mask.  It triggers
> > +when the address of a memory access matches the watchpoint address when both
> > +are masked by the watchpoint mask.  That is, the bits set in the mask determine
> > +which bits are relevant in the address comparison.
> 
> This description is too code-oriented.  Dopes the following catch what
> you wanted to say?
> 
>   A @dfn{masked watchpoint} specifies a mask in addition to an address
>   to watch.  The mask specifies that some bits of an address (the bits
>   which are reset in the mask) should be ignored when matching the
>   address accessed by the inferior against the watchpoint address.
>   Thus, a masked watchpoint watches many addresses
>   simultaneously---those addresses whose unmasked bits are identical
>   to the unmasked bits in the watchpoint address.

It does. I adopted your version.

> >                                                  To set a masked watchpoint
> > +in @value{GDBN}, use the @code{mask} parameter in the @code{watch} command
>                                         ^^^^^^^^^
> "argument"

Fixed.

> > +(see @ref{Set Watchpoints}), as in:
>    ^^^^^^^^^^^^^^^^^^^^^^^^^^^
> "(@pxref{Set Watchpoints})"

Fixed.

> > +A @dfn{ranged watchpoint} is defined by a start address and an end address
> > +specifying a region of memory inside which any access will trigger the
> > +watchpoint.  Both the start and end addresses are within the memory region.
> 
> "Defined by a start address and an end address" is inaccurate, because
> it can also be defined by a start address and length.  But there's no
> need to go into details here, since you are about to tell them anyway.
> So I would say only this:
> 
>   A @dfn{ranged watchpoint} watches a contiguous range of addresses.

Adopted your wording.

> > +@item watch-range @var{start-address, +length}
> 
> @var{} should be used only for a single symbol.  It's not just a
> markup, it also shows where each meta-syntactic variable starts and
> ends.  Portions of the test that are not part of the symbol should not
> be in @var{}.  So:
> 
>   @item watch-range @var{start-address}, +@var{length}
>   @itemx watch-range @var{start-address}, @var{end-address}
> 
> And the same for the rest.

Thanks for the explanation. Fixed all occurrences.

> > +The watchpoint will stop execution of your program whenever the inferior
> > +writes, reads, or accesses (respectively for watch-range, awatch-range
> > +and rwatch-range) any address within the @code{[start-address, end-address]}
> > +interval.         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>    ^^^^^^^^
> I would say "any address within the specified range".  This is more
> concise and also more accurate, since end-address is not the only
> possible way of specifying a range watchpoint.

Fixed.

> > +	  printf_filtered (_("Empty search range.\n"));
> 
> "search range" or "address range"?  The former assumes the user wanted
> to search something, but with range watchpoints this is not what the
> user wants.
> 
> > +	error (_("Search space too large."));
> 
> Same here.
> 
> > +	error (_("Invalid search space, end preceeds start."));
> 
> And here.

I factored the function out of parse_find_args but forgot to change the
error messages. Changed "search space" and "search range" to "address
range" everywhere.

> > +	error (_("Invalid length."));
> 
> "Invalid (negative) length of address range."

Fixed.

> > +      /* We don't support searching all of memory
> > +	 (i.e. start=0, end = 0xff..ff).
> > +	 Bail to avoid overflows later on.  */
> 
> "Bail out", I think.

Fixed.

> > +  /* The watchpoint will trigger if the address of the memory access is
> > +     within the defined range, as follows: p.addr <= address < p.addr2.  */
> > +  p.addr            = (uint64_t) addr;
> > +  p.addr2           = (uint64_t) addr + len;
> 
> But the documentation says that the end address is included, not
> excluded.  Can we eliminate this source of confusion?

This code is in ppc-linux-nat.c right before calling ptrace to set the
watchpoint, so it just documents how the kernel/processor interprets the
parameters.

The user-facing code respects the semantics explained in the
documentation. Also, target_insert_ranged_watchpoint takes a start
address and a length as arguments and IMHO doesn't have this confusion.
-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center


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

	Implement support for PowerPC BookE masked and ranged watchpoints.

gdb/
	* breakpoint.c (update_watchpoint): Call breakpoint's
	breakpoint_ops.extra_resources_needed and
	breakpoint_ops.works_in_software_mode if available.
	(watchpoints_triggered): Handle the case of a hardware masked
	watchpoint trigger.
	(watchpoint_check): Handle the case of a hardware masked watchpoint
	trigger.
	(print_one_breakpoint_location): Call breakpoint's
	breakpoint_ops.print_one_detail if available.
	(hw_watchpoint_used_count): Call breakpoint's
	breakpoint_ops.extra_resources_needed if available.
	(insert_ranged_watchpoint, remove_ranged_watchpoint)
	(extra_resources_needed_ranged_watchpoint)
	(print_one_detail_ranged_watchpoint, print_mention_ranged_watchpoint)
	(print_recreate_ranged_watchpoint): New functions.
	(ranged_watchpoint_breakpoint_ops): New structure.
	(insert_masked_watchpoint, remove_masked_watchpoint)
	(extra_resources_needed_masked_watchpoint)
	(works_in_software_mode_masked_watchpoint, print_it_masked_watchpoint)
	(print_one_detail_masked_watchpoint, print_mention_masked_watchpoint)
	(print_recreate_masked_watchpoint, is_masked_watchpoint): New functions.
	(masked_watchpoint_breakpoint_ops): New structure.
	(watch_command_1): Check for the existence of the `mask' parameter.
	Check whether a ranged hardware watchpoint can be used. Set b->ops
	according to the type of hardware watchpoint being created.
	(watch_range_command_1, watch_range_command)
	(awatch_range_command, rwatch_range_command): New functions.
	(_initialize_breakpoint): Register watch-range, awatch-range and
	rwatch-range commands.
	* breakpoint.h (struct ui_out): New opaque declaration.
	(struct breakpoint_ops) <extra_resources_needed>,
	<works_in_software_mode>, <print_one_detail>: New methods.  Initialize them
	to NULL in all existing breakpoint_ops instances.
	(struct breakpoint_ops) <print_it>: Add OLD_VAL parameter.  Update all
	implementations of the method.
	(enum hw_point_flag): New enumeration.
	(struct breakpoint) <hw_wp_mask>: New field.
	* findcmd.c (parse_addr_range): New function factored out of
	parse_find_args.
	(parse_find_args): Call `parse_addr_range'.
	* ppc-linux-nat.c (ppc_linux_can_use_special_hw_point): New function.
	(ppc_linux_region_ok_for_hw_watchpoint): Always handle regions when
	ranged watchpoints are available.
	(ppc_linux_insert_mask_watchpoint, ppc_linux_remove_mask_watchpoint)
	(ppc_linux_insert_ranged_watchpoint, ppc_linux_remove_ranged_watchpoint)
	(ppc_linux_hw_point_extra_slot_count): New functions.
	(_initialize_ppc_linux_nat): Initialize to_insert_mask_watchpoint,
	to_remove_mask_watchpoint, to_insert_ranged_watchpoint,
	to_remove_ranged_watchpoint, hw_point_extra_slot_count and
	to_can_use_special_hw_point.
	* target.c (update_current_target): Insert to_insert_mask_watchpoint,
	to_remove_mask_watchpoint, to_insert_ranged_watchpoint,
	to_remove_ranged_watchpoint, to_hw_point_extra_slot_count
	and to_can_use_special_hw_point.
	* target.h (enum hw_point_flag): New opaque declaration.
	(struct target_ops) <to_insert_mask_watchpoint>,
	<to_remove_mask_watchpoint>, <to_insert_ranged_watchpoint>,
	<to_remove_ranged_watchpoint>, <to_hw_point_extra_slot_count>,
	<to_can_use_special_hw_point>: New callbacks.
	(target_insert_mask_watchpoint, target_remove_mask_watchpoint)
	(target_insert_ranged_watchpoint, target_remove_ranged_watchpoint)
	(target_hw_point_extra_slot_count, target_can_use_special_hw_point): New
	defines.
	* ui-out.c (ui_out_field_range_core_addr): New function.
	* ui-out.h (ui_out_field_range_core_addr): Declare.
	* value.h (parse_addr_range): Declare.

gdb/doc/
	* gdb.texinfo (Set Watchpoints): Document mask parameter.
	(PowerPC Embedded): Document masked watchpoints and ranged watchpoints.


diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index ea71ea2..4f438ed 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10756,7 +10756,7 @@ print_recreate_exception (enum exception_catchpoint_kind ex,
 /* Virtual table for "catch exception" breakpoints.  */
 
 static enum print_stop_action
-print_it_catch_exception (struct breakpoint *b)
+print_it_catch_exception (struct breakpoint *b, const struct value *old_val)
 {
   return print_it_exception (ex_catch_exception, b);
 }
@@ -10784,8 +10784,11 @@ static struct breakpoint_ops catch_exception_breakpoint_ops =
   NULL, /* insert */
   NULL, /* remove */
   NULL, /* breakpoint_hit */
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_exception,
   print_one_catch_exception,
+  NULL, /* print_one_detail */
   print_mention_catch_exception,
   print_recreate_catch_exception
 };
@@ -10793,7 +10796,8 @@ static struct breakpoint_ops catch_exception_breakpoint_ops =
 /* Virtual table for "catch exception unhandled" breakpoints.  */
 
 static enum print_stop_action
-print_it_catch_exception_unhandled (struct breakpoint *b)
+print_it_catch_exception_unhandled (struct breakpoint *b,
+				    const struct value *old_val)
 {
   return print_it_exception (ex_catch_exception_unhandled, b);
 }
@@ -10822,8 +10826,11 @@ static struct breakpoint_ops catch_exception_unhandled_breakpoint_ops = {
   NULL, /* insert */
   NULL, /* remove */
   NULL, /* breakpoint_hit */
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_exception_unhandled,
   print_one_catch_exception_unhandled,
+  NULL, /* print_one_detail */
   print_mention_catch_exception_unhandled,
   print_recreate_catch_exception_unhandled
 };
@@ -10831,7 +10838,7 @@ static struct breakpoint_ops catch_exception_unhandled_breakpoint_ops = {
 /* Virtual table for "catch assert" breakpoints.  */
 
 static enum print_stop_action
-print_it_catch_assert (struct breakpoint *b)
+print_it_catch_assert (struct breakpoint *b, const struct value *old_val)
 {
   return print_it_exception (ex_catch_assert, b);
 }
@@ -10858,8 +10865,11 @@ static struct breakpoint_ops catch_assert_breakpoint_ops = {
   NULL, /* insert */
   NULL, /* remove */
   NULL, /* breakpoint_hit */
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_assert,
   print_one_catch_assert,
+  NULL, /* print_one_detail */
   print_mention_catch_assert,
   print_recreate_catch_assert
 };
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 04878be..14e8fd0 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -219,6 +219,8 @@ static void disable_trace_command (char *, int);
 
 static void trace_pass_command (char *, int);
 
+static int is_masked_watchpoint (const struct breakpoint *b);
+
 /* Assuming we're creating a static tracepoint, does S look like a
    static tracepoint marker spec ("-m MARKER_ID")?  */
 #define is_marker_spec(s)						\
@@ -1391,27 +1393,52 @@ update_watchpoint (struct breakpoint *b, int reparse)
 	if ((b->type == bp_watchpoint || b->type == bp_hardware_watchpoint)
 	    && reparse)
 	  {
-	    int i, mem_cnt, other_type_used;
-
-	    /* We need to determine how many resources are already used
-	       for all other hardware watchpoints to see if we still have
-	       enough resources to also fit this watchpoint in as well.
-	       To avoid the hw_watchpoint_used_count call below from counting
-	       this watchpoint, make sure that it is marked as a software
-	       watchpoint.  */
-	    b->type = bp_watchpoint;
-	    i = hw_watchpoint_used_count (bp_hardware_watchpoint,
-					  &other_type_used);
+	    int mem_cnt;
+
 	    mem_cnt = can_use_hardware_watchpoint (val_chain);
 
 	    if (!mem_cnt)
-	      b->type = bp_watchpoint;
+	      {
+		if (b->type == bp_hardware_watchpoint
+		    && b->ops && b->ops->works_in_software_mode
+		    && !b->ops->works_in_software_mode (b))
+		  error (_("This watchpoint cannot be used in software mode."));
+		else
+		  b->type = bp_watchpoint;
+	      }
 	    else
 	      {
-		int target_resources_ok = target_can_use_hardware_watchpoint
-		  (bp_hardware_watchpoint, i + mem_cnt, other_type_used);
+		int i, other_type_used, target_resources_ok;
+		enum bptype orig_type;
+
+		if (b->ops && b->ops->extra_resources_needed)
+		  mem_cnt += b->ops->extra_resources_needed (b);
+
+		/* We need to determine how many resources are already used
+		   for all other hardware watchpoints to see if we still have
+		   enough resources to also fit this watchpoint in as well.
+		   To avoid the hw_watchpoint_used_count call below from
+		   counting this watchpoint, make sure that it is marked as a
+		   software watchpoint.  */
+		orig_type = b->type;
+		b->type = bp_watchpoint;
+		i = hw_watchpoint_used_count (bp_hardware_watchpoint,
+					      &other_type_used);
+
+		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;
+		  {
+		    if (orig_type == bp_hardware_watchpoint
+			&& b->ops && b->ops->works_in_software_mode
+			&& !b->ops->works_in_software_mode (b))
+		      {
+			b->type = bp_hardware_watchpoint;
+			error (_("This watchpoint cannot be used in software mode."));
+		      }
+		    else
+		      b->type = bp_watchpoint;
+		  }
 		else
 		  b->type = bp_hardware_watchpoint;
 	      }
@@ -3368,7 +3395,7 @@ print_bp_stop_message (bpstat bs)
 	   print_it_typical.  */
 	/* FIXME: how breakpoint can ever be NULL here?  */
 	if (b != NULL && b->ops != NULL && b->ops->print_it != NULL)
-	  return b->ops->print_it (b);
+	  return b->ops->print_it (b, bs->old_val);
 	else
 	  return print_it_typical (bs);
       }
@@ -3504,15 +3531,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 (is_masked_watchpoint (loc->owner))
+	      {
+		newaddr = addr & loc->owner->hw_wp_mask;
+		start = loc->address & loc->owner->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;
@@ -3626,6 +3668,11 @@ watchpoint_check (void *p)
 	  b->val_valid = 1;
 	  return WP_VALUE_CHANGED;
 	}
+      else if (is_masked_watchpoint (b))
+	/* 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.  */
@@ -4696,9 +4743,12 @@ print_one_breakpoint_location (struct breakpoint *b,
 	  ui_out_field_int (uiout, "task", b->task);
 	}
     }
-  
+
   ui_out_text (uiout, "\n");
-  
+
+  if (!part_of_multiple && b->ops && b->ops->print_one_detail)
+    b->ops->print_one_detail (b, uiout);
+
   if (!part_of_multiple && b->static_trace_marker_id)
     {
       gdb_assert (b->type == bp_static_tracepoint);
@@ -5869,7 +5919,7 @@ breakpoint_hit_catch_fork (struct breakpoint *b)
 /* Implement the "print_it" breakpoint_ops method for fork catchpoints.  */
 
 static enum print_stop_action
-print_it_catch_fork (struct breakpoint *b)
+print_it_catch_fork (struct breakpoint *b, const struct value *old_val)
 {
   annotate_catchpoint (b->number);
   printf_filtered (_("\nCatchpoint %d (forked process %d), "),
@@ -5927,8 +5977,11 @@ static struct breakpoint_ops catch_fork_breakpoint_ops =
   insert_catch_fork,
   remove_catch_fork,
   breakpoint_hit_catch_fork,
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_fork,
   print_one_catch_fork,
+  NULL, /* print_one_detail */
   print_mention_catch_fork,
   print_recreate_catch_fork
 };
@@ -5961,7 +6014,7 @@ breakpoint_hit_catch_vfork (struct breakpoint *b)
 /* Implement the "print_it" breakpoint_ops method for vfork catchpoints.  */
 
 static enum print_stop_action
-print_it_catch_vfork (struct breakpoint *b)
+print_it_catch_vfork (struct breakpoint *b, const struct value *old_val)
 {
   annotate_catchpoint (b->number);
   printf_filtered (_("\nCatchpoint %d (vforked process %d), "),
@@ -6018,8 +6071,11 @@ static struct breakpoint_ops catch_vfork_breakpoint_ops =
   insert_catch_vfork,
   remove_catch_vfork,
   breakpoint_hit_catch_vfork,
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_vfork,
   print_one_catch_vfork,
+  NULL, /* print_one_detail */
   print_mention_catch_vfork,
   print_recreate_catch_vfork
 };
@@ -6139,7 +6195,7 @@ breakpoint_hit_catch_syscall (struct breakpoint *b)
    catchpoints.  */
 
 static enum print_stop_action
-print_it_catch_syscall (struct breakpoint *b)
+print_it_catch_syscall (struct breakpoint *b, const struct value *old_val)
 {
   /* These are needed because we want to know in which state a
      syscall is.  It can be in the TARGET_WAITKIND_SYSCALL_ENTRY
@@ -6299,8 +6355,11 @@ static struct breakpoint_ops catch_syscall_breakpoint_ops =
   insert_catch_syscall,
   remove_catch_syscall,
   breakpoint_hit_catch_syscall,
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_syscall,
   print_one_catch_syscall,
+  NULL, /* print_one_detail */
   print_mention_catch_syscall,
   print_recreate_catch_syscall
 };
@@ -6402,7 +6461,7 @@ breakpoint_hit_catch_exec (struct breakpoint *b)
 }
 
 static enum print_stop_action
-print_it_catch_exec (struct breakpoint *b)
+print_it_catch_exec (struct breakpoint *b, const struct value *old_val)
 {
   annotate_catchpoint (b->number);
   printf_filtered (_("\nCatchpoint %d (exec'd %s), "), b->number,
@@ -6452,8 +6511,11 @@ static struct breakpoint_ops catch_exec_breakpoint_ops =
   insert_catch_exec,
   remove_catch_exec,
   breakpoint_hit_catch_exec,
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_exec,
   print_one_catch_exec,
+  NULL, /* print_one_detail */
   print_mention_catch_exec,
   print_recreate_catch_exec
 };
@@ -6501,7 +6563,14 @@ hw_watchpoint_used_count (enum bptype type, int *other_type_used)
     if (breakpoint_enabled (b))
       {
 	if (b->type == type)
-	  i++;
+	  {
+	    i++;
+
+	    /* Special types of hardware watchpoints can use more than
+	       one register.  */
+	    if (b->ops && b->ops->extra_resources_needed)
+	      i += b->ops->extra_resources_needed (b);
+	  }
 	else if (is_hardware_watchpoint (b))
 	  *other_type_used = 1;
       }
@@ -8043,12 +8112,353 @@ static struct breakpoint_ops watchpoint_breakpoint_ops =
   insert_watchpoint,
   remove_watchpoint,
   NULL, /* breakpoint_hit */
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
   NULL, /* print_it */
   NULL, /* print_one */
+  NULL, /* print_one_detail */
   NULL, /* print_mention */
   NULL  /* print_recreate */
 };
 
+/* Implement the "insert" breakpoint_ops method for
+   ranged hardware watchpoints.  */
+
+static int
+insert_ranged_watchpoint (struct bp_location *bpt)
+{
+  return target_insert_ranged_watchpoint (bpt->address,
+					  bpt->length,
+					  bpt->watchpoint_type);
+}
+
+/* Implement the "remove" breakpoint_ops method for
+   ranged hardware watchpoints.  */
+
+static int
+remove_ranged_watchpoint (struct bp_location *bpt)
+{
+  return target_remove_ranged_watchpoint (bpt->address, bpt->length,
+					  bpt->watchpoint_type);
+}
+
+/* Implement the "extra_resources_needed" breakpoint_ops method for
+   ranged hardware watchpoints.  */
+
+static int
+extra_resources_needed_ranged_watchpoint (const struct breakpoint *b)
+{
+  return target_hw_point_extra_slot_count (HW_POINT_RANGED_WATCH);
+}
+
+/* Implement the "print_one_detail" breakpoint_ops method for
+   ranged hardware watchpoints.  */
+
+static void
+print_one_detail_ranged_watchpoint (const struct breakpoint *b, struct ui_out *uiout)
+{
+  /* If there's a separate expression for reparsing, then exp_string is already
+     a nice text set by watch_range_command_1 and was printed earlier.  */
+  if (b->exp_string_reparse)
+    return;
+
+  gdb_assert (b->loc);
+
+  ui_out_text (uiout, "\tmemory range: ");
+  ui_out_field_range_core_addr (uiout, "addr", b->loc->gdbarch,
+				b->loc->address, b->loc->length);
+  ui_out_text (uiout, "\n");
+}
+
+/* Implement the "print_mention" breakpoint_ops method for
+   ranged hardware watchpoints.  */
+
+static void
+print_mention_ranged_watchpoint (struct breakpoint *b)
+{
+  struct cleanup *ui_out_chain;
+
+  switch (b->type)
+    {
+    case bp_watchpoint:
+      ui_out_text (uiout, "Ranged watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt");
+      break;
+    case bp_hardware_watchpoint:
+      ui_out_text (uiout, "Ranged hardware watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt");
+      break;
+    case bp_read_watchpoint:
+      ui_out_text (uiout, "Ranged hardware read watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-rwpt");
+      break;
+    case bp_access_watchpoint:
+      ui_out_text (uiout, "Ranged hardware access (read/write) watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-awpt");
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  ui_out_field_int (uiout, "number", b->number);
+  ui_out_text (uiout, ": ");
+  ui_out_field_string (uiout, "exp", b->exp_string);
+  do_cleanups (ui_out_chain);
+}
+
+static void
+print_recreate_ranged_watchpoint (struct breakpoint *b, struct ui_file *fp)
+{
+  switch (b->type)
+    {
+    case bp_watchpoint:
+    case bp_hardware_watchpoint:
+      if (b->exp_string_reparse)
+	fprintf_unfiltered (fp, "watch-range");
+      else
+	fprintf_unfiltered (fp, "watch");
+      break;
+    case bp_read_watchpoint:
+      if (b->exp_string_reparse)
+	fprintf_unfiltered (fp, "rwatch-range");
+      else
+	fprintf_unfiltered (fp, "rwatch");
+      break;
+    case bp_access_watchpoint:
+      if (b->exp_string_reparse)
+	fprintf_unfiltered (fp, "awatch-range");
+      else
+	fprintf_unfiltered (fp, "awatch");
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  if (b->exp_string_reparse)
+    {
+      char start_addr[40], length[40];
+
+      /* watch_range_command_1 creates the following expression to represent
+	 internally a ranged watchpoint.  */
+      sscanf (b->exp_string_reparse, "{char[ %39s ]} %39s", length, start_addr);
+
+      fprintf_unfiltered (fp, " %s, +%s", start_addr, length);
+    }
+  else
+    fprintf_unfiltered (fp, " %s", b->exp_string);
+}
+
+/* The breakpoint_ops structure to be used in ranged hardware watchpoints.  */
+
+static struct breakpoint_ops ranged_watchpoint_breakpoint_ops =
+{
+  insert_ranged_watchpoint,
+  remove_ranged_watchpoint,
+  NULL, /* breakpoint_hit */
+  extra_resources_needed_ranged_watchpoint,
+  NULL, /* works_in_software_mode */
+  NULL, /* print_it */
+  NULL, /* print_one */
+  print_one_detail_ranged_watchpoint,
+  print_mention_ranged_watchpoint,
+  print_recreate_ranged_watchpoint
+};
+
+/* Implement the "insert" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static int
+insert_masked_watchpoint (struct bp_location *bpt)
+{
+  return target_insert_mask_watchpoint (bpt->address, bpt->owner->hw_wp_mask,
+					bpt->watchpoint_type);
+}
+
+/* Implement the "remove" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static int
+remove_masked_watchpoint (struct bp_location *bpt)
+{
+  return target_remove_mask_watchpoint (bpt->address, bpt->owner->hw_wp_mask,
+				        bpt->watchpoint_type);
+}
+
+/* Implement the "extra_resources_needed" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static int
+extra_resources_needed_masked_watchpoint (const struct breakpoint *b)
+{
+  return target_hw_point_extra_slot_count (HW_POINT_MASKED_WATCH);
+}
+
+/* Implement the "works_in_software_mode_masked_watchpoint" breakpoint_ops
+   method for masked hardware watchpoints.  */
+
+static int
+works_in_software_mode_masked_watchpoint (const struct breakpoint *b)
+{
+  return 0;
+}
+
+/* Implement the "print_it" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static enum print_stop_action
+print_it_masked_watchpoint (struct breakpoint *b, const struct value *old_val)
+{
+  struct ui_stream *stb;
+  struct cleanup *old_chain;
+
+  stb = ui_out_stream_new (uiout);
+  old_chain = make_cleanup_ui_out_stream_delete (stb);
+
+  switch (b->type)
+    {
+    case bp_hardware_watchpoint:
+      annotate_watchpoint (b->number);
+      if (ui_out_is_mi_like_p (uiout))
+	ui_out_field_string
+	  (uiout, "reason",
+	   async_reason_lookup (EXEC_ASYNC_WATCHPOINT_TRIGGER));
+      break;
+
+    case bp_read_watchpoint:
+      if (ui_out_is_mi_like_p (uiout))
+	ui_out_field_string
+	  (uiout, "reason",
+	   async_reason_lookup (EXEC_ASYNC_READ_WATCHPOINT_TRIGGER));
+      break;
+
+    case bp_access_watchpoint:
+      if (old_val != NULL)
+	{
+	  annotate_watchpoint (b->number);
+	  if (ui_out_is_mi_like_p (uiout))
+	    ui_out_field_string
+	      (uiout, "reason",
+	       async_reason_lookup (EXEC_ASYNC_ACCESS_WATCHPOINT_TRIGGER));
+	}
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  mention (b);
+  ui_out_text (uiout, _("\nCheck the underlying instruction \
+at PC for address and value related to this watchpoint trigger.\n"));
+  ui_out_text (uiout, "\n");
+
+  do_cleanups (old_chain);
+
+  /* More than one watchpoint may have been triggered.  */
+  return PRINT_UNKNOWN;
+}
+
+/* Implement the "print_one_detail" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static void
+print_one_detail_masked_watchpoint (const struct breakpoint *b, struct ui_out *uiout)
+{
+  ui_out_text (uiout, "\tmask ");
+
+  /* I don't know whether it's possible to get here without a b->loc,
+     but we can handle the situation.  */
+  if (b->loc)
+    ui_out_field_core_addr (uiout, "mask", b->loc->gdbarch, b->hw_wp_mask);
+  else
+    ui_out_field_string (uiout, "mask", core_addr_to_string (b->hw_wp_mask));
+
+  ui_out_text (uiout, "\n");
+}
+
+/* Implement the "print_mention" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static void
+print_mention_masked_watchpoint (struct breakpoint *b)
+{
+  struct cleanup *ui_out_chain;
+
+  switch (b->type)
+    {
+    case bp_hardware_watchpoint:
+      ui_out_text (uiout, "Masked hardware watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt");
+      break;
+    case bp_read_watchpoint:
+      ui_out_text (uiout, "Masked hardware read watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-rwpt");
+      break;
+    case bp_access_watchpoint:
+      ui_out_text (uiout, "Masked hardware access (read/write) watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-awpt");
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  ui_out_field_int (uiout, "number", b->number);
+  ui_out_text (uiout, ": ");
+  ui_out_field_string (uiout, "exp", b->exp_string);
+  do_cleanups (ui_out_chain);
+}
+
+static void
+print_recreate_masked_watchpoint (struct breakpoint *b, struct ui_file *fp)
+{
+  char tmp[40];
+
+  switch (b->type)
+    {
+    case bp_hardware_watchpoint:
+      fprintf_unfiltered (fp, "watch");
+      break;
+    case bp_read_watchpoint:
+      fprintf_unfiltered (fp, "rwatch");
+      break;
+    case bp_access_watchpoint:
+      fprintf_unfiltered (fp, "awatch");
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  sprintf_vma (tmp, b->hw_wp_mask);
+  fprintf_unfiltered (fp, " %s mask 0x%s", b->exp_string, tmp);
+}
+
+/* The breakpoint_ops structure to be used in masked hardware watchpoints.  */
+
+static struct breakpoint_ops masked_watchpoint_breakpoint_ops =
+{
+  insert_masked_watchpoint,
+  remove_masked_watchpoint,
+  NULL, /* breakpoint_hit */
+  extra_resources_needed_masked_watchpoint,
+  works_in_software_mode_masked_watchpoint,
+  print_it_masked_watchpoint,
+  NULL, /* print_one */
+  print_one_detail_masked_watchpoint,
+  print_mention_masked_watchpoint,
+  print_recreate_masked_watchpoint
+};
+
+/* Tells whether the given watchpoint is a masked hardware watchpoint.  */
+
+static int
+is_masked_watchpoint (const struct breakpoint *b)
+{
+  return b->ops == &masked_watchpoint_breakpoint_ops;
+}
+
 /* accessflag:  hw_write:  watch write, 
                 hw_read:   watch read, 
 		hw_access: watch access (read or write) */
@@ -8062,8 +8472,8 @@ watch_command_1 (char *arg, int accessflag, int from_tty, int just_location)
   struct frame_info *frame;
   char *exp_start = NULL;
   char *exp_end = NULL;
-  char *tok, *id_tok_start, *end_tok;
-  int toklen;
+  char *tok, *end_tok;
+  int toklen = -1;
   char *cond_start = NULL;
   char *cond_end = NULL;
   int i, other_type_used, target_resources_ok = 0;
@@ -8071,66 +8481,98 @@ watch_command_1 (char *arg, int accessflag, int from_tty, int just_location)
   int mem_cnt = 0;
   int thread = -1;
   int pc = 0;
+  /* 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;
 
   /* Make sure that we actually have parameters to parse.  */
   if (arg != NULL && arg[0] != '\0')
     {
-      toklen = strlen (arg); /* Size of argument list.  */
+      char *value_start;
+
+      /* Look for "parameter value" pairs at the end
+	 of the arguments string.  */
+      for (tok = arg + strlen (arg) - 1; tok > arg; tok--)
+	{
+	  /* Skip whitespace at the end of the argument list.  */
+	  while (tok > arg && (*tok == ' ' || *tok == '\t'))
+	    tok--;
+
+	  /* Find the beginning of the last token.
+	     This is the value of the parameter.  */
+	  while (tok > arg && (*tok != ' ' && *tok != '\t'))
+	    tok--;
+	  value_start = tok + 1;
+
+	  /* Skip whitespace.  */
+	  while (tok > arg && (*tok == ' ' || *tok == '\t'))
+	    tok--;
+
+	  end_tok = tok;
+
+	  /* Find the beginning of the second to last token.
+	     This is the parameter itself.  */
+	  while (tok > arg && (*tok != ' ' && *tok != '\t'))
+	    tok--;
+	  tok++;
+	  toklen = end_tok - tok + 1;
+
+	  if (toklen == 6 && !strncmp (tok, "thread", 6))
+	    {
+	      /* 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;
 
-      /* Points tok to the end of the argument list.  */
-      tok = arg + toklen - 1;
+	      if (thread != -1)
+		error(_("You can specify only one thread."));
 
-      /* 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--;
+	      /* Extract the thread ID from the next token.  */
+	      thread = strtol (value_start, &endp, 0);
 
-      /* Points end_tok to the beginning of the last token.  */
-      id_tok_start = tok + 1;
+	      /* 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."), value_start);
 
-      /* 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--;
+	      /* Check if the thread actually exists.  */
+	      if (!valid_thread_id (thread))
+		error (_("Unknown thread %d."), thread);
+	    }
+	  else if (toklen == 4 && !strncmp (tok, "mask", 4))
+	    {
+	      /* We've found a "mask" token, which means the user wants to
+		 create a hardware watchpoint that is going to have the mask
+		 facility.  */
+	      struct value *mask_value, *mark;
 
-      end_tok = tok;
+	      /* Does the target support masked watchpoints?  */
+	      if (!target_can_use_special_hw_point (HW_POINT_MASKED_WATCH))
+		error (_("\
+This target does not support the usage of masks with hardware watchpoints."));
 
-      while (tok > arg && (*tok != ' ' && *tok != '\t'))
-        tok--;
+	      if (use_mask)
+		error(_("You can specify only one mask."));
 
-      /* Move the pointer forward to skip the whitespace and
-         calculate the length of the token.  */
-      tok++;
-      toklen = end_tok - tok;
+	      use_mask = 1;
 
-      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';
-        }
+	      mark = value_mark ();
+	      mask_value = parse_to_comma_and_eval (&value_start);
+	      hw_wp_mask = value_as_address (mask_value);
+	      value_free_to_mark (mark);
+	    }
+	  else
+	    /* We didn't recognize what we found.  We should stop here.  */
+	    break;
+
+	  /* Truncate the string and get rid of the "parameter value" pair before
+	     the arguments string is parsed by the parse_exp_1 function.  */
+	  *tok = '\0';
+	}
     }
 
   /* Parse the rest of the arguments.  */
@@ -8208,6 +8650,22 @@ watch_command_1 (char *arg, int accessflag, int from_tty, int just_location)
     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 (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, 
@@ -8219,10 +8677,22 @@ watch_command_1 (char *arg, int accessflag, int from_tty, int just_location)
 	error (_("Target can only support one kind of HW watchpoint at a time."));
     }
 
-  /* 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 && !mem_cnt)
+	error (_("Cannot use masks with the given expression."));
+      else if (use_mask && target_resources_ok <= 0)
+	error (_("\
+Cannot use masks without enough available hardware watchpoints (need %d)."),
+	       mem_cnt);
+      else
+	{
+	  /* Change the type of breakpoint to an ordinary watchpoint if a
+	     hardware watchpoint could not be set.  */
+	  bp_type = bp_watchpoint;
+	  use_ranged = 0;
+	}
+    }
 
   frame = block_innermost_frame (exp_valid_block);
 
@@ -8291,7 +8761,16 @@ watch_command_1 (char *arg, int accessflag, int from_tty, int just_location)
     b->exp_string = savestring (exp_start, exp_end - exp_start);
   b->val = val;
   b->val_valid = 1;
-  b->ops = &watchpoint_breakpoint_ops;
+
+  if (use_mask)
+    {
+      b->hw_wp_mask = hw_wp_mask;
+      b->ops = &masked_watchpoint_breakpoint_ops;
+    }
+  else if (use_ranged)
+    b->ops = &ranged_watchpoint_breakpoint_ops;
+  else
+    b->ops = &watchpoint_breakpoint_ops;
 
   if (cond_start)
     b->cond_string = savestring (cond_start, cond_end - cond_start);
@@ -8478,6 +8957,99 @@ awatch_command (char *arg, int from_tty)
 {
   watch_maybe_just_location (arg, hw_access, from_tty);
 }
+
+static void
+watch_range_command_1 (char *arg, enum bptype type, int from_tty)
+{
+  char *exp_string, *string_p;
+  struct gdbarch *gdbarch = get_current_arch ();
+  int wp_count, other_type_used, can_use_wp, mem_cnt, pc = 0;
+  CORE_ADDR start_addr;
+  ULONGEST length;
+  struct breakpoint *b;
+  struct expression *exp;
+  struct symtab_and_line sal;
+  struct value *val;
+  struct cleanup *cleanups;
+
+  /* Check if we need hardware watchpoints, and if we have enough
+     of them available.  */
+
+  if (!can_use_hw_watchpoints && type != bp_hardware_watchpoint)
+    error (_("\
+Need watchpoint hardware for read and access watchpoints, but cannot use it\n\
+(see set can-use-hw-watchpoints)."));
+
+  mem_cnt = target_hw_point_extra_slot_count (HW_POINT_RANGED_WATCH) + 1;
+  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 || !can_use_hw_watchpoints)
+    {
+      if (type == bp_hardware_watchpoint)
+	/* Change the type of breakpoint to an ordinary watchpoint if a
+	   hardware watchpoint could not be set.  */
+	type = bp_watchpoint;
+      else
+	error (_("Not enough available hardware watchpoints (need %d)."),
+	       mem_cnt);
+    }
+
+  parse_addr_range (&arg, &start_addr, &length);
+
+  /* We need spaces around the brackets in the expression below so that
+     print_it_recreate_ranged_watchpoint can use scanf on it.  */
+  exp_string = string_p = xstrprintf ("{char[ %s ]} %s", pulongest (length),
+				      paddress (gdbarch, start_addr));
+  exp = parse_exp_1 (&string_p, 0, 0);
+  fetch_subexp_value (exp, &pc, &val, NULL, NULL);
+  if (val != NULL)
+    release_value (val);
+  cleanups = make_cleanup (xfree, exp_string);
+
+  init_sal (&sal);		/* initialize to zeroes */
+  sal.pspace = current_program_space;
+
+  /* Now set up the breakpoint.  */
+  b = set_raw_breakpoint (gdbarch, sal, type);
+  set_breakpoint_count (breakpoint_count + 1);
+  b->number = breakpoint_count;
+  b->thread = -1;
+  b->disposition = disp_donttouch;
+  b->exp = exp;
+  b->exp_string_reparse = exp_string;
+  b->exp_string = xstrprintf (_("range [%s, %s]"),
+			      paddress (gdbarch, start_addr),
+			      paddress (gdbarch, start_addr + length - 1));
+  b->ops = &ranged_watchpoint_breakpoint_ops;
+  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);
+}
+
 \f
 
 /* Helper routines for the until_command routine in infcmd.c.  Here
@@ -8715,7 +9287,8 @@ catch_exec_command_1 (char *arg, int from_tty,
 }
 
 static enum print_stop_action
-print_exception_catchpoint (struct breakpoint *b)
+print_it_exception_catchpoint (struct breakpoint *b,
+			       const struct value *old_val)
 {
   int bp_temp, bp_throw;
 
@@ -8804,8 +9377,11 @@ static struct breakpoint_ops gnu_v3_exception_catchpoint_ops = {
   NULL, /* insert */
   NULL, /* remove */
   NULL, /* breakpoint_hit */
-  print_exception_catchpoint,
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
+  print_it_exception_catchpoint,
   print_one_exception_catchpoint,
+  NULL, /* print_one_detail */
   print_mention_exception_catchpoint,
   print_recreate_exception_catchpoint
 };
@@ -12195,7 +12771,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 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 the inferior whenever it\n\
+writes to any address within the [start-address, end-address] 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 the inferior whenever it\n\
+accesses (reads from or writes to) any address within the\n\
+[start-address, end-address] 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 the inferior whenever it\n\
+reads from any address within the [start-address, end-address] range."));
+  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 1b66986..57dc74c 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -26,6 +26,7 @@
 
 struct value;
 struct block;
+struct ui_out;
 
 /* This is the maximum number of bytes a breakpoint instruction can take.
    Feel free to increase it.  It's just used in a few places to size
@@ -361,13 +362,37 @@ struct breakpoint_ops
      breakpoint was hit.  */
   int (*breakpoint_hit) (struct breakpoint *);
 
+  /* Tell how many additional hardware resources (debug registers) are needed
+     for this breakpoint.  We always count at least one resource.  If this
+     element is NULL, then no additional resources are needed.  */
+  int (*extra_resources_needed) (const struct breakpoint *);
+
+  /* Tell whether we can downgrade from a hardware watchpoint to a software
+     one.  If not, the user will not be able to enable the watchpoint when
+     there are not enough hardware resources available.  */
+  int (*works_in_software_mode) (const struct breakpoint *);
+
   /* The normal print routine for this breakpoint, called when we
      hit it.  */
-  enum print_stop_action (*print_it) (struct breakpoint *);
+  enum print_stop_action (*print_it) (struct breakpoint *,
+				      const struct value *old_val);
 
   /* Display information about this breakpoint, for "info breakpoints".  */
   void (*print_one) (struct breakpoint *, struct bp_location **);
 
+  /* Display extra information about this breakpoint, below the normal
+     breakpoint description in "info breakpoints".  In the example below,
+     the line with "memory range: [0x10094354, 0x100943a2]" was printed
+     by print_one_detail_ranged_watchpoint.
+
+     (gdb) info breakpoints
+     Num     Type           Disp Enb Address    What
+     2       hw watchpoint  keep y              b
+             memory range: [0x10094354, 0x100943a2]
+
+     */
+  void (*print_one_detail) (const struct breakpoint *, struct ui_out *);
+
   /* Display information about this breakpoint after setting it (roughly
      speaking; this is called from "mention").  */
   void (*print_mention) (struct breakpoint *);
@@ -400,6 +425,12 @@ DEF_VEC_P(bp_location_p);
    detail to the breakpoints module.  */
 struct counted_command_line;
 
+/* Special types of hardware breakpoints/watchpoints.  */
+enum hw_point_flag {
+	HW_POINT_RANGED_WATCH, /* Hardware ranged watchpoint.  */
+	HW_POINT_MASKED_WATCH  /* Hardware masked watchpoint.  */
+};
+
 /* Note that the ->silent field is not currently used by any commands
    (though the code is in there if it was to be, and set_raw_breakpoint
    does set it to 0).  I implemented it because I thought it would be
@@ -559,6 +590,9 @@ struct breakpoint
        breakpoints, we will use this index to try to find the same
        marker again.  */
     int static_trace_marker_id_idx;
+
+    /* The mask address for a hardware watchpoint.  */
+    CORE_ADDR hw_wp_mask;
   };
 
 typedef struct breakpoint *breakpoint_p;
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 9446932..ffe45fb 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -3711,7 +3711,7 @@ watchpoints, which do not slow down the running of your program.
 
 @table @code
 @kindex watch
-@item watch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]}
+@item watch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} @r{[}mask @var{maskvalue}@r{]}
 Set a watchpoint for an expression.  @value{GDBN} will break when the
 expression @var{expr} is written into by the program and its value
 changes.  The simplest (and the most popular) use of this command is
@@ -3722,12 +3722,17 @@ to watch the value of a single variable:
 @end smallexample
 
 If the command includes a @code{@r{[}thread @var{threadnum}@r{]}}
-clause, @value{GDBN} breaks only when the thread identified by
+argument, @value{GDBN} breaks only when the thread identified by
 @var{threadnum} changes the value of @var{expr}.  If any other threads
 change the value of @var{expr}, @value{GDBN} will not break.  Note
 that watchpoints restricted to a single thread in this way only work
 with Hardware Watchpoints.
 
+The @code{@r{[}mask @var{maskvalue}@r{]}} argument allows creation
+of masked watchpoints, if the current architecture supports this
+feature.  (Currently, this is only available on PowerPC Embedded
+architecture, see @ref{PowerPC Embedded}.)
+
 Ordinarily a watchpoint respects the scope of variables in @var{expr}
 (see below).  The @code{-location} argument tells @value{GDBN} to
 instead watch the memory referred to by @var{expr}.  In this case,
@@ -3738,12 +3743,12 @@ result does not have an address, then @value{GDBN} will print an
 error.
 
 @kindex rwatch
-@item rwatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]}
+@item rwatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} @r{[}mask @var{maskvalue}@r{]}
 Set a watchpoint that will break when the value of @var{expr} is read
 by the program.
 
 @kindex awatch
-@item awatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]}
+@item awatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} @r{[}mask @var{maskvalue}@r{]}
 Set a watchpoint that will break when @var{expr} is either read from
 or written into by the program.
 
@@ -18517,9 +18522,44 @@ The DVC register will be automatically used whenever @value{GDBN} detects
 such pattern in a condition expression.  This feature is available in native
 @value{GDBN} running on a Linux kernel version 2.6.34 or newer.
 
+PowerPC embedded processors support masked watchpoints and ranged watchpoints.
+
+A @dfn{masked watchpoint} specifies a mask in addition to an address
+to watch.  The mask specifies that some bits of an address (the bits
+which are reset in the mask) should be ignored when matching the
+address accessed by the inferior against the watchpoint address.
+Thus, a masked watchpoint watches many addresses
+simultaneously---those addresses whose unmasked bits are identical
+to the unmasked bits in the watchpoint address.
+
+To set a masked watchpoint in @value{GDBN}, use the @code{mask} argument in
+the @code{watch} command (@pxref{Set Watchpoints}), as in:
+
+@smallexample
+(@value{GDBP}) watch *0xdeadbeef mask 0xffffff00
+@end smallexample
+
+A @dfn{ranged watchpoint} watches a contiguous range of addresses.
+To set a ranged watchpoint in @value{GDBN}, use the @code{watch-range} command.
+In addition, @value{GDBN} automatically creates a ranged watchpoint when asked
+to watch an array or struct of known size and there are enough hardware
+registers available.
+
 @value{GDBN} provides the following PowerPC-specific commands:
 
 @table @code
+@kindex watch-range
+@item watch-range @var{start-address}, +@var{length}
+@itemx watch-range @var{start-address}, @var{end-address}
+@item rwatch-range @var{start-address}, +@var{length}
+@itemx rwatch-range @var{start-address}, @var{end-address}
+@item awatch-range @var{start-address}, +@var{length}
+@itemx awatch-range @var{start-address}, @var{end-address}
+Set a hardware watchpoint for an address range.
+The watchpoint will stop execution of your program whenever the inferior
+writes, reads, or accesses (respectively for watch-range, awatch-range
+and rwatch-range) any address within the specified range.
+
 @kindex set powerpc
 @item set powerpc soft-float
 @itemx show powerpc soft-float
diff --git a/gdb/findcmd.c b/gdb/findcmd.c
index ac63a9e..34b0dfe 100644
--- a/gdb/findcmd.c
+++ b/gdb/findcmd.c
@@ -45,6 +45,79 @@ 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.  Returns 1 on success, or 0 if an empty address range was given.  */
+
+int
+parse_addr_range (char **args, CORE_ADDR *start_addrp,
+		  ULONGEST *address_range_lenp)
+{
+  char *s = *args;
+  CORE_ADDR start_addr;
+  ULONGEST address_range_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)
+	{
+	  printf_filtered (_("Empty address range.\n"));
+	  return 0;
+	}
+      if (len < 0)
+	error (_("Invalid (negative) length of the address range."));
+      /* Watch for overflows.  */
+      if (len > CORE_ADDR_MAX
+	  || (start_addr + len - 1) < start_addr)
+	error (_("Address range too large."));
+      address_range_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 address range, end preceeds start."));
+      address_range_len = end_addr - start_addr + 1;
+      /* We don't support searching all of memory
+	 (i.e. start=0, end = 0xff..ff).
+	 Bail out to avoid overflows later on.  */
+      if (address_range_len == 0)
+	error (_("Overflow in address range computation, choose smaller range."));
+    }
+
+  if (*s == ',')
+    ++s;
+
+  *args = s;
+  *start_addrp = start_addr;
+  *address_range_lenp = address_range_len;
+
+  return 1;
+}
+
 /* Subroutine of find_command to simplify it.
    Parse the arguments of the "find" command.  */
 
@@ -114,53 +187,8 @@ 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;
+  if (!parse_addr_range (&s, &start_addr, &search_space_len))
+    return;
 
   /* Fetch the search string.  */
 
diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c
index 18ddee7..1de22ca 100644
--- a/gdb/ppc-linux-nat.c
+++ b/gdb/ppc-linux-nat.c
@@ -1478,6 +1478,28 @@ ppc_linux_can_use_hw_breakpoint (int type, int cnt, int ot)
 }
 
 static int
+ppc_linux_can_use_special_hw_point (enum hw_point_flag flag)
+{
+  uint64_t features;
+
+  if (!have_ptrace_booke_interface ())
+    return 0;
+
+  features = booke_debug_info.features;
+
+  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;
+      default:
+	internal_error (__FILE__, __LINE__,
+			_("Unknown hardware breakpoint/watchpoint type."));
+    }
+}
+
+static int
 ppc_linux_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
 {
   /* Handle sub-8-byte quantities.  */
@@ -1489,9 +1511,15 @@ ppc_linux_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
      to determine the hardcoded watchable region for watchpoints.  */
   if (have_ptrace_booke_interface ())
     {
-      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 (ppc_linux_can_use_special_hw_point (HW_POINT_RANGED_WATCH))
+	return 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
@@ -1685,6 +1713,106 @@ get_trigger_type (int rw)
   return t;
 }
 
+static int
+ppc_linux_insert_mask_watchpoint (CORE_ADDR addr, CORE_ADDR mask, int rw)
+{
+  ptid_t ptid;
+  struct lwp_info *lp;
+  struct ppc_hw_breakpoint p;
+
+  gdb_assert (have_ptrace_booke_interface ());
+
+  if ((mask & 0xC0000000) != 0xC0000000)
+    error (_("\
+The given mask covers kernel address space and cannot be used.\n\
+You have to delete the masked watchpoint to continue the debugging session."));
+
+  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) addr;
+  p.addr2           = (uint64_t) mask;
+  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, CORE_ADDR mask, int rw)
+{
+  ptid_t ptid;
+  struct lwp_info *lp;
+  struct ppc_hw_breakpoint p;
+
+  gdb_assert (have_ptrace_booke_interface ());
+
+  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) addr;
+  p.addr2           = (uint64_t) mask;
+  p.condition_value = 0;
+
+  ALL_LWPS (lp, ptid)
+    booke_remove_point (&p, TIDGET (ptid));
+
+  return 0;
+}
+
+static int
+ppc_linux_insert_ranged_watchpoint (CORE_ADDR addr, int len, int rw)
+{
+  ptid_t ptid;
+  struct lwp_info *lp;
+  struct ppc_hw_breakpoint p;
+
+  gdb_assert (have_ptrace_booke_interface ());
+
+  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.condition_value = 0;
+
+  /* The watchpoint will trigger if the address of the memory access is
+     within the defined range, as follows: p.addr <= address < p.addr2.  */
+  p.addr            = (uint64_t) addr;
+  p.addr2           = (uint64_t) addr + len;
+
+  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)
+{
+  ptid_t ptid;
+  struct lwp_info *lp;
+  struct ppc_hw_breakpoint p;
+
+  gdb_assert (have_ptrace_booke_interface ());
+
+  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;
+}
+
 /* Check whether we have at least one free DVC register.  */
 static int
 can_use_watchpoint_cond_accel (void)
@@ -2136,6 +2264,14 @@ ppc_linux_watchpoint_addr_within_range (struct target_ops *target,
   return start <= addr + mask && start + length - 1 >= addr;
 }
 
+static int
+ppc_linux_hw_point_extra_slot_count (enum hw_point_flag flag)
+{
+  gdb_assert (flag == HW_POINT_MASKED_WATCH || flag == HW_POINT_RANGED_WATCH);
+
+  return 1;
+}
+
 static void
 ppc_linux_store_inferior_registers (struct target_ops *ops,
 				    struct regcache *regcache, int regno)
@@ -2347,12 +2483,18 @@ _initialize_ppc_linux_nat (void)
   t->to_insert_hw_breakpoint = ppc_linux_insert_hw_breakpoint;
   t->to_remove_hw_breakpoint = ppc_linux_remove_hw_breakpoint;
   t->to_region_ok_for_hw_watchpoint = ppc_linux_region_ok_for_hw_watchpoint;
+  t->to_can_use_special_hw_point = ppc_linux_can_use_special_hw_point;
   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_stopped_by_watchpoint = ppc_linux_stopped_by_watchpoint;
   t->to_stopped_data_address = ppc_linux_stopped_data_address;
   t->to_watchpoint_addr_within_range = ppc_linux_watchpoint_addr_within_range;
   t->to_can_accel_watchpoint_condition = ppc_linux_can_accel_watchpoint_condition;
+  t->to_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/target.c b/gdb/target.c
index dd976c9..a9058a3 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -601,11 +601,16 @@ update_current_target (void)
       INHERIT (to_files_info, t);
       INHERIT (to_insert_breakpoint, t);
       INHERIT (to_remove_breakpoint, t);
+      INHERIT (to_can_use_special_hw_point, t);
       INHERIT (to_can_use_hw_breakpoint, t);
       INHERIT (to_insert_hw_breakpoint, t);
       INHERIT (to_remove_hw_breakpoint, t);
       INHERIT (to_insert_watchpoint, t);
       INHERIT (to_remove_watchpoint, t);
+      INHERIT (to_insert_ranged_watchpoint, t);
+      INHERIT (to_remove_ranged_watchpoint, t);
+      INHERIT (to_insert_mask_watchpoint, t);
+      INHERIT (to_remove_mask_watchpoint, t);
       INHERIT (to_stopped_data_address, t);
       INHERIT (to_have_steppable_watchpoint, t);
       INHERIT (to_have_continuable_watchpoint, t);
@@ -613,6 +618,7 @@ update_current_target (void)
       INHERIT (to_watchpoint_addr_within_range, t);
       INHERIT (to_region_ok_for_hw_watchpoint, t);
       INHERIT (to_can_accel_watchpoint_condition, 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);
@@ -727,6 +733,9 @@ update_current_target (void)
   de_fault (to_can_use_hw_breakpoint,
 	    (int (*) (int, int, int))
 	    return_zero);
+  de_fault (to_can_use_special_hw_point,
+	    (int (*) (enum hw_point_flag))
+	    return_zero);
   de_fault (to_insert_hw_breakpoint,
 	    (int (*) (struct gdbarch *, struct bp_target_info *))
 	    return_minus_one);
@@ -739,6 +748,18 @@ update_current_target (void)
   de_fault (to_remove_watchpoint,
 	    (int (*) (CORE_ADDR, int, int, struct expression *))
 	    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, CORE_ADDR, int))
+            return_minus_one);
+  de_fault (to_remove_mask_watchpoint,
+            (int (*) (CORE_ADDR, CORE_ADDR, int))
+            return_minus_one);
   de_fault (to_stopped_by_watchpoint,
 	    (int (*) (void))
 	    return_zero);
@@ -752,6 +773,9 @@ update_current_target (void)
   de_fault (to_can_accel_watchpoint_condition,
             (int (*) (CORE_ADDR, int, int, struct expression *))
             return_zero);
+  de_fault (to_hw_point_extra_slot_count,
+            (int (*) (enum hw_point_flag))
+            return_zero);
   de_fault (to_terminal_init,
 	    (void (*) (void))
 	    target_ignore);
diff --git a/gdb/target.h b/gdb/target.h
index 7687d8f..54a6747 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -39,6 +39,8 @@ struct static_tracepoint_marker;
 
 struct expression;
 
+enum hw_point_flag;
+
 /* This include file defines the interface between the main part
    of the debugger, and the part which is target-specific, or
    specific to the communications interface between us and the
@@ -438,6 +440,7 @@ struct target_ops
     int (*to_insert_breakpoint) (struct gdbarch *, struct bp_target_info *);
     int (*to_remove_breakpoint) (struct gdbarch *, struct bp_target_info *);
     int (*to_can_use_hw_breakpoint) (int, int, int);
+    int (*to_can_use_special_hw_point) (enum hw_point_flag);
     int (*to_insert_hw_breakpoint) (struct gdbarch *, struct bp_target_info *);
     int (*to_remove_hw_breakpoint) (struct gdbarch *, struct bp_target_info *);
 
@@ -446,6 +449,10 @@ struct target_ops
     int (*to_remove_watchpoint) (CORE_ADDR, int, int, struct expression *);
     int (*to_insert_watchpoint) (CORE_ADDR, int, int, struct expression *);
 
+    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, CORE_ADDR, int);
+    int (*to_remove_mask_watchpoint) (CORE_ADDR, CORE_ADDR, int);
     int (*to_stopped_by_watchpoint) (void);
     int to_have_steppable_watchpoint;
     int to_have_continuable_watchpoint;
@@ -455,6 +462,7 @@ struct target_ops
     int (*to_region_ok_for_hw_watchpoint) (CORE_ADDR, int);
     int (*to_can_accel_watchpoint_condition) (CORE_ADDR, int, int,
 					      struct expression *);
+    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);
@@ -1314,6 +1322,11 @@ extern char *normal_pid_to_str (ptid_t ptid);
 #define target_region_ok_for_hw_watchpoint(addr, len) \
     (*current_target.to_region_ok_for_hw_watchpoint) (addr, len)
 
+/* Returns non-zero if the target supports the special type of hardware
+   breakpoint/watchpoint represented by FLAG.  */
+#define target_can_use_special_hw_point(flag) \
+  (*current_target.to_can_use_special_hw_point) (flag)
+
 
 /* Set/clear a hardware watchpoint starting at ADDR, for LEN bytes.
    TYPE is 0 for write, 1 for read, and 2 for read/write accesses.
@@ -1327,6 +1340,20 @@ extern char *normal_pid_to_str (ptid_t ptid);
 #define	target_remove_watchpoint(addr, len, type, cond) \
      (*current_target.to_remove_watchpoint) (addr, len, type, cond)
 
+/* Hardware ranged watchpoints.  */
+#define target_insert_ranged_watchpoint(addr, len, type) \
+  (*current_target.to_insert_ranged_watchpoint) (addr, len, type)
+
+#define target_remove_ranged_watchpoint(addr, len, type) \
+  (*current_target.to_remove_ranged_watchpoint) (addr, len, type)
+
+/* Hardware watchpoints with an associated address mask.  */
+#define target_insert_mask_watchpoint(addr, mask, type) \
+  (*current_target.to_insert_mask_watchpoint) (addr, mask, type)
+
+#define target_remove_mask_watchpoint(addr, mask, type) \
+  (*current_target.to_remove_mask_watchpoint) (addr, mask, type)
+
 #define target_insert_hw_breakpoint(gdbarch, bp_tgt) \
      (*current_target.to_insert_hw_breakpoint) (gdbarch, bp_tgt)
 
@@ -1355,6 +1382,9 @@ extern char *normal_pid_to_str (ptid_t ptid);
 #define target_can_accel_watchpoint_condition(addr, len, type, cond) \
   (*current_target.to_can_accel_watchpoint_condition) (addr, len, type, cond)
 
+#define target_hw_point_extra_slot_count(flag) \
+  (*current_target.to_hw_point_extra_slot_count) (flag)
+
 /* Target can execute in reverse?  */
 #define target_can_execute_reverse \
      (current_target.to_can_execute_reverse ? \
diff --git a/gdb/ui-out.c b/gdb/ui-out.c
index 4d3bf0c..d6bea30 100644
--- a/gdb/ui-out.c
+++ b/gdb/ui-out.c
@@ -487,6 +487,46 @@ ui_out_field_fmt_int (struct ui_out *uiout,
 }
 
 void
+ui_out_field_range_core_addr (struct ui_out *uiout,
+			      const char *fldname,
+			      struct gdbarch *gdbarch,
+			      CORE_ADDR address_start,
+			      CORE_ADDR length)
+{
+  char addstr[80];
+  int addr_bit = gdbarch_addr_bit (gdbarch);
+  CORE_ADDR address_end = address_start + length - 1;
+
+  if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT))
+  {
+    address_start &= ((CORE_ADDR) 1 << addr_bit) - 1;
+    address_end &= ((CORE_ADDR) 1 << addr_bit) - 1;
+  }
+
+  /* FIXME: cagney/2002-05-03: Need local_address_string() function
+     that returns the language localized string formatted to a width
+     based on gdbarch_addr_bit.  */
+  if (addr_bit <= 32)
+  {
+    strcpy (addstr, "[");
+    strcat (addstr, hex_string_custom (address_start, 8));
+    strcat (addstr, ", ");
+    strcat (addstr, hex_string_custom (address_end, 8));
+    strcat (addstr, "]");
+  }
+  else
+  {
+    strcpy (addstr, "[");
+    strcat (addstr, hex_string_custom (address_start, 16));
+    strcat (addstr, ", ");
+    strcat (addstr, hex_string_custom (address_end, 16));
+    strcat (addstr, "]");
+  }
+
+  ui_out_field_string (uiout, fldname, addstr);
+}
+
+void
 ui_out_field_core_addr (struct ui_out *uiout,
 			const char *fldname,
 			struct gdbarch *gdbarch,
diff --git a/gdb/ui-out.h b/gdb/ui-out.h
index f65f42b..594691e 100644
--- a/gdb/ui-out.h
+++ b/gdb/ui-out.h
@@ -113,6 +113,12 @@ extern void ui_out_field_fmt_int (struct ui_out *uiout, int width,
 				  enum ui_align align, const char *fldname, 
 		 		  int value);
 
+extern void ui_out_field_range_core_addr (struct ui_out *uiout,
+					  const char *fldname,
+                                          struct gdbarch *gdbarch,
+					  CORE_ADDR address_start,
+					  CORE_ADDR length);
+
 extern void ui_out_field_core_addr (struct ui_out *uiout, const char *fldname,
 				    struct gdbarch *gdbarch, CORE_ADDR address);
 
diff --git a/gdb/value.h b/gdb/value.h
index d7912a8..64ea334 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -559,6 +559,9 @@ extern CORE_ADDR parse_and_eval_address_1 (char **expptr);
 
 extern LONGEST parse_and_eval_long (char *exp);
 
+int 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);


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

* Re: [patch 2/2] Implement support for PowerPC BookE masked and ranged watchpoints
  2010-10-30  1:59     ` Thiago Jung Bauermann
@ 2010-10-30  7:13       ` Eli Zaretskii
  2010-11-01 21:47         ` Thiago Jung Bauermann
  0 siblings, 1 reply; 19+ messages in thread
From: Eli Zaretskii @ 2010-10-30  7:13 UTC (permalink / raw)
  To: Thiago Jung Bauermann; +Cc: gdb-patches

> From: Thiago Jung Bauermann <bauerman@br.ibm.com>
> Cc: gdb-patches@sourceware.org
> Date: Fri, 29 Oct 2010 23:59:12 -0200
> 
> The version of the patch you reviewed wouldn't allow other architectures
> to create ranged software watchpoints (it asked the hardware whether the
> capability was available), though that was an unnecessary restriction.
> This version allows ranged software watchpoints for all architectures.
> (The change was made in the watch_range_command_1 function).

That's good to hear.  I think this is NEWS worthy, btw.

> > And what about masked watchpoints -- can they also be used in software
> > mode?
> 
> AFAIK, to implement masked watchpoints in software GDB would need to
> decode each instruction to see which address it was trying to access.
> This patch doesn't implement that, it would be hard work. If the target
> doesn't allow masked hardware watchpoints, the watch command will error
> out.

That's fine with me, I just wanted to make sure that documentation
faithfully reflects the implementation.

> > > +    case bp_hardware_watchpoint:
> > > +      ui_out_text (uiout, "Masked hardware watchpoint ");
> > 
> > Isn't it better to say "Masked hardware (write) watchpoint"?
> 
> Here I'm following the current GDB behaviour. It says just "Hardware
> watchpoint" for a bp_hardware_watchpoint.

OK.

> > > +  /* Display one line of extra information about this breakpoint,
> > > +     for "info breakpoints".  */
> > > +  void (*print_one_detail) (const struct breakpoint *, struct ui_out *);
> > 
> > Examples of such "extras" would be beneficial here.  Also, are there
> > any limitations on this extra information, like maximum length?
> 
> I changed this part to:
> 
>   /* Display extra information about this breakpoint, below the normal
>      breakpoint description in "info breakpoints".  In the example below,
>      the line with "memory range: [0x10094354, 0x100943a2]" was printed
>      by print_one_detail_ranged_watchpoint.
> 
>      (gdb) info breakpoints
>      Num     Type           Disp Enb Address    What
>      2       hw watchpoint  keep y              b
>              memory range: [0x10094354, 0x100943a2]
> 
>      */
>   void (*print_one_detail) (const struct breakpoint *, struct ui_out *);
> 
> What do you think?

I'm happy now.  Thanks.

> > > +  /* The watchpoint will trigger if the address of the memory access is
> > > +     within the defined range, as follows: p.addr <= address < p.addr2.  */
> > > +  p.addr            = (uint64_t) addr;
> > > +  p.addr2           = (uint64_t) addr + len;
> > 
> > But the documentation says that the end address is included, not
> > excluded.  Can we eliminate this source of confusion?
> 
> This code is in ppc-linux-nat.c right before calling ptrace to set the
> watchpoint, so it just documents how the kernel/processor interprets the
> parameters.
> 
> The user-facing code respects the semantics explained in the
> documentation. Also, target_insert_ranged_watchpoint takes a start
> address and a length as arguments and IMHO doesn't have this confusion.

Well, maybe this is worth a comment in this place.  Something like
"Note that this just documents how ptrace interprets its arguments;
the watchpoint is set to watch the defined range _inclusively_, as
specified by the user interface."

> gdb/doc/
> 	* gdb.texinfo (Set Watchpoints): Document mask parameter.
> 	(PowerPC Embedded): Document masked watchpoints and ranged watchpoints.

This part is approved.  Thanks.

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

* Re: [patch 2/2] Implement support for PowerPC BookE masked and ranged watchpoints
  2010-10-30  7:13       ` Eli Zaretskii
@ 2010-11-01 21:47         ` Thiago Jung Bauermann
  2010-11-02  3:53           ` Eli Zaretskii
  0 siblings, 1 reply; 19+ messages in thread
From: Thiago Jung Bauermann @ 2010-11-01 21:47 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches

On Sat, 2010-10-30 at 09:12 +0200, Eli Zaretskii wrote:
> > From: Thiago Jung Bauermann <bauerman@br.ibm.com>
> > Cc: gdb-patches@sourceware.org
> > Date: Fri, 29 Oct 2010 23:59:12 -0200
> > 
> > The version of the patch you reviewed wouldn't allow other architectures
> > to create ranged software watchpoints (it asked the hardware whether the
> > capability was available), though that was an unnecessary restriction.
> > This version allows ranged software watchpoints for all architectures.
> > (The change was made in the watch_range_command_1 function).
> 
> That's good to hear.  I think this is NEWS worthy, btw.

Indeed. Done.

> > > > +  /* The watchpoint will trigger if the address of the memory access is
> > > > +     within the defined range, as follows: p.addr <= address < p.addr2.  */
> > > > +  p.addr            = (uint64_t) addr;
> > > > +  p.addr2           = (uint64_t) addr + len;
> > > 
> > > But the documentation says that the end address is included, not
> > > excluded.  Can we eliminate this source of confusion?
> > 
> > This code is in ppc-linux-nat.c right before calling ptrace to set the
> > watchpoint, so it just documents how the kernel/processor interprets the
> > parameters.
> > 
> > The user-facing code respects the semantics explained in the
> > documentation. Also, target_insert_ranged_watchpoint takes a start
> > address and a length as arguments and IMHO doesn't have this confusion.
> 
> Well, maybe this is worth a comment in this place.  Something like
> "Note that this just documents how ptrace interprets its arguments;
> the watchpoint is set to watch the defined range _inclusively_, as
> specified by the user interface."

What about this?

  /* The watchpoint will trigger if the address of the memory access is
     within the defined range, as follows: p.addr <= address < p.addr2.

     Note that the above sentence just documents how ptrace interprets
     its arguments; the watchpoint is set to watch the range defined by
     the user _inclusively_, as specified by the user interface.  */

> > gdb/doc/
> > 	* gdb.texinfo (Set Watchpoints): Document mask parameter.
> > 	(PowerPC Embedded): Document masked watchpoints and ranged watchpoints.
> 
> This part is approved.  Thanks.

Great! Thanks.
-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center


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

	Implement support for PowerPC BookE masked and ranged watchpoints.

gdb/
	*NEWS: Mention masked and ranged watchpoint support.
	* breakpoint.c (update_watchpoint): Call breakpoint's
	breakpoint_ops.extra_resources_needed and
	breakpoint_ops.works_in_software_mode if available.
	(watchpoints_triggered): Handle the case of a hardware masked
	watchpoint trigger.
	(watchpoint_check): Handle the case of a hardware masked watchpoint
	trigger.
	(print_one_breakpoint_location): Call breakpoint's
	breakpoint_ops.print_one_detail if available.
	(hw_watchpoint_used_count): Call breakpoint's
	breakpoint_ops.extra_resources_needed if available.
	(insert_ranged_watchpoint, remove_ranged_watchpoint)
	(extra_resources_needed_ranged_watchpoint)
	(print_one_detail_ranged_watchpoint, print_mention_ranged_watchpoint)
	(print_recreate_ranged_watchpoint): New functions.
	(ranged_watchpoint_breakpoint_ops): New structure.
	(insert_masked_watchpoint, remove_masked_watchpoint)
	(extra_resources_needed_masked_watchpoint)
	(works_in_software_mode_masked_watchpoint, print_it_masked_watchpoint)
	(print_one_detail_masked_watchpoint, print_mention_masked_watchpoint)
	(print_recreate_masked_watchpoint, is_masked_watchpoint): New functions.
	(masked_watchpoint_breakpoint_ops): New structure.
	(watch_command_1): Check for the existence of the `mask' parameter.
	Check whether a ranged hardware watchpoint can be used. Set b->ops
	according to the type of hardware watchpoint being created.
	(watch_range_command_1, watch_range_command)
	(awatch_range_command, rwatch_range_command): New functions.
	(_initialize_breakpoint): Register watch-range, awatch-range and
	rwatch-range commands.
	* breakpoint.h (struct ui_out): New opaque declaration.
	(struct breakpoint_ops) <extra_resources_needed>,
	<works_in_software_mode>, <print_one_detail>: New methods.  Initialize them
	to NULL in all existing breakpoint_ops instances.
	(struct breakpoint_ops) <print_it>: Add OLD_VAL parameter.  Update all
	implementations of the method.
	(enum hw_point_flag): New enumeration.
	(struct breakpoint) <hw_wp_mask>: New field.
	* findcmd.c (parse_addr_range): New function factored out of
	parse_find_args.
	(parse_find_args): Call `parse_addr_range'.
	* ppc-linux-nat.c (ppc_linux_can_use_special_hw_point): New function.
	(ppc_linux_region_ok_for_hw_watchpoint): Always handle regions when
	ranged watchpoints are available.
	(ppc_linux_insert_mask_watchpoint, ppc_linux_remove_mask_watchpoint)
	(ppc_linux_insert_ranged_watchpoint, ppc_linux_remove_ranged_watchpoint)
	(ppc_linux_hw_point_extra_slot_count): New functions.
	(_initialize_ppc_linux_nat): Initialize to_insert_mask_watchpoint,
	to_remove_mask_watchpoint, to_insert_ranged_watchpoint,
	to_remove_ranged_watchpoint, hw_point_extra_slot_count and
	to_can_use_special_hw_point.
	* target.c (update_current_target): Insert to_insert_mask_watchpoint,
	to_remove_mask_watchpoint, to_insert_ranged_watchpoint,
	to_remove_ranged_watchpoint, to_hw_point_extra_slot_count
	and to_can_use_special_hw_point.
	* target.h (enum hw_point_flag): New opaque declaration.
	(struct target_ops) <to_insert_mask_watchpoint>,
	<to_remove_mask_watchpoint>, <to_insert_ranged_watchpoint>,
	<to_remove_ranged_watchpoint>, <to_hw_point_extra_slot_count>,
	<to_can_use_special_hw_point>: New callbacks.
	(target_insert_mask_watchpoint, target_remove_mask_watchpoint)
	(target_insert_ranged_watchpoint, target_remove_ranged_watchpoint)
	(target_hw_point_extra_slot_count, target_can_use_special_hw_point): New
	defines.
	* ui-out.c (ui_out_field_range_core_addr): New function.
	* ui-out.h (ui_out_field_range_core_addr): Declare.
	* value.h (parse_addr_range): Declare.

gdb/doc/
	* gdb.texinfo (Set Watchpoints): Document mask parameter.
	(PowerPC Embedded): Document masked watchpoints and ranged watchpoints.


diff --git a/gdb/NEWS b/gdb/NEWS
index 033d2fe..ab3c935 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -66,6 +66,19 @@
   libthread_db library with the "set libthread-db-search-path"
   command.  See the user manual for more details on this command.
 
+* GDB now supports ranged watchpoints, which stop the inferior when it
+  accesses any address within a specified memory range.  See the
+  documentation on the watch-range command for more information.  The
+  watchpoint is hardware-accelerated on some targets (currently only when
+  locally debugging programs on PowerPC BookE processors running a Linux
+  kernel version 2.6.34 or later.)
+
+* Also on native debugging on Linux running on PowerPC BookE, GDB supports
+  masked hardware watchpoints, which specifiy a mask in addition to an
+  address to watch.  The mask specifies that some bits of an address (the
+  bits which are reset in the mask) should be ignored when matching the
+  address accessed by the inferior against the watchpoint address.
+
 * New features in the GDB remote stub, GDBserver
 
   ** GDBserver is now supported on PowerPC LynxOS (versions 4.x and 5.x),
@@ -76,6 +89,22 @@
   see the "Tasking Support when using the Ravenscar Profile" section
   in the GDB user manual.
 
+* New commands
+
+watch-range START_ADDR,+LENGTH | START_ADDR, END_ADDR
+rwatch-range START_ADDR,+LENGTH | START_ADDR, END_ADDR
+awatch-range START_ADDR,+LENGTH | START_ADDR, END_ADDR
+  Set a hardware watchpoint for an address range.
+  The watchpoint will stop execution of your program whenever the inferior
+  writes, reads, or accesses (respectively for watch-range, awatch-range
+  and rwatch-range) any address within the specified range.
+
+* Changed commands
+
+watch
+  The watch command now supports the mask argument which allows creation
+  of masked watchpoints, if the current architecture supports this feature.
+
 *** Changes in GDB 7.2
 
 * Shared library support for remote targets by default
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index ea71ea2..4f438ed 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10756,7 +10756,7 @@ print_recreate_exception (enum exception_catchpoint_kind ex,
 /* Virtual table for "catch exception" breakpoints.  */
 
 static enum print_stop_action
-print_it_catch_exception (struct breakpoint *b)
+print_it_catch_exception (struct breakpoint *b, const struct value *old_val)
 {
   return print_it_exception (ex_catch_exception, b);
 }
@@ -10784,8 +10784,11 @@ static struct breakpoint_ops catch_exception_breakpoint_ops =
   NULL, /* insert */
   NULL, /* remove */
   NULL, /* breakpoint_hit */
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_exception,
   print_one_catch_exception,
+  NULL, /* print_one_detail */
   print_mention_catch_exception,
   print_recreate_catch_exception
 };
@@ -10793,7 +10796,8 @@ static struct breakpoint_ops catch_exception_breakpoint_ops =
 /* Virtual table for "catch exception unhandled" breakpoints.  */
 
 static enum print_stop_action
-print_it_catch_exception_unhandled (struct breakpoint *b)
+print_it_catch_exception_unhandled (struct breakpoint *b,
+				    const struct value *old_val)
 {
   return print_it_exception (ex_catch_exception_unhandled, b);
 }
@@ -10822,8 +10826,11 @@ static struct breakpoint_ops catch_exception_unhandled_breakpoint_ops = {
   NULL, /* insert */
   NULL, /* remove */
   NULL, /* breakpoint_hit */
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_exception_unhandled,
   print_one_catch_exception_unhandled,
+  NULL, /* print_one_detail */
   print_mention_catch_exception_unhandled,
   print_recreate_catch_exception_unhandled
 };
@@ -10831,7 +10838,7 @@ static struct breakpoint_ops catch_exception_unhandled_breakpoint_ops = {
 /* Virtual table for "catch assert" breakpoints.  */
 
 static enum print_stop_action
-print_it_catch_assert (struct breakpoint *b)
+print_it_catch_assert (struct breakpoint *b, const struct value *old_val)
 {
   return print_it_exception (ex_catch_assert, b);
 }
@@ -10858,8 +10865,11 @@ static struct breakpoint_ops catch_assert_breakpoint_ops = {
   NULL, /* insert */
   NULL, /* remove */
   NULL, /* breakpoint_hit */
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_assert,
   print_one_catch_assert,
+  NULL, /* print_one_detail */
   print_mention_catch_assert,
   print_recreate_catch_assert
 };
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 04878be..14e8fd0 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -219,6 +219,8 @@ static void disable_trace_command (char *, int);
 
 static void trace_pass_command (char *, int);
 
+static int is_masked_watchpoint (const struct breakpoint *b);
+
 /* Assuming we're creating a static tracepoint, does S look like a
    static tracepoint marker spec ("-m MARKER_ID")?  */
 #define is_marker_spec(s)						\
@@ -1391,27 +1393,52 @@ update_watchpoint (struct breakpoint *b, int reparse)
 	if ((b->type == bp_watchpoint || b->type == bp_hardware_watchpoint)
 	    && reparse)
 	  {
-	    int i, mem_cnt, other_type_used;
-
-	    /* We need to determine how many resources are already used
-	       for all other hardware watchpoints to see if we still have
-	       enough resources to also fit this watchpoint in as well.
-	       To avoid the hw_watchpoint_used_count call below from counting
-	       this watchpoint, make sure that it is marked as a software
-	       watchpoint.  */
-	    b->type = bp_watchpoint;
-	    i = hw_watchpoint_used_count (bp_hardware_watchpoint,
-					  &other_type_used);
+	    int mem_cnt;
+
 	    mem_cnt = can_use_hardware_watchpoint (val_chain);
 
 	    if (!mem_cnt)
-	      b->type = bp_watchpoint;
+	      {
+		if (b->type == bp_hardware_watchpoint
+		    && b->ops && b->ops->works_in_software_mode
+		    && !b->ops->works_in_software_mode (b))
+		  error (_("This watchpoint cannot be used in software mode."));
+		else
+		  b->type = bp_watchpoint;
+	      }
 	    else
 	      {
-		int target_resources_ok = target_can_use_hardware_watchpoint
-		  (bp_hardware_watchpoint, i + mem_cnt, other_type_used);
+		int i, other_type_used, target_resources_ok;
+		enum bptype orig_type;
+
+		if (b->ops && b->ops->extra_resources_needed)
+		  mem_cnt += b->ops->extra_resources_needed (b);
+
+		/* We need to determine how many resources are already used
+		   for all other hardware watchpoints to see if we still have
+		   enough resources to also fit this watchpoint in as well.
+		   To avoid the hw_watchpoint_used_count call below from
+		   counting this watchpoint, make sure that it is marked as a
+		   software watchpoint.  */
+		orig_type = b->type;
+		b->type = bp_watchpoint;
+		i = hw_watchpoint_used_count (bp_hardware_watchpoint,
+					      &other_type_used);
+
+		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;
+		  {
+		    if (orig_type == bp_hardware_watchpoint
+			&& b->ops && b->ops->works_in_software_mode
+			&& !b->ops->works_in_software_mode (b))
+		      {
+			b->type = bp_hardware_watchpoint;
+			error (_("This watchpoint cannot be used in software mode."));
+		      }
+		    else
+		      b->type = bp_watchpoint;
+		  }
 		else
 		  b->type = bp_hardware_watchpoint;
 	      }
@@ -3368,7 +3395,7 @@ print_bp_stop_message (bpstat bs)
 	   print_it_typical.  */
 	/* FIXME: how breakpoint can ever be NULL here?  */
 	if (b != NULL && b->ops != NULL && b->ops->print_it != NULL)
-	  return b->ops->print_it (b);
+	  return b->ops->print_it (b, bs->old_val);
 	else
 	  return print_it_typical (bs);
       }
@@ -3504,15 +3531,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 (is_masked_watchpoint (loc->owner))
+	      {
+		newaddr = addr & loc->owner->hw_wp_mask;
+		start = loc->address & loc->owner->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;
@@ -3626,6 +3668,11 @@ watchpoint_check (void *p)
 	  b->val_valid = 1;
 	  return WP_VALUE_CHANGED;
 	}
+      else if (is_masked_watchpoint (b))
+	/* 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.  */
@@ -4696,9 +4743,12 @@ print_one_breakpoint_location (struct breakpoint *b,
 	  ui_out_field_int (uiout, "task", b->task);
 	}
     }
-  
+
   ui_out_text (uiout, "\n");
-  
+
+  if (!part_of_multiple && b->ops && b->ops->print_one_detail)
+    b->ops->print_one_detail (b, uiout);
+
   if (!part_of_multiple && b->static_trace_marker_id)
     {
       gdb_assert (b->type == bp_static_tracepoint);
@@ -5869,7 +5919,7 @@ breakpoint_hit_catch_fork (struct breakpoint *b)
 /* Implement the "print_it" breakpoint_ops method for fork catchpoints.  */
 
 static enum print_stop_action
-print_it_catch_fork (struct breakpoint *b)
+print_it_catch_fork (struct breakpoint *b, const struct value *old_val)
 {
   annotate_catchpoint (b->number);
   printf_filtered (_("\nCatchpoint %d (forked process %d), "),
@@ -5927,8 +5977,11 @@ static struct breakpoint_ops catch_fork_breakpoint_ops =
   insert_catch_fork,
   remove_catch_fork,
   breakpoint_hit_catch_fork,
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_fork,
   print_one_catch_fork,
+  NULL, /* print_one_detail */
   print_mention_catch_fork,
   print_recreate_catch_fork
 };
@@ -5961,7 +6014,7 @@ breakpoint_hit_catch_vfork (struct breakpoint *b)
 /* Implement the "print_it" breakpoint_ops method for vfork catchpoints.  */
 
 static enum print_stop_action
-print_it_catch_vfork (struct breakpoint *b)
+print_it_catch_vfork (struct breakpoint *b, const struct value *old_val)
 {
   annotate_catchpoint (b->number);
   printf_filtered (_("\nCatchpoint %d (vforked process %d), "),
@@ -6018,8 +6071,11 @@ static struct breakpoint_ops catch_vfork_breakpoint_ops =
   insert_catch_vfork,
   remove_catch_vfork,
   breakpoint_hit_catch_vfork,
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_vfork,
   print_one_catch_vfork,
+  NULL, /* print_one_detail */
   print_mention_catch_vfork,
   print_recreate_catch_vfork
 };
@@ -6139,7 +6195,7 @@ breakpoint_hit_catch_syscall (struct breakpoint *b)
    catchpoints.  */
 
 static enum print_stop_action
-print_it_catch_syscall (struct breakpoint *b)
+print_it_catch_syscall (struct breakpoint *b, const struct value *old_val)
 {
   /* These are needed because we want to know in which state a
      syscall is.  It can be in the TARGET_WAITKIND_SYSCALL_ENTRY
@@ -6299,8 +6355,11 @@ static struct breakpoint_ops catch_syscall_breakpoint_ops =
   insert_catch_syscall,
   remove_catch_syscall,
   breakpoint_hit_catch_syscall,
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_syscall,
   print_one_catch_syscall,
+  NULL, /* print_one_detail */
   print_mention_catch_syscall,
   print_recreate_catch_syscall
 };
@@ -6402,7 +6461,7 @@ breakpoint_hit_catch_exec (struct breakpoint *b)
 }
 
 static enum print_stop_action
-print_it_catch_exec (struct breakpoint *b)
+print_it_catch_exec (struct breakpoint *b, const struct value *old_val)
 {
   annotate_catchpoint (b->number);
   printf_filtered (_("\nCatchpoint %d (exec'd %s), "), b->number,
@@ -6452,8 +6511,11 @@ static struct breakpoint_ops catch_exec_breakpoint_ops =
   insert_catch_exec,
   remove_catch_exec,
   breakpoint_hit_catch_exec,
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_exec,
   print_one_catch_exec,
+  NULL, /* print_one_detail */
   print_mention_catch_exec,
   print_recreate_catch_exec
 };
@@ -6501,7 +6563,14 @@ hw_watchpoint_used_count (enum bptype type, int *other_type_used)
     if (breakpoint_enabled (b))
       {
 	if (b->type == type)
-	  i++;
+	  {
+	    i++;
+
+	    /* Special types of hardware watchpoints can use more than
+	       one register.  */
+	    if (b->ops && b->ops->extra_resources_needed)
+	      i += b->ops->extra_resources_needed (b);
+	  }
 	else if (is_hardware_watchpoint (b))
 	  *other_type_used = 1;
       }
@@ -8043,12 +8112,353 @@ static struct breakpoint_ops watchpoint_breakpoint_ops =
   insert_watchpoint,
   remove_watchpoint,
   NULL, /* breakpoint_hit */
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
   NULL, /* print_it */
   NULL, /* print_one */
+  NULL, /* print_one_detail */
   NULL, /* print_mention */
   NULL  /* print_recreate */
 };
 
+/* Implement the "insert" breakpoint_ops method for
+   ranged hardware watchpoints.  */
+
+static int
+insert_ranged_watchpoint (struct bp_location *bpt)
+{
+  return target_insert_ranged_watchpoint (bpt->address,
+					  bpt->length,
+					  bpt->watchpoint_type);
+}
+
+/* Implement the "remove" breakpoint_ops method for
+   ranged hardware watchpoints.  */
+
+static int
+remove_ranged_watchpoint (struct bp_location *bpt)
+{
+  return target_remove_ranged_watchpoint (bpt->address, bpt->length,
+					  bpt->watchpoint_type);
+}
+
+/* Implement the "extra_resources_needed" breakpoint_ops method for
+   ranged hardware watchpoints.  */
+
+static int
+extra_resources_needed_ranged_watchpoint (const struct breakpoint *b)
+{
+  return target_hw_point_extra_slot_count (HW_POINT_RANGED_WATCH);
+}
+
+/* Implement the "print_one_detail" breakpoint_ops method for
+   ranged hardware watchpoints.  */
+
+static void
+print_one_detail_ranged_watchpoint (const struct breakpoint *b, struct ui_out *uiout)
+{
+  /* If there's a separate expression for reparsing, then exp_string is already
+     a nice text set by watch_range_command_1 and was printed earlier.  */
+  if (b->exp_string_reparse)
+    return;
+
+  gdb_assert (b->loc);
+
+  ui_out_text (uiout, "\tmemory range: ");
+  ui_out_field_range_core_addr (uiout, "addr", b->loc->gdbarch,
+				b->loc->address, b->loc->length);
+  ui_out_text (uiout, "\n");
+}
+
+/* Implement the "print_mention" breakpoint_ops method for
+   ranged hardware watchpoints.  */
+
+static void
+print_mention_ranged_watchpoint (struct breakpoint *b)
+{
+  struct cleanup *ui_out_chain;
+
+  switch (b->type)
+    {
+    case bp_watchpoint:
+      ui_out_text (uiout, "Ranged watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt");
+      break;
+    case bp_hardware_watchpoint:
+      ui_out_text (uiout, "Ranged hardware watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt");
+      break;
+    case bp_read_watchpoint:
+      ui_out_text (uiout, "Ranged hardware read watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-rwpt");
+      break;
+    case bp_access_watchpoint:
+      ui_out_text (uiout, "Ranged hardware access (read/write) watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-awpt");
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  ui_out_field_int (uiout, "number", b->number);
+  ui_out_text (uiout, ": ");
+  ui_out_field_string (uiout, "exp", b->exp_string);
+  do_cleanups (ui_out_chain);
+}
+
+static void
+print_recreate_ranged_watchpoint (struct breakpoint *b, struct ui_file *fp)
+{
+  switch (b->type)
+    {
+    case bp_watchpoint:
+    case bp_hardware_watchpoint:
+      if (b->exp_string_reparse)
+	fprintf_unfiltered (fp, "watch-range");
+      else
+	fprintf_unfiltered (fp, "watch");
+      break;
+    case bp_read_watchpoint:
+      if (b->exp_string_reparse)
+	fprintf_unfiltered (fp, "rwatch-range");
+      else
+	fprintf_unfiltered (fp, "rwatch");
+      break;
+    case bp_access_watchpoint:
+      if (b->exp_string_reparse)
+	fprintf_unfiltered (fp, "awatch-range");
+      else
+	fprintf_unfiltered (fp, "awatch");
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  if (b->exp_string_reparse)
+    {
+      char start_addr[40], length[40];
+
+      /* watch_range_command_1 creates the following expression to represent
+	 internally a ranged watchpoint.  */
+      sscanf (b->exp_string_reparse, "{char[ %39s ]} %39s", length, start_addr);
+
+      fprintf_unfiltered (fp, " %s, +%s", start_addr, length);
+    }
+  else
+    fprintf_unfiltered (fp, " %s", b->exp_string);
+}
+
+/* The breakpoint_ops structure to be used in ranged hardware watchpoints.  */
+
+static struct breakpoint_ops ranged_watchpoint_breakpoint_ops =
+{
+  insert_ranged_watchpoint,
+  remove_ranged_watchpoint,
+  NULL, /* breakpoint_hit */
+  extra_resources_needed_ranged_watchpoint,
+  NULL, /* works_in_software_mode */
+  NULL, /* print_it */
+  NULL, /* print_one */
+  print_one_detail_ranged_watchpoint,
+  print_mention_ranged_watchpoint,
+  print_recreate_ranged_watchpoint
+};
+
+/* Implement the "insert" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static int
+insert_masked_watchpoint (struct bp_location *bpt)
+{
+  return target_insert_mask_watchpoint (bpt->address, bpt->owner->hw_wp_mask,
+					bpt->watchpoint_type);
+}
+
+/* Implement the "remove" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static int
+remove_masked_watchpoint (struct bp_location *bpt)
+{
+  return target_remove_mask_watchpoint (bpt->address, bpt->owner->hw_wp_mask,
+				        bpt->watchpoint_type);
+}
+
+/* Implement the "extra_resources_needed" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static int
+extra_resources_needed_masked_watchpoint (const struct breakpoint *b)
+{
+  return target_hw_point_extra_slot_count (HW_POINT_MASKED_WATCH);
+}
+
+/* Implement the "works_in_software_mode_masked_watchpoint" breakpoint_ops
+   method for masked hardware watchpoints.  */
+
+static int
+works_in_software_mode_masked_watchpoint (const struct breakpoint *b)
+{
+  return 0;
+}
+
+/* Implement the "print_it" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static enum print_stop_action
+print_it_masked_watchpoint (struct breakpoint *b, const struct value *old_val)
+{
+  struct ui_stream *stb;
+  struct cleanup *old_chain;
+
+  stb = ui_out_stream_new (uiout);
+  old_chain = make_cleanup_ui_out_stream_delete (stb);
+
+  switch (b->type)
+    {
+    case bp_hardware_watchpoint:
+      annotate_watchpoint (b->number);
+      if (ui_out_is_mi_like_p (uiout))
+	ui_out_field_string
+	  (uiout, "reason",
+	   async_reason_lookup (EXEC_ASYNC_WATCHPOINT_TRIGGER));
+      break;
+
+    case bp_read_watchpoint:
+      if (ui_out_is_mi_like_p (uiout))
+	ui_out_field_string
+	  (uiout, "reason",
+	   async_reason_lookup (EXEC_ASYNC_READ_WATCHPOINT_TRIGGER));
+      break;
+
+    case bp_access_watchpoint:
+      if (old_val != NULL)
+	{
+	  annotate_watchpoint (b->number);
+	  if (ui_out_is_mi_like_p (uiout))
+	    ui_out_field_string
+	      (uiout, "reason",
+	       async_reason_lookup (EXEC_ASYNC_ACCESS_WATCHPOINT_TRIGGER));
+	}
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  mention (b);
+  ui_out_text (uiout, _("\nCheck the underlying instruction \
+at PC for address and value related to this watchpoint trigger.\n"));
+  ui_out_text (uiout, "\n");
+
+  do_cleanups (old_chain);
+
+  /* More than one watchpoint may have been triggered.  */
+  return PRINT_UNKNOWN;
+}
+
+/* Implement the "print_one_detail" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static void
+print_one_detail_masked_watchpoint (const struct breakpoint *b, struct ui_out *uiout)
+{
+  ui_out_text (uiout, "\tmask ");
+
+  /* I don't know whether it's possible to get here without a b->loc,
+     but we can handle the situation.  */
+  if (b->loc)
+    ui_out_field_core_addr (uiout, "mask", b->loc->gdbarch, b->hw_wp_mask);
+  else
+    ui_out_field_string (uiout, "mask", core_addr_to_string (b->hw_wp_mask));
+
+  ui_out_text (uiout, "\n");
+}
+
+/* Implement the "print_mention" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static void
+print_mention_masked_watchpoint (struct breakpoint *b)
+{
+  struct cleanup *ui_out_chain;
+
+  switch (b->type)
+    {
+    case bp_hardware_watchpoint:
+      ui_out_text (uiout, "Masked hardware watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt");
+      break;
+    case bp_read_watchpoint:
+      ui_out_text (uiout, "Masked hardware read watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-rwpt");
+      break;
+    case bp_access_watchpoint:
+      ui_out_text (uiout, "Masked hardware access (read/write) watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-awpt");
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  ui_out_field_int (uiout, "number", b->number);
+  ui_out_text (uiout, ": ");
+  ui_out_field_string (uiout, "exp", b->exp_string);
+  do_cleanups (ui_out_chain);
+}
+
+static void
+print_recreate_masked_watchpoint (struct breakpoint *b, struct ui_file *fp)
+{
+  char tmp[40];
+
+  switch (b->type)
+    {
+    case bp_hardware_watchpoint:
+      fprintf_unfiltered (fp, "watch");
+      break;
+    case bp_read_watchpoint:
+      fprintf_unfiltered (fp, "rwatch");
+      break;
+    case bp_access_watchpoint:
+      fprintf_unfiltered (fp, "awatch");
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  sprintf_vma (tmp, b->hw_wp_mask);
+  fprintf_unfiltered (fp, " %s mask 0x%s", b->exp_string, tmp);
+}
+
+/* The breakpoint_ops structure to be used in masked hardware watchpoints.  */
+
+static struct breakpoint_ops masked_watchpoint_breakpoint_ops =
+{
+  insert_masked_watchpoint,
+  remove_masked_watchpoint,
+  NULL, /* breakpoint_hit */
+  extra_resources_needed_masked_watchpoint,
+  works_in_software_mode_masked_watchpoint,
+  print_it_masked_watchpoint,
+  NULL, /* print_one */
+  print_one_detail_masked_watchpoint,
+  print_mention_masked_watchpoint,
+  print_recreate_masked_watchpoint
+};
+
+/* Tells whether the given watchpoint is a masked hardware watchpoint.  */
+
+static int
+is_masked_watchpoint (const struct breakpoint *b)
+{
+  return b->ops == &masked_watchpoint_breakpoint_ops;
+}
+
 /* accessflag:  hw_write:  watch write, 
                 hw_read:   watch read, 
 		hw_access: watch access (read or write) */
@@ -8062,8 +8472,8 @@ watch_command_1 (char *arg, int accessflag, int from_tty, int just_location)
   struct frame_info *frame;
   char *exp_start = NULL;
   char *exp_end = NULL;
-  char *tok, *id_tok_start, *end_tok;
-  int toklen;
+  char *tok, *end_tok;
+  int toklen = -1;
   char *cond_start = NULL;
   char *cond_end = NULL;
   int i, other_type_used, target_resources_ok = 0;
@@ -8071,66 +8481,98 @@ watch_command_1 (char *arg, int accessflag, int from_tty, int just_location)
   int mem_cnt = 0;
   int thread = -1;
   int pc = 0;
+  /* 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;
 
   /* Make sure that we actually have parameters to parse.  */
   if (arg != NULL && arg[0] != '\0')
     {
-      toklen = strlen (arg); /* Size of argument list.  */
+      char *value_start;
+
+      /* Look for "parameter value" pairs at the end
+	 of the arguments string.  */
+      for (tok = arg + strlen (arg) - 1; tok > arg; tok--)
+	{
+	  /* Skip whitespace at the end of the argument list.  */
+	  while (tok > arg && (*tok == ' ' || *tok == '\t'))
+	    tok--;
+
+	  /* Find the beginning of the last token.
+	     This is the value of the parameter.  */
+	  while (tok > arg && (*tok != ' ' && *tok != '\t'))
+	    tok--;
+	  value_start = tok + 1;
+
+	  /* Skip whitespace.  */
+	  while (tok > arg && (*tok == ' ' || *tok == '\t'))
+	    tok--;
+
+	  end_tok = tok;
+
+	  /* Find the beginning of the second to last token.
+	     This is the parameter itself.  */
+	  while (tok > arg && (*tok != ' ' && *tok != '\t'))
+	    tok--;
+	  tok++;
+	  toklen = end_tok - tok + 1;
+
+	  if (toklen == 6 && !strncmp (tok, "thread", 6))
+	    {
+	      /* 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;
 
-      /* Points tok to the end of the argument list.  */
-      tok = arg + toklen - 1;
+	      if (thread != -1)
+		error(_("You can specify only one thread."));
 
-      /* 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--;
+	      /* Extract the thread ID from the next token.  */
+	      thread = strtol (value_start, &endp, 0);
 
-      /* Points end_tok to the beginning of the last token.  */
-      id_tok_start = tok + 1;
+	      /* 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."), value_start);
 
-      /* 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--;
+	      /* Check if the thread actually exists.  */
+	      if (!valid_thread_id (thread))
+		error (_("Unknown thread %d."), thread);
+	    }
+	  else if (toklen == 4 && !strncmp (tok, "mask", 4))
+	    {
+	      /* We've found a "mask" token, which means the user wants to
+		 create a hardware watchpoint that is going to have the mask
+		 facility.  */
+	      struct value *mask_value, *mark;
 
-      end_tok = tok;
+	      /* Does the target support masked watchpoints?  */
+	      if (!target_can_use_special_hw_point (HW_POINT_MASKED_WATCH))
+		error (_("\
+This target does not support the usage of masks with hardware watchpoints."));
 
-      while (tok > arg && (*tok != ' ' && *tok != '\t'))
-        tok--;
+	      if (use_mask)
+		error(_("You can specify only one mask."));
 
-      /* Move the pointer forward to skip the whitespace and
-         calculate the length of the token.  */
-      tok++;
-      toklen = end_tok - tok;
+	      use_mask = 1;
 
-      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';
-        }
+	      mark = value_mark ();
+	      mask_value = parse_to_comma_and_eval (&value_start);
+	      hw_wp_mask = value_as_address (mask_value);
+	      value_free_to_mark (mark);
+	    }
+	  else
+	    /* We didn't recognize what we found.  We should stop here.  */
+	    break;
+
+	  /* Truncate the string and get rid of the "parameter value" pair before
+	     the arguments string is parsed by the parse_exp_1 function.  */
+	  *tok = '\0';
+	}
     }
 
   /* Parse the rest of the arguments.  */
@@ -8208,6 +8650,22 @@ watch_command_1 (char *arg, int accessflag, int from_tty, int just_location)
     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 (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, 
@@ -8219,10 +8677,22 @@ watch_command_1 (char *arg, int accessflag, int from_tty, int just_location)
 	error (_("Target can only support one kind of HW watchpoint at a time."));
     }
 
-  /* 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 && !mem_cnt)
+	error (_("Cannot use masks with the given expression."));
+      else if (use_mask && target_resources_ok <= 0)
+	error (_("\
+Cannot use masks without enough available hardware watchpoints (need %d)."),
+	       mem_cnt);
+      else
+	{
+	  /* Change the type of breakpoint to an ordinary watchpoint if a
+	     hardware watchpoint could not be set.  */
+	  bp_type = bp_watchpoint;
+	  use_ranged = 0;
+	}
+    }
 
   frame = block_innermost_frame (exp_valid_block);
 
@@ -8291,7 +8761,16 @@ watch_command_1 (char *arg, int accessflag, int from_tty, int just_location)
     b->exp_string = savestring (exp_start, exp_end - exp_start);
   b->val = val;
   b->val_valid = 1;
-  b->ops = &watchpoint_breakpoint_ops;
+
+  if (use_mask)
+    {
+      b->hw_wp_mask = hw_wp_mask;
+      b->ops = &masked_watchpoint_breakpoint_ops;
+    }
+  else if (use_ranged)
+    b->ops = &ranged_watchpoint_breakpoint_ops;
+  else
+    b->ops = &watchpoint_breakpoint_ops;
 
   if (cond_start)
     b->cond_string = savestring (cond_start, cond_end - cond_start);
@@ -8478,6 +8957,99 @@ awatch_command (char *arg, int from_tty)
 {
   watch_maybe_just_location (arg, hw_access, from_tty);
 }
+
+static void
+watch_range_command_1 (char *arg, enum bptype type, int from_tty)
+{
+  char *exp_string, *string_p;
+  struct gdbarch *gdbarch = get_current_arch ();
+  int wp_count, other_type_used, can_use_wp, mem_cnt, pc = 0;
+  CORE_ADDR start_addr;
+  ULONGEST length;
+  struct breakpoint *b;
+  struct expression *exp;
+  struct symtab_and_line sal;
+  struct value *val;
+  struct cleanup *cleanups;
+
+  /* Check if we need hardware watchpoints, and if we have enough
+     of them available.  */
+
+  if (!can_use_hw_watchpoints && type != bp_hardware_watchpoint)
+    error (_("\
+Need watchpoint hardware for read and access watchpoints, but cannot use it\n\
+(see set can-use-hw-watchpoints)."));
+
+  mem_cnt = target_hw_point_extra_slot_count (HW_POINT_RANGED_WATCH) + 1;
+  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 || !can_use_hw_watchpoints)
+    {
+      if (type == bp_hardware_watchpoint)
+	/* Change the type of breakpoint to an ordinary watchpoint if a
+	   hardware watchpoint could not be set.  */
+	type = bp_watchpoint;
+      else
+	error (_("Not enough available hardware watchpoints (need %d)."),
+	       mem_cnt);
+    }
+
+  parse_addr_range (&arg, &start_addr, &length);
+
+  /* We need spaces around the brackets in the expression below so that
+     print_it_recreate_ranged_watchpoint can use scanf on it.  */
+  exp_string = string_p = xstrprintf ("{char[ %s ]} %s", pulongest (length),
+				      paddress (gdbarch, start_addr));
+  exp = parse_exp_1 (&string_p, 0, 0);
+  fetch_subexp_value (exp, &pc, &val, NULL, NULL);
+  if (val != NULL)
+    release_value (val);
+  cleanups = make_cleanup (xfree, exp_string);
+
+  init_sal (&sal);		/* initialize to zeroes */
+  sal.pspace = current_program_space;
+
+  /* Now set up the breakpoint.  */
+  b = set_raw_breakpoint (gdbarch, sal, type);
+  set_breakpoint_count (breakpoint_count + 1);
+  b->number = breakpoint_count;
+  b->thread = -1;
+  b->disposition = disp_donttouch;
+  b->exp = exp;
+  b->exp_string_reparse = exp_string;
+  b->exp_string = xstrprintf (_("range [%s, %s]"),
+			      paddress (gdbarch, start_addr),
+			      paddress (gdbarch, start_addr + length - 1));
+  b->ops = &ranged_watchpoint_breakpoint_ops;
+  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);
+}
+
 \f
 
 /* Helper routines for the until_command routine in infcmd.c.  Here
@@ -8715,7 +9287,8 @@ catch_exec_command_1 (char *arg, int from_tty,
 }
 
 static enum print_stop_action
-print_exception_catchpoint (struct breakpoint *b)
+print_it_exception_catchpoint (struct breakpoint *b,
+			       const struct value *old_val)
 {
   int bp_temp, bp_throw;
 
@@ -8804,8 +9377,11 @@ static struct breakpoint_ops gnu_v3_exception_catchpoint_ops = {
   NULL, /* insert */
   NULL, /* remove */
   NULL, /* breakpoint_hit */
-  print_exception_catchpoint,
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
+  print_it_exception_catchpoint,
   print_one_exception_catchpoint,
+  NULL, /* print_one_detail */
   print_mention_exception_catchpoint,
   print_recreate_exception_catchpoint
 };
@@ -12195,7 +12771,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 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 the inferior whenever it\n\
+writes to any address within the [start-address, end-address] 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 the inferior whenever it\n\
+accesses (reads from or writes to) any address within the\n\
+[start-address, end-address] 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 the inferior whenever it\n\
+reads from any address within the [start-address, end-address] range."));
+  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 1b66986..57dc74c 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -26,6 +26,7 @@
 
 struct value;
 struct block;
+struct ui_out;
 
 /* This is the maximum number of bytes a breakpoint instruction can take.
    Feel free to increase it.  It's just used in a few places to size
@@ -361,13 +362,37 @@ struct breakpoint_ops
      breakpoint was hit.  */
   int (*breakpoint_hit) (struct breakpoint *);
 
+  /* Tell how many additional hardware resources (debug registers) are needed
+     for this breakpoint.  We always count at least one resource.  If this
+     element is NULL, then no additional resources are needed.  */
+  int (*extra_resources_needed) (const struct breakpoint *);
+
+  /* Tell whether we can downgrade from a hardware watchpoint to a software
+     one.  If not, the user will not be able to enable the watchpoint when
+     there are not enough hardware resources available.  */
+  int (*works_in_software_mode) (const struct breakpoint *);
+
   /* The normal print routine for this breakpoint, called when we
      hit it.  */
-  enum print_stop_action (*print_it) (struct breakpoint *);
+  enum print_stop_action (*print_it) (struct breakpoint *,
+				      const struct value *old_val);
 
   /* Display information about this breakpoint, for "info breakpoints".  */
   void (*print_one) (struct breakpoint *, struct bp_location **);
 
+  /* Display extra information about this breakpoint, below the normal
+     breakpoint description in "info breakpoints".  In the example below,
+     the line with "memory range: [0x10094354, 0x100943a2]" was printed
+     by print_one_detail_ranged_watchpoint.
+
+     (gdb) info breakpoints
+     Num     Type           Disp Enb Address    What
+     2       hw watchpoint  keep y              b
+             memory range: [0x10094354, 0x100943a2]
+
+     */
+  void (*print_one_detail) (const struct breakpoint *, struct ui_out *);
+
   /* Display information about this breakpoint after setting it (roughly
      speaking; this is called from "mention").  */
   void (*print_mention) (struct breakpoint *);
@@ -400,6 +425,12 @@ DEF_VEC_P(bp_location_p);
    detail to the breakpoints module.  */
 struct counted_command_line;
 
+/* Special types of hardware breakpoints/watchpoints.  */
+enum hw_point_flag {
+	HW_POINT_RANGED_WATCH, /* Hardware ranged watchpoint.  */
+	HW_POINT_MASKED_WATCH  /* Hardware masked watchpoint.  */
+};
+
 /* Note that the ->silent field is not currently used by any commands
    (though the code is in there if it was to be, and set_raw_breakpoint
    does set it to 0).  I implemented it because I thought it would be
@@ -559,6 +590,9 @@ struct breakpoint
        breakpoints, we will use this index to try to find the same
        marker again.  */
     int static_trace_marker_id_idx;
+
+    /* The mask address for a hardware watchpoint.  */
+    CORE_ADDR hw_wp_mask;
   };
 
 typedef struct breakpoint *breakpoint_p;
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 9446932..ffe45fb 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -3711,7 +3711,7 @@ watchpoints, which do not slow down the running of your program.
 
 @table @code
 @kindex watch
-@item watch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]}
+@item watch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} @r{[}mask @var{maskvalue}@r{]}
 Set a watchpoint for an expression.  @value{GDBN} will break when the
 expression @var{expr} is written into by the program and its value
 changes.  The simplest (and the most popular) use of this command is
@@ -3722,12 +3722,17 @@ to watch the value of a single variable:
 @end smallexample
 
 If the command includes a @code{@r{[}thread @var{threadnum}@r{]}}
-clause, @value{GDBN} breaks only when the thread identified by
+argument, @value{GDBN} breaks only when the thread identified by
 @var{threadnum} changes the value of @var{expr}.  If any other threads
 change the value of @var{expr}, @value{GDBN} will not break.  Note
 that watchpoints restricted to a single thread in this way only work
 with Hardware Watchpoints.
 
+The @code{@r{[}mask @var{maskvalue}@r{]}} argument allows creation
+of masked watchpoints, if the current architecture supports this
+feature.  (Currently, this is only available on PowerPC Embedded
+architecture, see @ref{PowerPC Embedded}.)
+
 Ordinarily a watchpoint respects the scope of variables in @var{expr}
 (see below).  The @code{-location} argument tells @value{GDBN} to
 instead watch the memory referred to by @var{expr}.  In this case,
@@ -3738,12 +3743,12 @@ result does not have an address, then @value{GDBN} will print an
 error.
 
 @kindex rwatch
-@item rwatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]}
+@item rwatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} @r{[}mask @var{maskvalue}@r{]}
 Set a watchpoint that will break when the value of @var{expr} is read
 by the program.
 
 @kindex awatch
-@item awatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]}
+@item awatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} @r{[}mask @var{maskvalue}@r{]}
 Set a watchpoint that will break when @var{expr} is either read from
 or written into by the program.
 
@@ -18517,9 +18522,44 @@ The DVC register will be automatically used whenever @value{GDBN} detects
 such pattern in a condition expression.  This feature is available in native
 @value{GDBN} running on a Linux kernel version 2.6.34 or newer.
 
+PowerPC embedded processors support masked watchpoints and ranged watchpoints.
+
+A @dfn{masked watchpoint} specifies a mask in addition to an address
+to watch.  The mask specifies that some bits of an address (the bits
+which are reset in the mask) should be ignored when matching the
+address accessed by the inferior against the watchpoint address.
+Thus, a masked watchpoint watches many addresses
+simultaneously---those addresses whose unmasked bits are identical
+to the unmasked bits in the watchpoint address.
+
+To set a masked watchpoint in @value{GDBN}, use the @code{mask} argument in
+the @code{watch} command (@pxref{Set Watchpoints}), as in:
+
+@smallexample
+(@value{GDBP}) watch *0xdeadbeef mask 0xffffff00
+@end smallexample
+
+A @dfn{ranged watchpoint} watches a contiguous range of addresses.
+To set a ranged watchpoint in @value{GDBN}, use the @code{watch-range} command.
+In addition, @value{GDBN} automatically creates a ranged watchpoint when asked
+to watch an array or struct of known size and there are enough hardware
+registers available.
+
 @value{GDBN} provides the following PowerPC-specific commands:
 
 @table @code
+@kindex watch-range
+@item watch-range @var{start-address}, +@var{length}
+@itemx watch-range @var{start-address}, @var{end-address}
+@item rwatch-range @var{start-address}, +@var{length}
+@itemx rwatch-range @var{start-address}, @var{end-address}
+@item awatch-range @var{start-address}, +@var{length}
+@itemx awatch-range @var{start-address}, @var{end-address}
+Set a hardware watchpoint for an address range.
+The watchpoint will stop execution of your program whenever the inferior
+writes, reads, or accesses (respectively for watch-range, awatch-range
+and rwatch-range) any address within the specified range.
+
 @kindex set powerpc
 @item set powerpc soft-float
 @itemx show powerpc soft-float
diff --git a/gdb/findcmd.c b/gdb/findcmd.c
index ac63a9e..34b0dfe 100644
--- a/gdb/findcmd.c
+++ b/gdb/findcmd.c
@@ -45,6 +45,79 @@ 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.  Returns 1 on success, or 0 if an empty address range was given.  */
+
+int
+parse_addr_range (char **args, CORE_ADDR *start_addrp,
+		  ULONGEST *address_range_lenp)
+{
+  char *s = *args;
+  CORE_ADDR start_addr;
+  ULONGEST address_range_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)
+	{
+	  printf_filtered (_("Empty address range.\n"));
+	  return 0;
+	}
+      if (len < 0)
+	error (_("Invalid (negative) length of the address range."));
+      /* Watch for overflows.  */
+      if (len > CORE_ADDR_MAX
+	  || (start_addr + len - 1) < start_addr)
+	error (_("Address range too large."));
+      address_range_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 address range, end preceeds start."));
+      address_range_len = end_addr - start_addr + 1;
+      /* We don't support searching all of memory
+	 (i.e. start=0, end = 0xff..ff).
+	 Bail out to avoid overflows later on.  */
+      if (address_range_len == 0)
+	error (_("Overflow in address range computation, choose smaller range."));
+    }
+
+  if (*s == ',')
+    ++s;
+
+  *args = s;
+  *start_addrp = start_addr;
+  *address_range_lenp = address_range_len;
+
+  return 1;
+}
+
 /* Subroutine of find_command to simplify it.
    Parse the arguments of the "find" command.  */
 
@@ -114,53 +187,8 @@ 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;
+  if (!parse_addr_range (&s, &start_addr, &search_space_len))
+    return;
 
   /* Fetch the search string.  */
 
diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c
index 18ddee7..e520dcd 100644
--- a/gdb/ppc-linux-nat.c
+++ b/gdb/ppc-linux-nat.c
@@ -1478,6 +1478,28 @@ ppc_linux_can_use_hw_breakpoint (int type, int cnt, int ot)
 }
 
 static int
+ppc_linux_can_use_special_hw_point (enum hw_point_flag flag)
+{
+  uint64_t features;
+
+  if (!have_ptrace_booke_interface ())
+    return 0;
+
+  features = booke_debug_info.features;
+
+  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;
+      default:
+	internal_error (__FILE__, __LINE__,
+			_("Unknown hardware breakpoint/watchpoint type."));
+    }
+}
+
+static int
 ppc_linux_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
 {
   /* Handle sub-8-byte quantities.  */
@@ -1489,9 +1511,15 @@ ppc_linux_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
      to determine the hardcoded watchable region for watchpoints.  */
   if (have_ptrace_booke_interface ())
     {
-      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 (ppc_linux_can_use_special_hw_point (HW_POINT_RANGED_WATCH))
+	return 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
@@ -1685,6 +1713,110 @@ get_trigger_type (int rw)
   return t;
 }
 
+static int
+ppc_linux_insert_mask_watchpoint (CORE_ADDR addr, CORE_ADDR mask, int rw)
+{
+  ptid_t ptid;
+  struct lwp_info *lp;
+  struct ppc_hw_breakpoint p;
+
+  gdb_assert (have_ptrace_booke_interface ());
+
+  if ((mask & 0xC0000000) != 0xC0000000)
+    error (_("\
+The given mask covers kernel address space and cannot be used.\n\
+You have to delete the masked watchpoint to continue the debugging session."));
+
+  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) addr;
+  p.addr2           = (uint64_t) mask;
+  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, CORE_ADDR mask, int rw)
+{
+  ptid_t ptid;
+  struct lwp_info *lp;
+  struct ppc_hw_breakpoint p;
+
+  gdb_assert (have_ptrace_booke_interface ());
+
+  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) addr;
+  p.addr2           = (uint64_t) mask;
+  p.condition_value = 0;
+
+  ALL_LWPS (lp, ptid)
+    booke_remove_point (&p, TIDGET (ptid));
+
+  return 0;
+}
+
+static int
+ppc_linux_insert_ranged_watchpoint (CORE_ADDR addr, int len, int rw)
+{
+  ptid_t ptid;
+  struct lwp_info *lp;
+  struct ppc_hw_breakpoint p;
+
+  gdb_assert (have_ptrace_booke_interface ());
+
+  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.condition_value = 0;
+
+  /* The watchpoint will trigger if the address of the memory access is
+     within the defined range, as follows: p.addr <= address < p.addr2.
+
+     Note that the above sentence just documents how ptrace interprets
+     its arguments; the watchpoint is set to watch the range defined by
+     the user _inclusively_, as specified by the user interface.  */
+  p.addr            = (uint64_t) addr;
+  p.addr2           = (uint64_t) addr + len;
+
+  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)
+{
+  ptid_t ptid;
+  struct lwp_info *lp;
+  struct ppc_hw_breakpoint p;
+
+  gdb_assert (have_ptrace_booke_interface ());
+
+  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;
+}
+
 /* Check whether we have at least one free DVC register.  */
 static int
 can_use_watchpoint_cond_accel (void)
@@ -2136,6 +2268,14 @@ ppc_linux_watchpoint_addr_within_range (struct target_ops *target,
   return start <= addr + mask && start + length - 1 >= addr;
 }
 
+static int
+ppc_linux_hw_point_extra_slot_count (enum hw_point_flag flag)
+{
+  gdb_assert (flag == HW_POINT_MASKED_WATCH || flag == HW_POINT_RANGED_WATCH);
+
+  return 1;
+}
+
 static void
 ppc_linux_store_inferior_registers (struct target_ops *ops,
 				    struct regcache *regcache, int regno)
@@ -2347,12 +2487,18 @@ _initialize_ppc_linux_nat (void)
   t->to_insert_hw_breakpoint = ppc_linux_insert_hw_breakpoint;
   t->to_remove_hw_breakpoint = ppc_linux_remove_hw_breakpoint;
   t->to_region_ok_for_hw_watchpoint = ppc_linux_region_ok_for_hw_watchpoint;
+  t->to_can_use_special_hw_point = ppc_linux_can_use_special_hw_point;
   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_stopped_by_watchpoint = ppc_linux_stopped_by_watchpoint;
   t->to_stopped_data_address = ppc_linux_stopped_data_address;
   t->to_watchpoint_addr_within_range = ppc_linux_watchpoint_addr_within_range;
   t->to_can_accel_watchpoint_condition = ppc_linux_can_accel_watchpoint_condition;
+  t->to_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/target.c b/gdb/target.c
index dd976c9..a9058a3 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -601,11 +601,16 @@ update_current_target (void)
       INHERIT (to_files_info, t);
       INHERIT (to_insert_breakpoint, t);
       INHERIT (to_remove_breakpoint, t);
+      INHERIT (to_can_use_special_hw_point, t);
       INHERIT (to_can_use_hw_breakpoint, t);
       INHERIT (to_insert_hw_breakpoint, t);
       INHERIT (to_remove_hw_breakpoint, t);
       INHERIT (to_insert_watchpoint, t);
       INHERIT (to_remove_watchpoint, t);
+      INHERIT (to_insert_ranged_watchpoint, t);
+      INHERIT (to_remove_ranged_watchpoint, t);
+      INHERIT (to_insert_mask_watchpoint, t);
+      INHERIT (to_remove_mask_watchpoint, t);
       INHERIT (to_stopped_data_address, t);
       INHERIT (to_have_steppable_watchpoint, t);
       INHERIT (to_have_continuable_watchpoint, t);
@@ -613,6 +618,7 @@ update_current_target (void)
       INHERIT (to_watchpoint_addr_within_range, t);
       INHERIT (to_region_ok_for_hw_watchpoint, t);
       INHERIT (to_can_accel_watchpoint_condition, 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);
@@ -727,6 +733,9 @@ update_current_target (void)
   de_fault (to_can_use_hw_breakpoint,
 	    (int (*) (int, int, int))
 	    return_zero);
+  de_fault (to_can_use_special_hw_point,
+	    (int (*) (enum hw_point_flag))
+	    return_zero);
   de_fault (to_insert_hw_breakpoint,
 	    (int (*) (struct gdbarch *, struct bp_target_info *))
 	    return_minus_one);
@@ -739,6 +748,18 @@ update_current_target (void)
   de_fault (to_remove_watchpoint,
 	    (int (*) (CORE_ADDR, int, int, struct expression *))
 	    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, CORE_ADDR, int))
+            return_minus_one);
+  de_fault (to_remove_mask_watchpoint,
+            (int (*) (CORE_ADDR, CORE_ADDR, int))
+            return_minus_one);
   de_fault (to_stopped_by_watchpoint,
 	    (int (*) (void))
 	    return_zero);
@@ -752,6 +773,9 @@ update_current_target (void)
   de_fault (to_can_accel_watchpoint_condition,
             (int (*) (CORE_ADDR, int, int, struct expression *))
             return_zero);
+  de_fault (to_hw_point_extra_slot_count,
+            (int (*) (enum hw_point_flag))
+            return_zero);
   de_fault (to_terminal_init,
 	    (void (*) (void))
 	    target_ignore);
diff --git a/gdb/target.h b/gdb/target.h
index 7687d8f..54a6747 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -39,6 +39,8 @@ struct static_tracepoint_marker;
 
 struct expression;
 
+enum hw_point_flag;
+
 /* This include file defines the interface between the main part
    of the debugger, and the part which is target-specific, or
    specific to the communications interface between us and the
@@ -438,6 +440,7 @@ struct target_ops
     int (*to_insert_breakpoint) (struct gdbarch *, struct bp_target_info *);
     int (*to_remove_breakpoint) (struct gdbarch *, struct bp_target_info *);
     int (*to_can_use_hw_breakpoint) (int, int, int);
+    int (*to_can_use_special_hw_point) (enum hw_point_flag);
     int (*to_insert_hw_breakpoint) (struct gdbarch *, struct bp_target_info *);
     int (*to_remove_hw_breakpoint) (struct gdbarch *, struct bp_target_info *);
 
@@ -446,6 +449,10 @@ struct target_ops
     int (*to_remove_watchpoint) (CORE_ADDR, int, int, struct expression *);
     int (*to_insert_watchpoint) (CORE_ADDR, int, int, struct expression *);
 
+    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, CORE_ADDR, int);
+    int (*to_remove_mask_watchpoint) (CORE_ADDR, CORE_ADDR, int);
     int (*to_stopped_by_watchpoint) (void);
     int to_have_steppable_watchpoint;
     int to_have_continuable_watchpoint;
@@ -455,6 +462,7 @@ struct target_ops
     int (*to_region_ok_for_hw_watchpoint) (CORE_ADDR, int);
     int (*to_can_accel_watchpoint_condition) (CORE_ADDR, int, int,
 					      struct expression *);
+    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);
@@ -1314,6 +1322,11 @@ extern char *normal_pid_to_str (ptid_t ptid);
 #define target_region_ok_for_hw_watchpoint(addr, len) \
     (*current_target.to_region_ok_for_hw_watchpoint) (addr, len)
 
+/* Returns non-zero if the target supports the special type of hardware
+   breakpoint/watchpoint represented by FLAG.  */
+#define target_can_use_special_hw_point(flag) \
+  (*current_target.to_can_use_special_hw_point) (flag)
+
 
 /* Set/clear a hardware watchpoint starting at ADDR, for LEN bytes.
    TYPE is 0 for write, 1 for read, and 2 for read/write accesses.
@@ -1327,6 +1340,20 @@ extern char *normal_pid_to_str (ptid_t ptid);
 #define	target_remove_watchpoint(addr, len, type, cond) \
      (*current_target.to_remove_watchpoint) (addr, len, type, cond)
 
+/* Hardware ranged watchpoints.  */
+#define target_insert_ranged_watchpoint(addr, len, type) \
+  (*current_target.to_insert_ranged_watchpoint) (addr, len, type)
+
+#define target_remove_ranged_watchpoint(addr, len, type) \
+  (*current_target.to_remove_ranged_watchpoint) (addr, len, type)
+
+/* Hardware watchpoints with an associated address mask.  */
+#define target_insert_mask_watchpoint(addr, mask, type) \
+  (*current_target.to_insert_mask_watchpoint) (addr, mask, type)
+
+#define target_remove_mask_watchpoint(addr, mask, type) \
+  (*current_target.to_remove_mask_watchpoint) (addr, mask, type)
+
 #define target_insert_hw_breakpoint(gdbarch, bp_tgt) \
      (*current_target.to_insert_hw_breakpoint) (gdbarch, bp_tgt)
 
@@ -1355,6 +1382,9 @@ extern char *normal_pid_to_str (ptid_t ptid);
 #define target_can_accel_watchpoint_condition(addr, len, type, cond) \
   (*current_target.to_can_accel_watchpoint_condition) (addr, len, type, cond)
 
+#define target_hw_point_extra_slot_count(flag) \
+  (*current_target.to_hw_point_extra_slot_count) (flag)
+
 /* Target can execute in reverse?  */
 #define target_can_execute_reverse \
      (current_target.to_can_execute_reverse ? \
diff --git a/gdb/ui-out.c b/gdb/ui-out.c
index 4d3bf0c..d6bea30 100644
--- a/gdb/ui-out.c
+++ b/gdb/ui-out.c
@@ -487,6 +487,46 @@ ui_out_field_fmt_int (struct ui_out *uiout,
 }
 
 void
+ui_out_field_range_core_addr (struct ui_out *uiout,
+			      const char *fldname,
+			      struct gdbarch *gdbarch,
+			      CORE_ADDR address_start,
+			      CORE_ADDR length)
+{
+  char addstr[80];
+  int addr_bit = gdbarch_addr_bit (gdbarch);
+  CORE_ADDR address_end = address_start + length - 1;
+
+  if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT))
+  {
+    address_start &= ((CORE_ADDR) 1 << addr_bit) - 1;
+    address_end &= ((CORE_ADDR) 1 << addr_bit) - 1;
+  }
+
+  /* FIXME: cagney/2002-05-03: Need local_address_string() function
+     that returns the language localized string formatted to a width
+     based on gdbarch_addr_bit.  */
+  if (addr_bit <= 32)
+  {
+    strcpy (addstr, "[");
+    strcat (addstr, hex_string_custom (address_start, 8));
+    strcat (addstr, ", ");
+    strcat (addstr, hex_string_custom (address_end, 8));
+    strcat (addstr, "]");
+  }
+  else
+  {
+    strcpy (addstr, "[");
+    strcat (addstr, hex_string_custom (address_start, 16));
+    strcat (addstr, ", ");
+    strcat (addstr, hex_string_custom (address_end, 16));
+    strcat (addstr, "]");
+  }
+
+  ui_out_field_string (uiout, fldname, addstr);
+}
+
+void
 ui_out_field_core_addr (struct ui_out *uiout,
 			const char *fldname,
 			struct gdbarch *gdbarch,
diff --git a/gdb/ui-out.h b/gdb/ui-out.h
index f65f42b..594691e 100644
--- a/gdb/ui-out.h
+++ b/gdb/ui-out.h
@@ -113,6 +113,12 @@ extern void ui_out_field_fmt_int (struct ui_out *uiout, int width,
 				  enum ui_align align, const char *fldname, 
 		 		  int value);
 
+extern void ui_out_field_range_core_addr (struct ui_out *uiout,
+					  const char *fldname,
+                                          struct gdbarch *gdbarch,
+					  CORE_ADDR address_start,
+					  CORE_ADDR length);
+
 extern void ui_out_field_core_addr (struct ui_out *uiout, const char *fldname,
 				    struct gdbarch *gdbarch, CORE_ADDR address);
 
diff --git a/gdb/value.h b/gdb/value.h
index d7912a8..64ea334 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -559,6 +559,9 @@ extern CORE_ADDR parse_and_eval_address_1 (char **expptr);
 
 extern LONGEST parse_and_eval_long (char *exp);
 
+int 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);


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

* Re: [patch 2/2] Implement support for PowerPC BookE masked and ranged watchpoints
  2010-11-01 21:47         ` Thiago Jung Bauermann
@ 2010-11-02  3:53           ` Eli Zaretskii
  2010-11-04 21:12             ` Thiago Jung Bauermann
  0 siblings, 1 reply; 19+ messages in thread
From: Eli Zaretskii @ 2010-11-02  3:53 UTC (permalink / raw)
  To: Thiago Jung Bauermann; +Cc: gdb-patches

> From: Thiago Jung Bauermann <bauerman@br.ibm.com>
> Cc: gdb-patches@sourceware.org
> Date: Mon, 01 Nov 2010 19:47:06 -0200
> 
> What about this?
> 
>   /* The watchpoint will trigger if the address of the memory access is
>      within the defined range, as follows: p.addr <= address < p.addr2.
> 
>      Note that the above sentence just documents how ptrace interprets
>      its arguments; the watchpoint is set to watch the range defined by
>      the user _inclusively_, as specified by the user interface.  */

That's fine, thanks.

> +* GDB now supports ranged watchpoints, which stop the inferior when it
> +  accesses any address within a specified memory range.  See the
> +  documentation on the watch-range command for more information.  The
> +  watchpoint is hardware-accelerated on some targets (currently only when
> +  locally debugging programs on PowerPC BookE processors running a Linux
> +  kernel version 2.6.34 or later.)

The last period should be outside the parentheses.

> +* Also on native debugging on Linux running on PowerPC BookE, GDB supports
          ^^
"for"

> +  masked hardware watchpoints, which specifiy a mask in addition to an
> +  address to watch.  The mask specifies that some bits of an address (the
> +  bits which are reset in the mask) should be ignored when matching the
> +  address accessed by the inferior against the watchpoint address.

A pointer to the corresponding section in the manual would be good
here.

> +watch
> +  The watch command now supports the mask argument which allows creation
> +  of masked watchpoints, if the current architecture supports this feature.

Instead of just "watch", I suggest to show here its form with a mask.

OK with those changes.

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

* Re: [patch 2/2] Implement support for PowerPC BookE masked and ranged watchpoints
  2010-11-02  3:53           ` Eli Zaretskii
@ 2010-11-04 21:12             ` Thiago Jung Bauermann
  2010-11-16  4:01               ` Jan Kratochvil
  0 siblings, 1 reply; 19+ messages in thread
From: Thiago Jung Bauermann @ 2010-11-04 21:12 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches

Hi,

On Tue, 2010-11-02 at 05:53 +0200, Eli Zaretskii wrote:
> > From: Thiago Jung Bauermann <bauerman@br.ibm.com>
> > Cc: gdb-patches@sourceware.org
> > Date: Mon, 01 Nov 2010 19:47:06 -0200
> > 
> > +  masked hardware watchpoints, which specifiy a mask in addition to an
> > +  address to watch.  The mask specifies that some bits of an address (the
> > +  bits which are reset in the mask) should be ignored when matching the
> > +  address accessed by the inferior against the watchpoint address.
> 
> A pointer to the corresponding section in the manual would be good
> here.

I appended this line to the paragraph:

  See the "PowerPC Embedded" section in the user manual for more details.

> > +watch
> > +  The watch command now supports the mask argument which allows creation
> > +  of masked watchpoints, if the current architecture supports this feature.
> 
> Instead of just "watch", I suggest to show here its form with a mask.

It now reads:

watch EXPR mask MASK_VALUE
  The watch command now supports the mask argument which allows creation
  of masked watchpoints, if the current architecture supports this feature.

> OK with those changes.

Here's a new version with the fixes.

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


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

	Implement support for PowerPC BookE masked and ranged watchpoints.

gdb/
	*NEWS: Mention masked and ranged watchpoint support.
	* breakpoint.c (update_watchpoint): Call breakpoint's
	breakpoint_ops.extra_resources_needed and
	breakpoint_ops.works_in_software_mode if available.
	(watchpoints_triggered): Handle the case of a hardware masked
	watchpoint trigger.
	(watchpoint_check): Handle the case of a hardware masked watchpoint
	trigger.
	(print_one_breakpoint_location): Call breakpoint's
	breakpoint_ops.print_one_detail if available.
	(hw_watchpoint_used_count): Call breakpoint's
	breakpoint_ops.extra_resources_needed if available.
	(insert_ranged_watchpoint, remove_ranged_watchpoint)
	(extra_resources_needed_ranged_watchpoint)
	(print_one_detail_ranged_watchpoint, print_mention_ranged_watchpoint)
	(print_recreate_ranged_watchpoint): New functions.
	(ranged_watchpoint_breakpoint_ops): New structure.
	(insert_masked_watchpoint, remove_masked_watchpoint)
	(extra_resources_needed_masked_watchpoint)
	(works_in_software_mode_masked_watchpoint, print_it_masked_watchpoint)
	(print_one_detail_masked_watchpoint, print_mention_masked_watchpoint)
	(print_recreate_masked_watchpoint, is_masked_watchpoint): New functions.
	(masked_watchpoint_breakpoint_ops): New structure.
	(watch_command_1): Check for the existence of the `mask' parameter.
	Check whether a ranged hardware watchpoint can be used. Set b->ops
	according to the type of hardware watchpoint being created.
	(watch_range_command_1, watch_range_command)
	(awatch_range_command, rwatch_range_command): New functions.
	(_initialize_breakpoint): Register watch-range, awatch-range and
	rwatch-range commands.
	* breakpoint.h (struct ui_out): New opaque declaration.
	(struct breakpoint_ops) <extra_resources_needed>,
	<works_in_software_mode>, <print_one_detail>: New methods.
	Initialize them to NULL in all existing breakpoint_ops instances.
	(struct breakpoint_ops) <print_it>: Add OLD_VAL parameter.  Update all
	implementations of the method.
	(enum hw_point_flag): New enumeration.
	(struct breakpoint) <hw_wp_mask>: New field.
	* findcmd.c (parse_addr_range): New function factored out of
	parse_find_args.
	(parse_find_args): Call `parse_addr_range'.
	* ppc-linux-nat.c (ppc_linux_can_use_special_hw_point): New function.
	(ppc_linux_region_ok_for_hw_watchpoint): Always handle regions when
	ranged watchpoints are available.
	(ppc_linux_insert_mask_watchpoint, ppc_linux_remove_mask_watchpoint)
	(ppc_linux_insert_ranged_watchpoint, ppc_linux_remove_ranged_watchpoint)
	(ppc_linux_hw_point_extra_slot_count): New functions.
	(_initialize_ppc_linux_nat): Initialize to_insert_mask_watchpoint,
	to_remove_mask_watchpoint, to_insert_ranged_watchpoint,
	to_remove_ranged_watchpoint, hw_point_extra_slot_count and
	to_can_use_special_hw_point.
	* target.c (update_current_target): Insert to_insert_mask_watchpoint,
	to_remove_mask_watchpoint, to_insert_ranged_watchpoint,
	to_remove_ranged_watchpoint, to_hw_point_extra_slot_count
	and to_can_use_special_hw_point.
	* target.h (enum hw_point_flag): New opaque declaration.
	(struct target_ops) <to_insert_mask_watchpoint>,
	<to_remove_mask_watchpoint>, <to_insert_ranged_watchpoint>,
	<to_remove_ranged_watchpoint>, <to_hw_point_extra_slot_count>,
	<to_can_use_special_hw_point>: New callbacks.
	(target_insert_mask_watchpoint, target_remove_mask_watchpoint)
	(target_insert_ranged_watchpoint, target_remove_ranged_watchpoint)
	(target_hw_point_extra_slot_count, target_can_use_special_hw_point): New
	defines.
	* ui-out.c (ui_out_field_range_core_addr): New function.
	* ui-out.h (ui_out_field_range_core_addr): Declare.
	* value.h (parse_addr_range): Declare.

gdb/doc/
	* gdb.texinfo (Set Watchpoints): Document mask parameter.
	(PowerPC Embedded): Document masked watchpoints and ranged watchpoints.


diff --git a/gdb/NEWS b/gdb/NEWS
index 033d2fe..bcc8041 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -66,6 +66,20 @@
   libthread_db library with the "set libthread-db-search-path"
   command.  See the user manual for more details on this command.
 
+* GDB now supports ranged watchpoints, which stop the inferior when it
+  accesses any address within a specified memory range.  See the
+  documentation on the watch-range command for more information.  The
+  watchpoint is hardware-accelerated on some targets (currently only when
+  locally debugging programs on PowerPC BookE processors running a Linux
+  kernel version 2.6.34 or later).
+
+* Also for native debugging on Linux running on PowerPC BookE, GDB supports
+  masked hardware watchpoints, which specifiy a mask in addition to an
+  address to watch.  The mask specifies that some bits of an address (the
+  bits which are reset in the mask) should be ignored when matching the
+  address accessed by the inferior against the watchpoint address.
+  See the "PowerPC Embedded" section in the user manual for more details.
+
 * New features in the GDB remote stub, GDBserver
 
   ** GDBserver is now supported on PowerPC LynxOS (versions 4.x and 5.x),
@@ -76,6 +90,22 @@
   see the "Tasking Support when using the Ravenscar Profile" section
   in the GDB user manual.
 
+* New commands
+
+watch-range START_ADDR,+LENGTH | START_ADDR, END_ADDR
+rwatch-range START_ADDR,+LENGTH | START_ADDR, END_ADDR
+awatch-range START_ADDR,+LENGTH | START_ADDR, END_ADDR
+  Set a hardware watchpoint for an address range.
+  The watchpoint will stop execution of your program whenever the inferior
+  writes, reads, or accesses (respectively for watch-range, awatch-range
+  and rwatch-range) any address within the specified range.
+
+* Changed commands
+
+watch EXPR mask MASK_VALUE
+  The watch command now supports the mask argument which allows creation
+  of masked watchpoints, if the current architecture supports this feature.
+
 *** Changes in GDB 7.2
 
 * Shared library support for remote targets by default
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index ea71ea2..4f438ed 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10756,7 +10756,7 @@ print_recreate_exception (enum exception_catchpoint_kind ex,
 /* Virtual table for "catch exception" breakpoints.  */
 
 static enum print_stop_action
-print_it_catch_exception (struct breakpoint *b)
+print_it_catch_exception (struct breakpoint *b, const struct value *old_val)
 {
   return print_it_exception (ex_catch_exception, b);
 }
@@ -10784,8 +10784,11 @@ static struct breakpoint_ops catch_exception_breakpoint_ops =
   NULL, /* insert */
   NULL, /* remove */
   NULL, /* breakpoint_hit */
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_exception,
   print_one_catch_exception,
+  NULL, /* print_one_detail */
   print_mention_catch_exception,
   print_recreate_catch_exception
 };
@@ -10793,7 +10796,8 @@ static struct breakpoint_ops catch_exception_breakpoint_ops =
 /* Virtual table for "catch exception unhandled" breakpoints.  */
 
 static enum print_stop_action
-print_it_catch_exception_unhandled (struct breakpoint *b)
+print_it_catch_exception_unhandled (struct breakpoint *b,
+				    const struct value *old_val)
 {
   return print_it_exception (ex_catch_exception_unhandled, b);
 }
@@ -10822,8 +10826,11 @@ static struct breakpoint_ops catch_exception_unhandled_breakpoint_ops = {
   NULL, /* insert */
   NULL, /* remove */
   NULL, /* breakpoint_hit */
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_exception_unhandled,
   print_one_catch_exception_unhandled,
+  NULL, /* print_one_detail */
   print_mention_catch_exception_unhandled,
   print_recreate_catch_exception_unhandled
 };
@@ -10831,7 +10838,7 @@ static struct breakpoint_ops catch_exception_unhandled_breakpoint_ops = {
 /* Virtual table for "catch assert" breakpoints.  */
 
 static enum print_stop_action
-print_it_catch_assert (struct breakpoint *b)
+print_it_catch_assert (struct breakpoint *b, const struct value *old_val)
 {
   return print_it_exception (ex_catch_assert, b);
 }
@@ -10858,8 +10865,11 @@ static struct breakpoint_ops catch_assert_breakpoint_ops = {
   NULL, /* insert */
   NULL, /* remove */
   NULL, /* breakpoint_hit */
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_assert,
   print_one_catch_assert,
+  NULL, /* print_one_detail */
   print_mention_catch_assert,
   print_recreate_catch_assert
 };
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 04878be..14e8fd0 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -219,6 +219,8 @@ static void disable_trace_command (char *, int);
 
 static void trace_pass_command (char *, int);
 
+static int is_masked_watchpoint (const struct breakpoint *b);
+
 /* Assuming we're creating a static tracepoint, does S look like a
    static tracepoint marker spec ("-m MARKER_ID")?  */
 #define is_marker_spec(s)						\
@@ -1391,27 +1393,52 @@ update_watchpoint (struct breakpoint *b, int reparse)
 	if ((b->type == bp_watchpoint || b->type == bp_hardware_watchpoint)
 	    && reparse)
 	  {
-	    int i, mem_cnt, other_type_used;
-
-	    /* We need to determine how many resources are already used
-	       for all other hardware watchpoints to see if we still have
-	       enough resources to also fit this watchpoint in as well.
-	       To avoid the hw_watchpoint_used_count call below from counting
-	       this watchpoint, make sure that it is marked as a software
-	       watchpoint.  */
-	    b->type = bp_watchpoint;
-	    i = hw_watchpoint_used_count (bp_hardware_watchpoint,
-					  &other_type_used);
+	    int mem_cnt;
+
 	    mem_cnt = can_use_hardware_watchpoint (val_chain);
 
 	    if (!mem_cnt)
-	      b->type = bp_watchpoint;
+	      {
+		if (b->type == bp_hardware_watchpoint
+		    && b->ops && b->ops->works_in_software_mode
+		    && !b->ops->works_in_software_mode (b))
+		  error (_("This watchpoint cannot be used in software mode."));
+		else
+		  b->type = bp_watchpoint;
+	      }
 	    else
 	      {
-		int target_resources_ok = target_can_use_hardware_watchpoint
-		  (bp_hardware_watchpoint, i + mem_cnt, other_type_used);
+		int i, other_type_used, target_resources_ok;
+		enum bptype orig_type;
+
+		if (b->ops && b->ops->extra_resources_needed)
+		  mem_cnt += b->ops->extra_resources_needed (b);
+
+		/* We need to determine how many resources are already used
+		   for all other hardware watchpoints to see if we still have
+		   enough resources to also fit this watchpoint in as well.
+		   To avoid the hw_watchpoint_used_count call below from
+		   counting this watchpoint, make sure that it is marked as a
+		   software watchpoint.  */
+		orig_type = b->type;
+		b->type = bp_watchpoint;
+		i = hw_watchpoint_used_count (bp_hardware_watchpoint,
+					      &other_type_used);
+
+		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;
+		  {
+		    if (orig_type == bp_hardware_watchpoint
+			&& b->ops && b->ops->works_in_software_mode
+			&& !b->ops->works_in_software_mode (b))
+		      {
+			b->type = bp_hardware_watchpoint;
+			error (_("This watchpoint cannot be used in software mode."));
+		      }
+		    else
+		      b->type = bp_watchpoint;
+		  }
 		else
 		  b->type = bp_hardware_watchpoint;
 	      }
@@ -3368,7 +3395,7 @@ print_bp_stop_message (bpstat bs)
 	   print_it_typical.  */
 	/* FIXME: how breakpoint can ever be NULL here?  */
 	if (b != NULL && b->ops != NULL && b->ops->print_it != NULL)
-	  return b->ops->print_it (b);
+	  return b->ops->print_it (b, bs->old_val);
 	else
 	  return print_it_typical (bs);
       }
@@ -3504,15 +3531,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 (is_masked_watchpoint (loc->owner))
+	      {
+		newaddr = addr & loc->owner->hw_wp_mask;
+		start = loc->address & loc->owner->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;
@@ -3626,6 +3668,11 @@ watchpoint_check (void *p)
 	  b->val_valid = 1;
 	  return WP_VALUE_CHANGED;
 	}
+      else if (is_masked_watchpoint (b))
+	/* 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.  */
@@ -4696,9 +4743,12 @@ print_one_breakpoint_location (struct breakpoint *b,
 	  ui_out_field_int (uiout, "task", b->task);
 	}
     }
-  
+
   ui_out_text (uiout, "\n");
-  
+
+  if (!part_of_multiple && b->ops && b->ops->print_one_detail)
+    b->ops->print_one_detail (b, uiout);
+
   if (!part_of_multiple && b->static_trace_marker_id)
     {
       gdb_assert (b->type == bp_static_tracepoint);
@@ -5869,7 +5919,7 @@ breakpoint_hit_catch_fork (struct breakpoint *b)
 /* Implement the "print_it" breakpoint_ops method for fork catchpoints.  */
 
 static enum print_stop_action
-print_it_catch_fork (struct breakpoint *b)
+print_it_catch_fork (struct breakpoint *b, const struct value *old_val)
 {
   annotate_catchpoint (b->number);
   printf_filtered (_("\nCatchpoint %d (forked process %d), "),
@@ -5927,8 +5977,11 @@ static struct breakpoint_ops catch_fork_breakpoint_ops =
   insert_catch_fork,
   remove_catch_fork,
   breakpoint_hit_catch_fork,
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_fork,
   print_one_catch_fork,
+  NULL, /* print_one_detail */
   print_mention_catch_fork,
   print_recreate_catch_fork
 };
@@ -5961,7 +6014,7 @@ breakpoint_hit_catch_vfork (struct breakpoint *b)
 /* Implement the "print_it" breakpoint_ops method for vfork catchpoints.  */
 
 static enum print_stop_action
-print_it_catch_vfork (struct breakpoint *b)
+print_it_catch_vfork (struct breakpoint *b, const struct value *old_val)
 {
   annotate_catchpoint (b->number);
   printf_filtered (_("\nCatchpoint %d (vforked process %d), "),
@@ -6018,8 +6071,11 @@ static struct breakpoint_ops catch_vfork_breakpoint_ops =
   insert_catch_vfork,
   remove_catch_vfork,
   breakpoint_hit_catch_vfork,
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_vfork,
   print_one_catch_vfork,
+  NULL, /* print_one_detail */
   print_mention_catch_vfork,
   print_recreate_catch_vfork
 };
@@ -6139,7 +6195,7 @@ breakpoint_hit_catch_syscall (struct breakpoint *b)
    catchpoints.  */
 
 static enum print_stop_action
-print_it_catch_syscall (struct breakpoint *b)
+print_it_catch_syscall (struct breakpoint *b, const struct value *old_val)
 {
   /* These are needed because we want to know in which state a
      syscall is.  It can be in the TARGET_WAITKIND_SYSCALL_ENTRY
@@ -6299,8 +6355,11 @@ static struct breakpoint_ops catch_syscall_breakpoint_ops =
   insert_catch_syscall,
   remove_catch_syscall,
   breakpoint_hit_catch_syscall,
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_syscall,
   print_one_catch_syscall,
+  NULL, /* print_one_detail */
   print_mention_catch_syscall,
   print_recreate_catch_syscall
 };
@@ -6402,7 +6461,7 @@ breakpoint_hit_catch_exec (struct breakpoint *b)
 }
 
 static enum print_stop_action
-print_it_catch_exec (struct breakpoint *b)
+print_it_catch_exec (struct breakpoint *b, const struct value *old_val)
 {
   annotate_catchpoint (b->number);
   printf_filtered (_("\nCatchpoint %d (exec'd %s), "), b->number,
@@ -6452,8 +6511,11 @@ static struct breakpoint_ops catch_exec_breakpoint_ops =
   insert_catch_exec,
   remove_catch_exec,
   breakpoint_hit_catch_exec,
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_exec,
   print_one_catch_exec,
+  NULL, /* print_one_detail */
   print_mention_catch_exec,
   print_recreate_catch_exec
 };
@@ -6501,7 +6563,14 @@ hw_watchpoint_used_count (enum bptype type, int *other_type_used)
     if (breakpoint_enabled (b))
       {
 	if (b->type == type)
-	  i++;
+	  {
+	    i++;
+
+	    /* Special types of hardware watchpoints can use more than
+	       one register.  */
+	    if (b->ops && b->ops->extra_resources_needed)
+	      i += b->ops->extra_resources_needed (b);
+	  }
 	else if (is_hardware_watchpoint (b))
 	  *other_type_used = 1;
       }
@@ -8043,12 +8112,353 @@ static struct breakpoint_ops watchpoint_breakpoint_ops =
   insert_watchpoint,
   remove_watchpoint,
   NULL, /* breakpoint_hit */
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
   NULL, /* print_it */
   NULL, /* print_one */
+  NULL, /* print_one_detail */
   NULL, /* print_mention */
   NULL  /* print_recreate */
 };
 
+/* Implement the "insert" breakpoint_ops method for
+   ranged hardware watchpoints.  */
+
+static int
+insert_ranged_watchpoint (struct bp_location *bpt)
+{
+  return target_insert_ranged_watchpoint (bpt->address,
+					  bpt->length,
+					  bpt->watchpoint_type);
+}
+
+/* Implement the "remove" breakpoint_ops method for
+   ranged hardware watchpoints.  */
+
+static int
+remove_ranged_watchpoint (struct bp_location *bpt)
+{
+  return target_remove_ranged_watchpoint (bpt->address, bpt->length,
+					  bpt->watchpoint_type);
+}
+
+/* Implement the "extra_resources_needed" breakpoint_ops method for
+   ranged hardware watchpoints.  */
+
+static int
+extra_resources_needed_ranged_watchpoint (const struct breakpoint *b)
+{
+  return target_hw_point_extra_slot_count (HW_POINT_RANGED_WATCH);
+}
+
+/* Implement the "print_one_detail" breakpoint_ops method for
+   ranged hardware watchpoints.  */
+
+static void
+print_one_detail_ranged_watchpoint (const struct breakpoint *b, struct ui_out *uiout)
+{
+  /* If there's a separate expression for reparsing, then exp_string is already
+     a nice text set by watch_range_command_1 and was printed earlier.  */
+  if (b->exp_string_reparse)
+    return;
+
+  gdb_assert (b->loc);
+
+  ui_out_text (uiout, "\tmemory range: ");
+  ui_out_field_range_core_addr (uiout, "addr", b->loc->gdbarch,
+				b->loc->address, b->loc->length);
+  ui_out_text (uiout, "\n");
+}
+
+/* Implement the "print_mention" breakpoint_ops method for
+   ranged hardware watchpoints.  */
+
+static void
+print_mention_ranged_watchpoint (struct breakpoint *b)
+{
+  struct cleanup *ui_out_chain;
+
+  switch (b->type)
+    {
+    case bp_watchpoint:
+      ui_out_text (uiout, "Ranged watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt");
+      break;
+    case bp_hardware_watchpoint:
+      ui_out_text (uiout, "Ranged hardware watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt");
+      break;
+    case bp_read_watchpoint:
+      ui_out_text (uiout, "Ranged hardware read watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-rwpt");
+      break;
+    case bp_access_watchpoint:
+      ui_out_text (uiout, "Ranged hardware access (read/write) watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-awpt");
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  ui_out_field_int (uiout, "number", b->number);
+  ui_out_text (uiout, ": ");
+  ui_out_field_string (uiout, "exp", b->exp_string);
+  do_cleanups (ui_out_chain);
+}
+
+static void
+print_recreate_ranged_watchpoint (struct breakpoint *b, struct ui_file *fp)
+{
+  switch (b->type)
+    {
+    case bp_watchpoint:
+    case bp_hardware_watchpoint:
+      if (b->exp_string_reparse)
+	fprintf_unfiltered (fp, "watch-range");
+      else
+	fprintf_unfiltered (fp, "watch");
+      break;
+    case bp_read_watchpoint:
+      if (b->exp_string_reparse)
+	fprintf_unfiltered (fp, "rwatch-range");
+      else
+	fprintf_unfiltered (fp, "rwatch");
+      break;
+    case bp_access_watchpoint:
+      if (b->exp_string_reparse)
+	fprintf_unfiltered (fp, "awatch-range");
+      else
+	fprintf_unfiltered (fp, "awatch");
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  if (b->exp_string_reparse)
+    {
+      char start_addr[40], length[40];
+
+      /* watch_range_command_1 creates the following expression to represent
+	 internally a ranged watchpoint.  */
+      sscanf (b->exp_string_reparse, "{char[ %39s ]} %39s", length, start_addr);
+
+      fprintf_unfiltered (fp, " %s, +%s", start_addr, length);
+    }
+  else
+    fprintf_unfiltered (fp, " %s", b->exp_string);
+}
+
+/* The breakpoint_ops structure to be used in ranged hardware watchpoints.  */
+
+static struct breakpoint_ops ranged_watchpoint_breakpoint_ops =
+{
+  insert_ranged_watchpoint,
+  remove_ranged_watchpoint,
+  NULL, /* breakpoint_hit */
+  extra_resources_needed_ranged_watchpoint,
+  NULL, /* works_in_software_mode */
+  NULL, /* print_it */
+  NULL, /* print_one */
+  print_one_detail_ranged_watchpoint,
+  print_mention_ranged_watchpoint,
+  print_recreate_ranged_watchpoint
+};
+
+/* Implement the "insert" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static int
+insert_masked_watchpoint (struct bp_location *bpt)
+{
+  return target_insert_mask_watchpoint (bpt->address, bpt->owner->hw_wp_mask,
+					bpt->watchpoint_type);
+}
+
+/* Implement the "remove" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static int
+remove_masked_watchpoint (struct bp_location *bpt)
+{
+  return target_remove_mask_watchpoint (bpt->address, bpt->owner->hw_wp_mask,
+				        bpt->watchpoint_type);
+}
+
+/* Implement the "extra_resources_needed" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static int
+extra_resources_needed_masked_watchpoint (const struct breakpoint *b)
+{
+  return target_hw_point_extra_slot_count (HW_POINT_MASKED_WATCH);
+}
+
+/* Implement the "works_in_software_mode_masked_watchpoint" breakpoint_ops
+   method for masked hardware watchpoints.  */
+
+static int
+works_in_software_mode_masked_watchpoint (const struct breakpoint *b)
+{
+  return 0;
+}
+
+/* Implement the "print_it" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static enum print_stop_action
+print_it_masked_watchpoint (struct breakpoint *b, const struct value *old_val)
+{
+  struct ui_stream *stb;
+  struct cleanup *old_chain;
+
+  stb = ui_out_stream_new (uiout);
+  old_chain = make_cleanup_ui_out_stream_delete (stb);
+
+  switch (b->type)
+    {
+    case bp_hardware_watchpoint:
+      annotate_watchpoint (b->number);
+      if (ui_out_is_mi_like_p (uiout))
+	ui_out_field_string
+	  (uiout, "reason",
+	   async_reason_lookup (EXEC_ASYNC_WATCHPOINT_TRIGGER));
+      break;
+
+    case bp_read_watchpoint:
+      if (ui_out_is_mi_like_p (uiout))
+	ui_out_field_string
+	  (uiout, "reason",
+	   async_reason_lookup (EXEC_ASYNC_READ_WATCHPOINT_TRIGGER));
+      break;
+
+    case bp_access_watchpoint:
+      if (old_val != NULL)
+	{
+	  annotate_watchpoint (b->number);
+	  if (ui_out_is_mi_like_p (uiout))
+	    ui_out_field_string
+	      (uiout, "reason",
+	       async_reason_lookup (EXEC_ASYNC_ACCESS_WATCHPOINT_TRIGGER));
+	}
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  mention (b);
+  ui_out_text (uiout, _("\nCheck the underlying instruction \
+at PC for address and value related to this watchpoint trigger.\n"));
+  ui_out_text (uiout, "\n");
+
+  do_cleanups (old_chain);
+
+  /* More than one watchpoint may have been triggered.  */
+  return PRINT_UNKNOWN;
+}
+
+/* Implement the "print_one_detail" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static void
+print_one_detail_masked_watchpoint (const struct breakpoint *b, struct ui_out *uiout)
+{
+  ui_out_text (uiout, "\tmask ");
+
+  /* I don't know whether it's possible to get here without a b->loc,
+     but we can handle the situation.  */
+  if (b->loc)
+    ui_out_field_core_addr (uiout, "mask", b->loc->gdbarch, b->hw_wp_mask);
+  else
+    ui_out_field_string (uiout, "mask", core_addr_to_string (b->hw_wp_mask));
+
+  ui_out_text (uiout, "\n");
+}
+
+/* Implement the "print_mention" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static void
+print_mention_masked_watchpoint (struct breakpoint *b)
+{
+  struct cleanup *ui_out_chain;
+
+  switch (b->type)
+    {
+    case bp_hardware_watchpoint:
+      ui_out_text (uiout, "Masked hardware watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt");
+      break;
+    case bp_read_watchpoint:
+      ui_out_text (uiout, "Masked hardware read watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-rwpt");
+      break;
+    case bp_access_watchpoint:
+      ui_out_text (uiout, "Masked hardware access (read/write) watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-awpt");
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  ui_out_field_int (uiout, "number", b->number);
+  ui_out_text (uiout, ": ");
+  ui_out_field_string (uiout, "exp", b->exp_string);
+  do_cleanups (ui_out_chain);
+}
+
+static void
+print_recreate_masked_watchpoint (struct breakpoint *b, struct ui_file *fp)
+{
+  char tmp[40];
+
+  switch (b->type)
+    {
+    case bp_hardware_watchpoint:
+      fprintf_unfiltered (fp, "watch");
+      break;
+    case bp_read_watchpoint:
+      fprintf_unfiltered (fp, "rwatch");
+      break;
+    case bp_access_watchpoint:
+      fprintf_unfiltered (fp, "awatch");
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  sprintf_vma (tmp, b->hw_wp_mask);
+  fprintf_unfiltered (fp, " %s mask 0x%s", b->exp_string, tmp);
+}
+
+/* The breakpoint_ops structure to be used in masked hardware watchpoints.  */
+
+static struct breakpoint_ops masked_watchpoint_breakpoint_ops =
+{
+  insert_masked_watchpoint,
+  remove_masked_watchpoint,
+  NULL, /* breakpoint_hit */
+  extra_resources_needed_masked_watchpoint,
+  works_in_software_mode_masked_watchpoint,
+  print_it_masked_watchpoint,
+  NULL, /* print_one */
+  print_one_detail_masked_watchpoint,
+  print_mention_masked_watchpoint,
+  print_recreate_masked_watchpoint
+};
+
+/* Tells whether the given watchpoint is a masked hardware watchpoint.  */
+
+static int
+is_masked_watchpoint (const struct breakpoint *b)
+{
+  return b->ops == &masked_watchpoint_breakpoint_ops;
+}
+
 /* accessflag:  hw_write:  watch write, 
                 hw_read:   watch read, 
 		hw_access: watch access (read or write) */
@@ -8062,8 +8472,8 @@ watch_command_1 (char *arg, int accessflag, int from_tty, int just_location)
   struct frame_info *frame;
   char *exp_start = NULL;
   char *exp_end = NULL;
-  char *tok, *id_tok_start, *end_tok;
-  int toklen;
+  char *tok, *end_tok;
+  int toklen = -1;
   char *cond_start = NULL;
   char *cond_end = NULL;
   int i, other_type_used, target_resources_ok = 0;
@@ -8071,66 +8481,98 @@ watch_command_1 (char *arg, int accessflag, int from_tty, int just_location)
   int mem_cnt = 0;
   int thread = -1;
   int pc = 0;
+  /* 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;
 
   /* Make sure that we actually have parameters to parse.  */
   if (arg != NULL && arg[0] != '\0')
     {
-      toklen = strlen (arg); /* Size of argument list.  */
+      char *value_start;
+
+      /* Look for "parameter value" pairs at the end
+	 of the arguments string.  */
+      for (tok = arg + strlen (arg) - 1; tok > arg; tok--)
+	{
+	  /* Skip whitespace at the end of the argument list.  */
+	  while (tok > arg && (*tok == ' ' || *tok == '\t'))
+	    tok--;
+
+	  /* Find the beginning of the last token.
+	     This is the value of the parameter.  */
+	  while (tok > arg && (*tok != ' ' && *tok != '\t'))
+	    tok--;
+	  value_start = tok + 1;
+
+	  /* Skip whitespace.  */
+	  while (tok > arg && (*tok == ' ' || *tok == '\t'))
+	    tok--;
+
+	  end_tok = tok;
+
+	  /* Find the beginning of the second to last token.
+	     This is the parameter itself.  */
+	  while (tok > arg && (*tok != ' ' && *tok != '\t'))
+	    tok--;
+	  tok++;
+	  toklen = end_tok - tok + 1;
+
+	  if (toklen == 6 && !strncmp (tok, "thread", 6))
+	    {
+	      /* 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;
 
-      /* Points tok to the end of the argument list.  */
-      tok = arg + toklen - 1;
+	      if (thread != -1)
+		error(_("You can specify only one thread."));
 
-      /* 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--;
+	      /* Extract the thread ID from the next token.  */
+	      thread = strtol (value_start, &endp, 0);
 
-      /* Points end_tok to the beginning of the last token.  */
-      id_tok_start = tok + 1;
+	      /* 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."), value_start);
 
-      /* 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--;
+	      /* Check if the thread actually exists.  */
+	      if (!valid_thread_id (thread))
+		error (_("Unknown thread %d."), thread);
+	    }
+	  else if (toklen == 4 && !strncmp (tok, "mask", 4))
+	    {
+	      /* We've found a "mask" token, which means the user wants to
+		 create a hardware watchpoint that is going to have the mask
+		 facility.  */
+	      struct value *mask_value, *mark;
 
-      end_tok = tok;
+	      /* Does the target support masked watchpoints?  */
+	      if (!target_can_use_special_hw_point (HW_POINT_MASKED_WATCH))
+		error (_("\
+This target does not support the usage of masks with hardware watchpoints."));
 
-      while (tok > arg && (*tok != ' ' && *tok != '\t'))
-        tok--;
+	      if (use_mask)
+		error(_("You can specify only one mask."));
 
-      /* Move the pointer forward to skip the whitespace and
-         calculate the length of the token.  */
-      tok++;
-      toklen = end_tok - tok;
+	      use_mask = 1;
 
-      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';
-        }
+	      mark = value_mark ();
+	      mask_value = parse_to_comma_and_eval (&value_start);
+	      hw_wp_mask = value_as_address (mask_value);
+	      value_free_to_mark (mark);
+	    }
+	  else
+	    /* We didn't recognize what we found.  We should stop here.  */
+	    break;
+
+	  /* Truncate the string and get rid of the "parameter value" pair before
+	     the arguments string is parsed by the parse_exp_1 function.  */
+	  *tok = '\0';
+	}
     }
 
   /* Parse the rest of the arguments.  */
@@ -8208,6 +8650,22 @@ watch_command_1 (char *arg, int accessflag, int from_tty, int just_location)
     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 (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, 
@@ -8219,10 +8677,22 @@ watch_command_1 (char *arg, int accessflag, int from_tty, int just_location)
 	error (_("Target can only support one kind of HW watchpoint at a time."));
     }
 
-  /* 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 && !mem_cnt)
+	error (_("Cannot use masks with the given expression."));
+      else if (use_mask && target_resources_ok <= 0)
+	error (_("\
+Cannot use masks without enough available hardware watchpoints (need %d)."),
+	       mem_cnt);
+      else
+	{
+	  /* Change the type of breakpoint to an ordinary watchpoint if a
+	     hardware watchpoint could not be set.  */
+	  bp_type = bp_watchpoint;
+	  use_ranged = 0;
+	}
+    }
 
   frame = block_innermost_frame (exp_valid_block);
 
@@ -8291,7 +8761,16 @@ watch_command_1 (char *arg, int accessflag, int from_tty, int just_location)
     b->exp_string = savestring (exp_start, exp_end - exp_start);
   b->val = val;
   b->val_valid = 1;
-  b->ops = &watchpoint_breakpoint_ops;
+
+  if (use_mask)
+    {
+      b->hw_wp_mask = hw_wp_mask;
+      b->ops = &masked_watchpoint_breakpoint_ops;
+    }
+  else if (use_ranged)
+    b->ops = &ranged_watchpoint_breakpoint_ops;
+  else
+    b->ops = &watchpoint_breakpoint_ops;
 
   if (cond_start)
     b->cond_string = savestring (cond_start, cond_end - cond_start);
@@ -8478,6 +8957,99 @@ awatch_command (char *arg, int from_tty)
 {
   watch_maybe_just_location (arg, hw_access, from_tty);
 }
+
+static void
+watch_range_command_1 (char *arg, enum bptype type, int from_tty)
+{
+  char *exp_string, *string_p;
+  struct gdbarch *gdbarch = get_current_arch ();
+  int wp_count, other_type_used, can_use_wp, mem_cnt, pc = 0;
+  CORE_ADDR start_addr;
+  ULONGEST length;
+  struct breakpoint *b;
+  struct expression *exp;
+  struct symtab_and_line sal;
+  struct value *val;
+  struct cleanup *cleanups;
+
+  /* Check if we need hardware watchpoints, and if we have enough
+     of them available.  */
+
+  if (!can_use_hw_watchpoints && type != bp_hardware_watchpoint)
+    error (_("\
+Need watchpoint hardware for read and access watchpoints, but cannot use it\n\
+(see set can-use-hw-watchpoints)."));
+
+  mem_cnt = target_hw_point_extra_slot_count (HW_POINT_RANGED_WATCH) + 1;
+  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 || !can_use_hw_watchpoints)
+    {
+      if (type == bp_hardware_watchpoint)
+	/* Change the type of breakpoint to an ordinary watchpoint if a
+	   hardware watchpoint could not be set.  */
+	type = bp_watchpoint;
+      else
+	error (_("Not enough available hardware watchpoints (need %d)."),
+	       mem_cnt);
+    }
+
+  parse_addr_range (&arg, &start_addr, &length);
+
+  /* We need spaces around the brackets in the expression below so that
+     print_it_recreate_ranged_watchpoint can use scanf on it.  */
+  exp_string = string_p = xstrprintf ("{char[ %s ]} %s", pulongest (length),
+				      paddress (gdbarch, start_addr));
+  exp = parse_exp_1 (&string_p, 0, 0);
+  fetch_subexp_value (exp, &pc, &val, NULL, NULL);
+  if (val != NULL)
+    release_value (val);
+  cleanups = make_cleanup (xfree, exp_string);
+
+  init_sal (&sal);		/* initialize to zeroes */
+  sal.pspace = current_program_space;
+
+  /* Now set up the breakpoint.  */
+  b = set_raw_breakpoint (gdbarch, sal, type);
+  set_breakpoint_count (breakpoint_count + 1);
+  b->number = breakpoint_count;
+  b->thread = -1;
+  b->disposition = disp_donttouch;
+  b->exp = exp;
+  b->exp_string_reparse = exp_string;
+  b->exp_string = xstrprintf (_("range [%s, %s]"),
+			      paddress (gdbarch, start_addr),
+			      paddress (gdbarch, start_addr + length - 1));
+  b->ops = &ranged_watchpoint_breakpoint_ops;
+  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);
+}
+
 \f
 
 /* Helper routines for the until_command routine in infcmd.c.  Here
@@ -8715,7 +9287,8 @@ catch_exec_command_1 (char *arg, int from_tty,
 }
 
 static enum print_stop_action
-print_exception_catchpoint (struct breakpoint *b)
+print_it_exception_catchpoint (struct breakpoint *b,
+			       const struct value *old_val)
 {
   int bp_temp, bp_throw;
 
@@ -8804,8 +9377,11 @@ static struct breakpoint_ops gnu_v3_exception_catchpoint_ops = {
   NULL, /* insert */
   NULL, /* remove */
   NULL, /* breakpoint_hit */
-  print_exception_catchpoint,
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
+  print_it_exception_catchpoint,
   print_one_exception_catchpoint,
+  NULL, /* print_one_detail */
   print_mention_exception_catchpoint,
   print_recreate_exception_catchpoint
 };
@@ -12195,7 +12771,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 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 the inferior whenever it\n\
+writes to any address within the [start-address, end-address] 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 the inferior whenever it\n\
+accesses (reads from or writes to) any address within the\n\
+[start-address, end-address] 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 the inferior whenever it\n\
+reads from any address within the [start-address, end-address] range."));
+  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 1b66986..57dc74c 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -26,6 +26,7 @@
 
 struct value;
 struct block;
+struct ui_out;
 
 /* This is the maximum number of bytes a breakpoint instruction can take.
    Feel free to increase it.  It's just used in a few places to size
@@ -361,13 +362,37 @@ struct breakpoint_ops
      breakpoint was hit.  */
   int (*breakpoint_hit) (struct breakpoint *);
 
+  /* Tell how many additional hardware resources (debug registers) are needed
+     for this breakpoint.  We always count at least one resource.  If this
+     element is NULL, then no additional resources are needed.  */
+  int (*extra_resources_needed) (const struct breakpoint *);
+
+  /* Tell whether we can downgrade from a hardware watchpoint to a software
+     one.  If not, the user will not be able to enable the watchpoint when
+     there are not enough hardware resources available.  */
+  int (*works_in_software_mode) (const struct breakpoint *);
+
   /* The normal print routine for this breakpoint, called when we
      hit it.  */
-  enum print_stop_action (*print_it) (struct breakpoint *);
+  enum print_stop_action (*print_it) (struct breakpoint *,
+				      const struct value *old_val);
 
   /* Display information about this breakpoint, for "info breakpoints".  */
   void (*print_one) (struct breakpoint *, struct bp_location **);
 
+  /* Display extra information about this breakpoint, below the normal
+     breakpoint description in "info breakpoints".  In the example below,
+     the line with "memory range: [0x10094354, 0x100943a2]" was printed
+     by print_one_detail_ranged_watchpoint.
+
+     (gdb) info breakpoints
+     Num     Type           Disp Enb Address    What
+     2       hw watchpoint  keep y              b
+             memory range: [0x10094354, 0x100943a2]
+
+     */
+  void (*print_one_detail) (const struct breakpoint *, struct ui_out *);
+
   /* Display information about this breakpoint after setting it (roughly
      speaking; this is called from "mention").  */
   void (*print_mention) (struct breakpoint *);
@@ -400,6 +425,12 @@ DEF_VEC_P(bp_location_p);
    detail to the breakpoints module.  */
 struct counted_command_line;
 
+/* Special types of hardware breakpoints/watchpoints.  */
+enum hw_point_flag {
+	HW_POINT_RANGED_WATCH, /* Hardware ranged watchpoint.  */
+	HW_POINT_MASKED_WATCH  /* Hardware masked watchpoint.  */
+};
+
 /* Note that the ->silent field is not currently used by any commands
    (though the code is in there if it was to be, and set_raw_breakpoint
    does set it to 0).  I implemented it because I thought it would be
@@ -559,6 +590,9 @@ struct breakpoint
        breakpoints, we will use this index to try to find the same
        marker again.  */
     int static_trace_marker_id_idx;
+
+    /* The mask address for a hardware watchpoint.  */
+    CORE_ADDR hw_wp_mask;
   };
 
 typedef struct breakpoint *breakpoint_p;
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 9446932..ffe45fb 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -3711,7 +3711,7 @@ watchpoints, which do not slow down the running of your program.
 
 @table @code
 @kindex watch
-@item watch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]}
+@item watch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} @r{[}mask @var{maskvalue}@r{]}
 Set a watchpoint for an expression.  @value{GDBN} will break when the
 expression @var{expr} is written into by the program and its value
 changes.  The simplest (and the most popular) use of this command is
@@ -3722,12 +3722,17 @@ to watch the value of a single variable:
 @end smallexample
 
 If the command includes a @code{@r{[}thread @var{threadnum}@r{]}}
-clause, @value{GDBN} breaks only when the thread identified by
+argument, @value{GDBN} breaks only when the thread identified by
 @var{threadnum} changes the value of @var{expr}.  If any other threads
 change the value of @var{expr}, @value{GDBN} will not break.  Note
 that watchpoints restricted to a single thread in this way only work
 with Hardware Watchpoints.
 
+The @code{@r{[}mask @var{maskvalue}@r{]}} argument allows creation
+of masked watchpoints, if the current architecture supports this
+feature.  (Currently, this is only available on PowerPC Embedded
+architecture, see @ref{PowerPC Embedded}.)
+
 Ordinarily a watchpoint respects the scope of variables in @var{expr}
 (see below).  The @code{-location} argument tells @value{GDBN} to
 instead watch the memory referred to by @var{expr}.  In this case,
@@ -3738,12 +3743,12 @@ result does not have an address, then @value{GDBN} will print an
 error.
 
 @kindex rwatch
-@item rwatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]}
+@item rwatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} @r{[}mask @var{maskvalue}@r{]}
 Set a watchpoint that will break when the value of @var{expr} is read
 by the program.
 
 @kindex awatch
-@item awatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]}
+@item awatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} @r{[}mask @var{maskvalue}@r{]}
 Set a watchpoint that will break when @var{expr} is either read from
 or written into by the program.
 
@@ -18517,9 +18522,44 @@ The DVC register will be automatically used whenever @value{GDBN} detects
 such pattern in a condition expression.  This feature is available in native
 @value{GDBN} running on a Linux kernel version 2.6.34 or newer.
 
+PowerPC embedded processors support masked watchpoints and ranged watchpoints.
+
+A @dfn{masked watchpoint} specifies a mask in addition to an address
+to watch.  The mask specifies that some bits of an address (the bits
+which are reset in the mask) should be ignored when matching the
+address accessed by the inferior against the watchpoint address.
+Thus, a masked watchpoint watches many addresses
+simultaneously---those addresses whose unmasked bits are identical
+to the unmasked bits in the watchpoint address.
+
+To set a masked watchpoint in @value{GDBN}, use the @code{mask} argument in
+the @code{watch} command (@pxref{Set Watchpoints}), as in:
+
+@smallexample
+(@value{GDBP}) watch *0xdeadbeef mask 0xffffff00
+@end smallexample
+
+A @dfn{ranged watchpoint} watches a contiguous range of addresses.
+To set a ranged watchpoint in @value{GDBN}, use the @code{watch-range} command.
+In addition, @value{GDBN} automatically creates a ranged watchpoint when asked
+to watch an array or struct of known size and there are enough hardware
+registers available.
+
 @value{GDBN} provides the following PowerPC-specific commands:
 
 @table @code
+@kindex watch-range
+@item watch-range @var{start-address}, +@var{length}
+@itemx watch-range @var{start-address}, @var{end-address}
+@item rwatch-range @var{start-address}, +@var{length}
+@itemx rwatch-range @var{start-address}, @var{end-address}
+@item awatch-range @var{start-address}, +@var{length}
+@itemx awatch-range @var{start-address}, @var{end-address}
+Set a hardware watchpoint for an address range.
+The watchpoint will stop execution of your program whenever the inferior
+writes, reads, or accesses (respectively for watch-range, awatch-range
+and rwatch-range) any address within the specified range.
+
 @kindex set powerpc
 @item set powerpc soft-float
 @itemx show powerpc soft-float
diff --git a/gdb/findcmd.c b/gdb/findcmd.c
index ac63a9e..34b0dfe 100644
--- a/gdb/findcmd.c
+++ b/gdb/findcmd.c
@@ -45,6 +45,79 @@ 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.  Returns 1 on success, or 0 if an empty address range was given.  */
+
+int
+parse_addr_range (char **args, CORE_ADDR *start_addrp,
+		  ULONGEST *address_range_lenp)
+{
+  char *s = *args;
+  CORE_ADDR start_addr;
+  ULONGEST address_range_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)
+	{
+	  printf_filtered (_("Empty address range.\n"));
+	  return 0;
+	}
+      if (len < 0)
+	error (_("Invalid (negative) length of the address range."));
+      /* Watch for overflows.  */
+      if (len > CORE_ADDR_MAX
+	  || (start_addr + len - 1) < start_addr)
+	error (_("Address range too large."));
+      address_range_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 address range, end preceeds start."));
+      address_range_len = end_addr - start_addr + 1;
+      /* We don't support searching all of memory
+	 (i.e. start=0, end = 0xff..ff).
+	 Bail out to avoid overflows later on.  */
+      if (address_range_len == 0)
+	error (_("Overflow in address range computation, choose smaller range."));
+    }
+
+  if (*s == ',')
+    ++s;
+
+  *args = s;
+  *start_addrp = start_addr;
+  *address_range_lenp = address_range_len;
+
+  return 1;
+}
+
 /* Subroutine of find_command to simplify it.
    Parse the arguments of the "find" command.  */
 
@@ -114,53 +187,8 @@ 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;
+  if (!parse_addr_range (&s, &start_addr, &search_space_len))
+    return;
 
   /* Fetch the search string.  */
 
diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c
index 18ddee7..e520dcd 100644
--- a/gdb/ppc-linux-nat.c
+++ b/gdb/ppc-linux-nat.c
@@ -1478,6 +1478,28 @@ ppc_linux_can_use_hw_breakpoint (int type, int cnt, int ot)
 }
 
 static int
+ppc_linux_can_use_special_hw_point (enum hw_point_flag flag)
+{
+  uint64_t features;
+
+  if (!have_ptrace_booke_interface ())
+    return 0;
+
+  features = booke_debug_info.features;
+
+  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;
+      default:
+	internal_error (__FILE__, __LINE__,
+			_("Unknown hardware breakpoint/watchpoint type."));
+    }
+}
+
+static int
 ppc_linux_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
 {
   /* Handle sub-8-byte quantities.  */
@@ -1489,9 +1511,15 @@ ppc_linux_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
      to determine the hardcoded watchable region for watchpoints.  */
   if (have_ptrace_booke_interface ())
     {
-      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 (ppc_linux_can_use_special_hw_point (HW_POINT_RANGED_WATCH))
+	return 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
@@ -1685,6 +1713,110 @@ get_trigger_type (int rw)
   return t;
 }
 
+static int
+ppc_linux_insert_mask_watchpoint (CORE_ADDR addr, CORE_ADDR mask, int rw)
+{
+  ptid_t ptid;
+  struct lwp_info *lp;
+  struct ppc_hw_breakpoint p;
+
+  gdb_assert (have_ptrace_booke_interface ());
+
+  if ((mask & 0xC0000000) != 0xC0000000)
+    error (_("\
+The given mask covers kernel address space and cannot be used.\n\
+You have to delete the masked watchpoint to continue the debugging session."));
+
+  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) addr;
+  p.addr2           = (uint64_t) mask;
+  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, CORE_ADDR mask, int rw)
+{
+  ptid_t ptid;
+  struct lwp_info *lp;
+  struct ppc_hw_breakpoint p;
+
+  gdb_assert (have_ptrace_booke_interface ());
+
+  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) addr;
+  p.addr2           = (uint64_t) mask;
+  p.condition_value = 0;
+
+  ALL_LWPS (lp, ptid)
+    booke_remove_point (&p, TIDGET (ptid));
+
+  return 0;
+}
+
+static int
+ppc_linux_insert_ranged_watchpoint (CORE_ADDR addr, int len, int rw)
+{
+  ptid_t ptid;
+  struct lwp_info *lp;
+  struct ppc_hw_breakpoint p;
+
+  gdb_assert (have_ptrace_booke_interface ());
+
+  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.condition_value = 0;
+
+  /* The watchpoint will trigger if the address of the memory access is
+     within the defined range, as follows: p.addr <= address < p.addr2.
+
+     Note that the above sentence just documents how ptrace interprets
+     its arguments; the watchpoint is set to watch the range defined by
+     the user _inclusively_, as specified by the user interface.  */
+  p.addr            = (uint64_t) addr;
+  p.addr2           = (uint64_t) addr + len;
+
+  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)
+{
+  ptid_t ptid;
+  struct lwp_info *lp;
+  struct ppc_hw_breakpoint p;
+
+  gdb_assert (have_ptrace_booke_interface ());
+
+  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;
+}
+
 /* Check whether we have at least one free DVC register.  */
 static int
 can_use_watchpoint_cond_accel (void)
@@ -2136,6 +2268,14 @@ ppc_linux_watchpoint_addr_within_range (struct target_ops *target,
   return start <= addr + mask && start + length - 1 >= addr;
 }
 
+static int
+ppc_linux_hw_point_extra_slot_count (enum hw_point_flag flag)
+{
+  gdb_assert (flag == HW_POINT_MASKED_WATCH || flag == HW_POINT_RANGED_WATCH);
+
+  return 1;
+}
+
 static void
 ppc_linux_store_inferior_registers (struct target_ops *ops,
 				    struct regcache *regcache, int regno)
@@ -2347,12 +2487,18 @@ _initialize_ppc_linux_nat (void)
   t->to_insert_hw_breakpoint = ppc_linux_insert_hw_breakpoint;
   t->to_remove_hw_breakpoint = ppc_linux_remove_hw_breakpoint;
   t->to_region_ok_for_hw_watchpoint = ppc_linux_region_ok_for_hw_watchpoint;
+  t->to_can_use_special_hw_point = ppc_linux_can_use_special_hw_point;
   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_stopped_by_watchpoint = ppc_linux_stopped_by_watchpoint;
   t->to_stopped_data_address = ppc_linux_stopped_data_address;
   t->to_watchpoint_addr_within_range = ppc_linux_watchpoint_addr_within_range;
   t->to_can_accel_watchpoint_condition = ppc_linux_can_accel_watchpoint_condition;
+  t->to_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/target.c b/gdb/target.c
index dd976c9..a9058a3 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -601,11 +601,16 @@ update_current_target (void)
       INHERIT (to_files_info, t);
       INHERIT (to_insert_breakpoint, t);
       INHERIT (to_remove_breakpoint, t);
+      INHERIT (to_can_use_special_hw_point, t);
       INHERIT (to_can_use_hw_breakpoint, t);
       INHERIT (to_insert_hw_breakpoint, t);
       INHERIT (to_remove_hw_breakpoint, t);
       INHERIT (to_insert_watchpoint, t);
       INHERIT (to_remove_watchpoint, t);
+      INHERIT (to_insert_ranged_watchpoint, t);
+      INHERIT (to_remove_ranged_watchpoint, t);
+      INHERIT (to_insert_mask_watchpoint, t);
+      INHERIT (to_remove_mask_watchpoint, t);
       INHERIT (to_stopped_data_address, t);
       INHERIT (to_have_steppable_watchpoint, t);
       INHERIT (to_have_continuable_watchpoint, t);
@@ -613,6 +618,7 @@ update_current_target (void)
       INHERIT (to_watchpoint_addr_within_range, t);
       INHERIT (to_region_ok_for_hw_watchpoint, t);
       INHERIT (to_can_accel_watchpoint_condition, 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);
@@ -727,6 +733,9 @@ update_current_target (void)
   de_fault (to_can_use_hw_breakpoint,
 	    (int (*) (int, int, int))
 	    return_zero);
+  de_fault (to_can_use_special_hw_point,
+	    (int (*) (enum hw_point_flag))
+	    return_zero);
   de_fault (to_insert_hw_breakpoint,
 	    (int (*) (struct gdbarch *, struct bp_target_info *))
 	    return_minus_one);
@@ -739,6 +748,18 @@ update_current_target (void)
   de_fault (to_remove_watchpoint,
 	    (int (*) (CORE_ADDR, int, int, struct expression *))
 	    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, CORE_ADDR, int))
+            return_minus_one);
+  de_fault (to_remove_mask_watchpoint,
+            (int (*) (CORE_ADDR, CORE_ADDR, int))
+            return_minus_one);
   de_fault (to_stopped_by_watchpoint,
 	    (int (*) (void))
 	    return_zero);
@@ -752,6 +773,9 @@ update_current_target (void)
   de_fault (to_can_accel_watchpoint_condition,
             (int (*) (CORE_ADDR, int, int, struct expression *))
             return_zero);
+  de_fault (to_hw_point_extra_slot_count,
+            (int (*) (enum hw_point_flag))
+            return_zero);
   de_fault (to_terminal_init,
 	    (void (*) (void))
 	    target_ignore);
diff --git a/gdb/target.h b/gdb/target.h
index 7687d8f..54a6747 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -39,6 +39,8 @@ struct static_tracepoint_marker;
 
 struct expression;
 
+enum hw_point_flag;
+
 /* This include file defines the interface between the main part
    of the debugger, and the part which is target-specific, or
    specific to the communications interface between us and the
@@ -438,6 +440,7 @@ struct target_ops
     int (*to_insert_breakpoint) (struct gdbarch *, struct bp_target_info *);
     int (*to_remove_breakpoint) (struct gdbarch *, struct bp_target_info *);
     int (*to_can_use_hw_breakpoint) (int, int, int);
+    int (*to_can_use_special_hw_point) (enum hw_point_flag);
     int (*to_insert_hw_breakpoint) (struct gdbarch *, struct bp_target_info *);
     int (*to_remove_hw_breakpoint) (struct gdbarch *, struct bp_target_info *);
 
@@ -446,6 +449,10 @@ struct target_ops
     int (*to_remove_watchpoint) (CORE_ADDR, int, int, struct expression *);
     int (*to_insert_watchpoint) (CORE_ADDR, int, int, struct expression *);
 
+    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, CORE_ADDR, int);
+    int (*to_remove_mask_watchpoint) (CORE_ADDR, CORE_ADDR, int);
     int (*to_stopped_by_watchpoint) (void);
     int to_have_steppable_watchpoint;
     int to_have_continuable_watchpoint;
@@ -455,6 +462,7 @@ struct target_ops
     int (*to_region_ok_for_hw_watchpoint) (CORE_ADDR, int);
     int (*to_can_accel_watchpoint_condition) (CORE_ADDR, int, int,
 					      struct expression *);
+    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);
@@ -1314,6 +1322,11 @@ extern char *normal_pid_to_str (ptid_t ptid);
 #define target_region_ok_for_hw_watchpoint(addr, len) \
     (*current_target.to_region_ok_for_hw_watchpoint) (addr, len)
 
+/* Returns non-zero if the target supports the special type of hardware
+   breakpoint/watchpoint represented by FLAG.  */
+#define target_can_use_special_hw_point(flag) \
+  (*current_target.to_can_use_special_hw_point) (flag)
+
 
 /* Set/clear a hardware watchpoint starting at ADDR, for LEN bytes.
    TYPE is 0 for write, 1 for read, and 2 for read/write accesses.
@@ -1327,6 +1340,20 @@ extern char *normal_pid_to_str (ptid_t ptid);
 #define	target_remove_watchpoint(addr, len, type, cond) \
      (*current_target.to_remove_watchpoint) (addr, len, type, cond)
 
+/* Hardware ranged watchpoints.  */
+#define target_insert_ranged_watchpoint(addr, len, type) \
+  (*current_target.to_insert_ranged_watchpoint) (addr, len, type)
+
+#define target_remove_ranged_watchpoint(addr, len, type) \
+  (*current_target.to_remove_ranged_watchpoint) (addr, len, type)
+
+/* Hardware watchpoints with an associated address mask.  */
+#define target_insert_mask_watchpoint(addr, mask, type) \
+  (*current_target.to_insert_mask_watchpoint) (addr, mask, type)
+
+#define target_remove_mask_watchpoint(addr, mask, type) \
+  (*current_target.to_remove_mask_watchpoint) (addr, mask, type)
+
 #define target_insert_hw_breakpoint(gdbarch, bp_tgt) \
      (*current_target.to_insert_hw_breakpoint) (gdbarch, bp_tgt)
 
@@ -1355,6 +1382,9 @@ extern char *normal_pid_to_str (ptid_t ptid);
 #define target_can_accel_watchpoint_condition(addr, len, type, cond) \
   (*current_target.to_can_accel_watchpoint_condition) (addr, len, type, cond)
 
+#define target_hw_point_extra_slot_count(flag) \
+  (*current_target.to_hw_point_extra_slot_count) (flag)
+
 /* Target can execute in reverse?  */
 #define target_can_execute_reverse \
      (current_target.to_can_execute_reverse ? \
diff --git a/gdb/ui-out.c b/gdb/ui-out.c
index 4d3bf0c..d6bea30 100644
--- a/gdb/ui-out.c
+++ b/gdb/ui-out.c
@@ -487,6 +487,46 @@ ui_out_field_fmt_int (struct ui_out *uiout,
 }
 
 void
+ui_out_field_range_core_addr (struct ui_out *uiout,
+			      const char *fldname,
+			      struct gdbarch *gdbarch,
+			      CORE_ADDR address_start,
+			      CORE_ADDR length)
+{
+  char addstr[80];
+  int addr_bit = gdbarch_addr_bit (gdbarch);
+  CORE_ADDR address_end = address_start + length - 1;
+
+  if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT))
+  {
+    address_start &= ((CORE_ADDR) 1 << addr_bit) - 1;
+    address_end &= ((CORE_ADDR) 1 << addr_bit) - 1;
+  }
+
+  /* FIXME: cagney/2002-05-03: Need local_address_string() function
+     that returns the language localized string formatted to a width
+     based on gdbarch_addr_bit.  */
+  if (addr_bit <= 32)
+  {
+    strcpy (addstr, "[");
+    strcat (addstr, hex_string_custom (address_start, 8));
+    strcat (addstr, ", ");
+    strcat (addstr, hex_string_custom (address_end, 8));
+    strcat (addstr, "]");
+  }
+  else
+  {
+    strcpy (addstr, "[");
+    strcat (addstr, hex_string_custom (address_start, 16));
+    strcat (addstr, ", ");
+    strcat (addstr, hex_string_custom (address_end, 16));
+    strcat (addstr, "]");
+  }
+
+  ui_out_field_string (uiout, fldname, addstr);
+}
+
+void
 ui_out_field_core_addr (struct ui_out *uiout,
 			const char *fldname,
 			struct gdbarch *gdbarch,
diff --git a/gdb/ui-out.h b/gdb/ui-out.h
index f65f42b..594691e 100644
--- a/gdb/ui-out.h
+++ b/gdb/ui-out.h
@@ -113,6 +113,12 @@ extern void ui_out_field_fmt_int (struct ui_out *uiout, int width,
 				  enum ui_align align, const char *fldname, 
 		 		  int value);
 
+extern void ui_out_field_range_core_addr (struct ui_out *uiout,
+					  const char *fldname,
+                                          struct gdbarch *gdbarch,
+					  CORE_ADDR address_start,
+					  CORE_ADDR length);
+
 extern void ui_out_field_core_addr (struct ui_out *uiout, const char *fldname,
 				    struct gdbarch *gdbarch, CORE_ADDR address);
 
diff --git a/gdb/value.h b/gdb/value.h
index d7912a8..64ea334 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -559,6 +559,9 @@ extern CORE_ADDR parse_and_eval_address_1 (char **expptr);
 
 extern LONGEST parse_and_eval_long (char *exp);
 
+int 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);


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

* Re: [patch 2/2] Implement support for PowerPC BookE masked and ranged watchpoints
  2010-11-04 21:12             ` Thiago Jung Bauermann
@ 2010-11-16  4:01               ` Jan Kratochvil
  2010-11-18 17:26                 ` Joel Brobecker
  2010-11-19 19:55                 ` Thiago Jung Bauermann
  0 siblings, 2 replies; 19+ messages in thread
From: Jan Kratochvil @ 2010-11-16  4:01 UTC (permalink / raw)
  To: Thiago Jung Bauermann; +Cc: Eli Zaretskii, gdb-patches

#       awatch-range 0xbffff8e8,0xbffff8f8


[...]
#       awatch *0xbffff8e8 mask 0xffffff00

What is the difference of this masked range versus?

        awatch-range 0xbffff800, 0xbffff8ff

If there is no difference then the mask address feature is useful only for
masks which are not of the form (-1 << n).


On Thu, 04 Nov 2010 22:12:05 +0100, Thiago Jung Bauermann wrote:
> +watch-range START_ADDR,+LENGTH | START_ADDR, END_ADDR
> +rwatch-range START_ADDR,+LENGTH | START_ADDR, END_ADDR
> +awatch-range START_ADDR,+LENGTH | START_ADDR, END_ADDR
> +  Set a hardware watchpoint for an address range.
> +  The watchpoint will stop execution of your program whenever the inferior
> +  writes, reads, or accesses (respectively for watch-range, awatch-range
> +  and rwatch-range) any address within the specified range.

What is the problem with the syntax?

watch *array@elementcount
OR
watch *(char *)array@bytescount

People already must know the @ operator just for printing arrays.  And some
nifty user friendly is provided by FE (graphical front end) and not CLI.

I may be biased but I would not try to invent new commands unless necessary,
GDB has already enough of them no user knows them all.


> +		target_resources_ok =  target_can_use_hardware_watchpoint

two spaces.


> +static int
> +insert_ranged_watchpoint (struct bp_location *bpt)

Like going to send in the other mail, `bpt' is (mostly) used for
`struct breakpoint'.  For bp_location please use `bl', `bploc' or some other
bp_location-suggesting names used in GDB.


> +  c = add_com ("watch-range", class_breakpoint, watch_range_command, _("\
> +Set a 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 the inferior whenever it\n\
> +writes to any address within the [start-address, end-address] range."));

I would prefer some explicit "both inclusively" statement there.
One could expect `end-address' to be the exclusive one.


> +/* Special types of hardware breakpoints/watchpoints.  */
> +enum hw_point_flag {

Incorrect GNU formatting.

> +	HW_POINT_RANGED_WATCH, /* Hardware ranged watchpoint.  */
> +	HW_POINT_MASKED_WATCH  /* Hardware masked watchpoint.  */
> +};


> +  p.version         = PPC_DEBUG_CURRENT_VERSION;

These extraneous spaces do not conform to GNU formatting.

> +  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) addr;
> +  p.addr2           = (uint64_t) mask;

Probably excessive cast.


> --- a/gdb/target.c
> +++ b/gdb/target.c
> @@ -601,11 +601,16 @@ update_current_target (void)
>        INHERIT (to_files_info, t);
>        INHERIT (to_insert_breakpoint, t);
>        INHERIT (to_remove_breakpoint, t);
> +      INHERIT (to_can_use_special_hw_point, t);

There are now two target interface styles in use.  This inheriting one and the
runtime-inheriting one (see target_pid_to_str and others).  I was told the
target_pid_to_str style is now preferred and it makes sense to me.  Please
convert the new target vector methods to the new style.


> +  if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT))
> +  {

Wrong GNU formatting.

> +    address_start &= ((CORE_ADDR) 1 << addr_bit) - 1;
> +    address_end &= ((CORE_ADDR) 1 << addr_bit) - 1;
> +  }
> +
> +  /* FIXME: cagney/2002-05-03: Need local_address_string() function
> +     that returns the language localized string formatted to a width
> +     based on gdbarch_addr_bit.  */
> +  if (addr_bit <= 32)
> +  {

Wrong GNU formatting.

> +    strcpy (addstr, "[");
> +    strcat (addstr, hex_string_custom (address_start, 8));
> +    strcat (addstr, ", ");
> +    strcat (addstr, hex_string_custom (address_end, 8));
> +    strcat (addstr, "]");
> +  }
> +  else
> +  {

Wrong GNU formatting.

> --- a/gdb/ui-out.h
> +++ b/gdb/ui-out.h
> @@ -113,6 +113,12 @@ extern void ui_out_field_fmt_int (struct ui_out *uiout, int width,
>  				  enum ui_align align, const char *fldname, 
>  		 		  int value);
>  
> +extern void ui_out_field_range_core_addr (struct ui_out *uiout,
> +					  const char *fldname,
> +                                          struct gdbarch *gdbarch,

Spaces used instead of tabs.

> +					  CORE_ADDR address_start,
> +					  CORE_ADDR length);
> +


Thanks,
Jan

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

* Re: [patch 2/2] Implement support for PowerPC BookE masked and ranged watchpoints
  2010-11-16  4:01               ` Jan Kratochvil
@ 2010-11-18 17:26                 ` Joel Brobecker
  2010-11-19 19:55                 ` Thiago Jung Bauermann
  1 sibling, 0 replies; 19+ messages in thread
From: Joel Brobecker @ 2010-11-18 17:26 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: Thiago Jung Bauermann, Eli Zaretskii, gdb-patches

> [Jan's review]

FWIW: No additional comments :)

-- 
Joel

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

* Re: [patch 2/2] Implement support for PowerPC BookE masked and ranged watchpoints
  2010-11-16  4:01               ` Jan Kratochvil
  2010-11-18 17:26                 ` Joel Brobecker
@ 2010-11-19 19:55                 ` Thiago Jung Bauermann
  2010-11-19 23:45                   ` Joel Brobecker
  2010-11-20  5:00                   ` Joel Brobecker
  1 sibling, 2 replies; 19+ messages in thread
From: Thiago Jung Bauermann @ 2010-11-19 19:55 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: Eli Zaretskii, gdb-patches

Hi Jan,

Thanks for the review!

On Tue, 2010-11-16 at 05:01 +0100, Jan Kratochvil wrote:
> #       awatch-range 0xbffff8e8,0xbffff8f8
> 
> 
> [...]
> #       awatch *0xbffff8e8 mask 0xffffff00
> 
> What is the difference of this masked range versus?
> 
>         awatch-range 0xbffff800, 0xbffff8ff
> 
> If there is no difference then the mask address feature is useful only for
> masks which are not of the form (-1 << n).

That's correct. That doesn't make the mask feature less useful, IMHO.

> On Thu, 04 Nov 2010 22:12:05 +0100, Thiago Jung Bauermann wrote:
> > +watch-range START_ADDR,+LENGTH | START_ADDR, END_ADDR
> > +rwatch-range START_ADDR,+LENGTH | START_ADDR, END_ADDR
> > +awatch-range START_ADDR,+LENGTH | START_ADDR, END_ADDR
> > +  Set a hardware watchpoint for an address range.
> > +  The watchpoint will stop execution of your program whenever the inferior
> > +  writes, reads, or accesses (respectively for watch-range, awatch-range
> > +  and rwatch-range) any address within the specified range.
> 
> What is the problem with the syntax?
> 
> watch *array@elementcount
> OR
> watch *(char *)array@bytescount
> 
> People already must know the @ operator just for printing arrays.  And some
> nifty user friendly is provided by FE (graphical front end) and not CLI.
> 
> I may be biased but I would not try to invent new commands unless necessary,
> GDB has already enough of them no user knows them all.

Eli made the same remark a long while ago (I wouldn't expect anyone to
remember):

http://sourceware.org/ml/gdb-patches/2009-12/msg00424.html

Here's what I said at the time:

        I agree that it is convenient to support ranged watchpoints with
        an established GDB syntax. So I implemented that. If the user
        asks to watch an array (natural or artificial) or struct, and
        ranged watchpoints are available then it will use them
        automatically.
        
        I'm reluctant to remove the watch-range command though, because
        with the artificial array syntax it's not straightforward to say
        "watch len *bytes* starting at addr". Using:
        
        watch *addr@len
        
        is not correct, since it will watch len *integers* starting at
        addr. To do what he/she wants, the user will have to type:
        
        watch *((char *) addr)@len
        
        Compare with:
        
        watch-range addr, +len
        
        (or perhaps I'm missing a simpler way to use artificial arrays
        in the example above..)

Also, Daniel said:

        This unintuitive command should also work:
        
          watch {char[len]} addr
        
        It's not a very nice syntax though.

Joel said:

        FWIW, I actually prefer the seperate command over your
        suggestion.
        The use of the @8 seems logical, but '@' is little known and the
        new command seems more explicit about the actual range being
        watched.

and later (where "syntax you suggested" is the same that you are
suggesting):

        Just in case you are referring to my answer as in favor, I
        should
        say that I'm more like 50-50, or only slightly in favor. I am
        not
        against the syntax you suggested provided that it does not
        complicate
        the implementation too much.

So to be honest I'm the only one actually in favor of introducing
watch-range. :-)  So should I drop watch-range then?

> > +		target_resources_ok =  target_can_use_hardware_watchpoint
> 
> two spaces.
> 
> 
> > +static int
> > +insert_ranged_watchpoint (struct bp_location *bpt)
> 
> Like going to send in the other mail, `bpt' is (mostly) used for
> `struct breakpoint'.  For bp_location please use `bl', `bploc' or some other
> bp_location-suggesting names used in GDB.

IIUC you already posted a patch which takes care of this right? Thank
you very much!!

> > +  c = add_com ("watch-range", class_breakpoint, watch_range_command, _("\
> > +Set a 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 the inferior whenever it\n\
> > +writes to any address within the [start-address, end-address] range."));
> 
> I would prefer some explicit "both inclusively" statement there.
> One could expect `end-address' to be the exclusive one.

Changed to:

+The watchpoint will stop execution of the inferior whenever it\n\
+writes to any address within the [start-address, end-address] range\n\
+(including start-address and end-address)."));

I also made the same change in awatch-range and rwatch-range. What do
you think?

> > +/* Special types of hardware breakpoints/watchpoints.  */
> > +enum hw_point_flag {
> 
> Incorrect GNU formatting.
> 
> > +	HW_POINT_RANGED_WATCH, /* Hardware ranged watchpoint.  */
> > +	HW_POINT_MASKED_WATCH  /* Hardware masked watchpoint.  */
> > +};

Fixed.

> > +  p.version         = PPC_DEBUG_CURRENT_VERSION;
> 
> These extraneous spaces do not conform to GNU formatting.

Previous patches in this series also used this style and were accepted,
so there's currently code like that in ppc-linux-nat.c in CVS HEAD
(e.g., ppc_linux_{insert,remove}_hw_breakpoint,
ppc_linux_{insert,remove}_watchpoint). Should I keep this patch like
this for consistency, or change this patch and the existing instances?

> > +  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) addr;
> > +  p.addr2           = (uint64_t) mask;
> 
> Probably excessive cast.

Indeed, fixed.

> > --- a/gdb/target.c
> > +++ b/gdb/target.c
> > @@ -601,11 +601,16 @@ update_current_target (void)
> >        INHERIT (to_files_info, t);
> >        INHERIT (to_insert_breakpoint, t);
> >        INHERIT (to_remove_breakpoint, t);
> > +      INHERIT (to_can_use_special_hw_point, t);
> 
> There are now two target interface styles in use.  This inheriting one and the
> runtime-inheriting one (see target_pid_to_str and others).  I was told the
> target_pid_to_str style is now preferred and it makes sense to me.  Please
> convert the new target vector methods to the new style.

Interesting, I didn't know about that. Fixed.

> > +  if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT))
> > +  {
> 
> Wrong GNU formatting.

Fixed.

> > +    address_start &= ((CORE_ADDR) 1 << addr_bit) - 1;
> > +    address_end &= ((CORE_ADDR) 1 << addr_bit) - 1;
> > +  }
> > +
> > +  /* FIXME: cagney/2002-05-03: Need local_address_string() function
> > +     that returns the language localized string formatted to a width
> > +     based on gdbarch_addr_bit.  */
> > +  if (addr_bit <= 32)
> > +  {
> 
> Wrong GNU formatting.

Fixed.

> > +    strcpy (addstr, "[");
> > +    strcat (addstr, hex_string_custom (address_start, 8));
> > +    strcat (addstr, ", ");
> > +    strcat (addstr, hex_string_custom (address_end, 8));
> > +    strcat (addstr, "]");
> > +  }
> > +  else
> > +  {
> 
> Wrong GNU formatting.

Fixed.

> > --- a/gdb/ui-out.h
> > +++ b/gdb/ui-out.h
> > @@ -113,6 +113,12 @@ extern void ui_out_field_fmt_int (struct ui_out *uiout, int width,
> >  				  enum ui_align align, const char *fldname, 
> >  		 		  int value);
> >  
> > +extern void ui_out_field_range_core_addr (struct ui_out *uiout,
> > +					  const char *fldname,
> > +                                          struct gdbarch *gdbarch,
> 
> Spaces used instead of tabs.

Oops. Fixed.

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


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

	Implement support for PowerPC BookE masked and ranged watchpoints.

gdb/
	*NEWS: Mention masked and ranged watchpoint support.
	Create "New commands" and "Changed commands" sections and populate
	it based on other NEWS items.
	* breakpoint.c (update_watchpoint): Call breakpoint's
	breakpoint_ops.extra_resources_needed and
	breakpoint_ops.works_in_software_mode if available.
	(watchpoints_triggered): Handle the case of a hardware masked
	watchpoint trigger.
	(watchpoint_check): Handle the case of a hardware masked watchpoint
	trigger.
	(print_one_breakpoint_location): Call breakpoint's
	breakpoint_ops.print_one_detail if available.
	(hw_watchpoint_used_count): Call breakpoint's
	breakpoint_ops.extra_resources_needed if available.
	(insert_ranged_watchpoint, remove_ranged_watchpoint)
	(extra_resources_needed_ranged_watchpoint)
	(print_one_detail_ranged_watchpoint, print_mention_ranged_watchpoint)
	(print_recreate_ranged_watchpoint): New functions.
	(ranged_watchpoint_breakpoint_ops): New structure.
	(insert_masked_watchpoint, remove_masked_watchpoint)
	(extra_resources_needed_masked_watchpoint)
	(works_in_software_mode_masked_watchpoint, print_it_masked_watchpoint)
	(print_one_detail_masked_watchpoint, print_mention_masked_watchpoint)
	(print_recreate_masked_watchpoint, is_masked_watchpoint): New functions.
	(masked_watchpoint_breakpoint_ops): New structure.
	(watch_command_1): Check for the existence of the `mask' parameter.
	Check whether a ranged hardware watchpoint can be used. Set b->ops
	according to the type of hardware watchpoint being created.
	(watch_range_command_1, watch_range_command)
	(awatch_range_command, rwatch_range_command): New functions.
	(_initialize_breakpoint): Register watch-range, awatch-range and
	rwatch-range commands.
	* breakpoint.h (struct ui_out): New opaque declaration.
	(struct breakpoint_ops) <extra_resources_needed>,
	<works_in_software_mode>, <print_one_detail>: New methods.
	Initialize them to NULL in all existing breakpoint_ops instances.
	(struct breakpoint_ops) <print_it>: Add OLD_VAL parameter.  Update all
	implementations of the method.
	(enum hw_point_flag): New enumeration.
	(struct breakpoint) <hw_wp_mask>: New field.
	* findcmd.c (parse_addr_range): New function factored out of
	parse_find_args.
	(parse_find_args): Call `parse_addr_range'.
	* ppc-linux-nat.c (ppc_linux_can_use_special_hw_point): New function.
	(ppc_linux_region_ok_for_hw_watchpoint): Always handle regions when
	ranged watchpoints are available.
	(ppc_linux_insert_mask_watchpoint, ppc_linux_remove_mask_watchpoint)
	(ppc_linux_insert_ranged_watchpoint, ppc_linux_remove_ranged_watchpoint)
	(ppc_linux_hw_point_extra_slot_count): New functions.
	(_initialize_ppc_linux_nat): Initialize to_insert_mask_watchpoint,
	to_remove_mask_watchpoint, to_insert_ranged_watchpoint,
	to_remove_ranged_watchpoint, hw_point_extra_slot_count and
	to_can_use_special_hw_point.
	* target.c (update_current_target): Mention to_insert_mask_watchpoint,
	to_remove_mask_watchpoint, to_insert_ranged_watchpoint,
	to_remove_ranged_watchpoint, to_hw_point_extra_slot_count
	and to_can_use_special_hw_point.
	(target_insert_mask_watchpoint, target_remove_mask_watchpoint)
	(target_insert_ranged_watchpoint, target_remove_ranged_watchpoint)
	(target_hw_point_extra_slot_count,
	target_can_use_special_hw_point): New functions.
	* target.h (enum hw_point_flag): New opaque declaration.
	(struct target_ops) <to_insert_mask_watchpoint>,
	<to_remove_mask_watchpoint>, <to_insert_ranged_watchpoint>,
	<to_remove_ranged_watchpoint>, <to_hw_point_extra_slot_count>,
	<to_can_use_special_hw_point>: New callbacks.
	(target_insert_mask_watchpoint, target_remove_mask_watchpoint)
	(target_insert_ranged_watchpoint, target_remove_ranged_watchpoint)
	(target_hw_point_extra_slot_count,
	target_can_use_special_hw_point): Add prototypes.
	* ui-out.c (ui_out_field_range_core_addr): New function.
	* ui-out.h (ui_out_field_range_core_addr): Declare.
	* value.h (parse_addr_range): Declare.

gdb/doc/
	* gdb.texinfo (Set Watchpoints): Document mask parameter.
	(PowerPC Embedded): Document masked watchpoints and ranged watchpoints.


diff --git a/gdb/NEWS b/gdb/NEWS
index 38478c4..935bee0 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -85,6 +85,20 @@
   libthread_db library with the "set libthread-db-search-path"
   command.  See the user manual for more details on this command.
 
+* GDB now supports ranged watchpoints, which stop the inferior when it
+  accesses any address within a specified memory range.  See the
+  documentation on the watch-range command for more information.  The
+  watchpoint is hardware-accelerated on some targets (currently only when
+  locally debugging programs on PowerPC BookE processors running a Linux
+  kernel version 2.6.34 or later).
+
+* Also for native debugging on Linux running on PowerPC BookE, GDB supports
+  masked hardware watchpoints, which specifiy a mask in addition to an
+  address to watch.  The mask specifies that some bits of an address (the
+  bits which are reset in the mask) should be ignored when matching the
+  address accessed by the inferior against the watchpoint address.
+  See the "PowerPC Embedded" section in the user manual for more details.
+
 * New features in the GDB remote stub, GDBserver
 
   ** GDBserver is now supported on PowerPC LynxOS (versions 4.x and 5.x),
@@ -97,6 +111,37 @@
 
 * Guile support was removed.
 
+* New commands
+
+watch-range START_ADDR,+LENGTH | START_ADDR, END_ADDR
+rwatch-range START_ADDR,+LENGTH | START_ADDR, END_ADDR
+awatch-range START_ADDR,+LENGTH | START_ADDR, END_ADDR
+  Set a hardware watchpoint for an address range.
+  The watchpoint will stop execution of your program whenever the inferior
+  writes, reads, or accesses (respectively for watch-range, awatch-range
+  and rwatch-range) any address within the specified range.
+
+set directories PATH
+  It is like the "dir" command except that it replaces the
+  source path list instead of augmenting it.
+
+info pretty-printers
+enable pretty-printer
+disable pretty-printer
+
+* Changed commands
+
+watch EXPRESSION mask MASK_VALUE
+  The watch command now supports the mask argument which allows creation
+  of masked watchpoints, if the current architecture supports this feature.
+
+watch -location EXPRESSION
+watch -l EXPRESSION
+  The "watch" command now accepts an optional "-location" argument.
+  When used, this causes GDB to watch the memory referred to by the
+  expression.  Such a watchpoint is never deleted due to it going out
+  of scope.
+
 *** Changes in GDB 7.2
 
 * Shared library support for remote targets by default
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 76b20e7..2a36f48 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10743,7 +10743,7 @@ print_recreate_exception (enum exception_catchpoint_kind ex,
 /* Virtual table for "catch exception" breakpoints.  */
 
 static enum print_stop_action
-print_it_catch_exception (struct breakpoint *b)
+print_it_catch_exception (struct breakpoint *b, const struct value *old_val)
 {
   return print_it_exception (ex_catch_exception, b);
 }
@@ -10771,8 +10771,11 @@ static struct breakpoint_ops catch_exception_breakpoint_ops =
   NULL, /* insert */
   NULL, /* remove */
   NULL, /* breakpoint_hit */
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_exception,
   print_one_catch_exception,
+  NULL, /* print_one_detail */
   print_mention_catch_exception,
   print_recreate_catch_exception
 };
@@ -10780,7 +10783,8 @@ static struct breakpoint_ops catch_exception_breakpoint_ops =
 /* Virtual table for "catch exception unhandled" breakpoints.  */
 
 static enum print_stop_action
-print_it_catch_exception_unhandled (struct breakpoint *b)
+print_it_catch_exception_unhandled (struct breakpoint *b,
+				    const struct value *old_val)
 {
   return print_it_exception (ex_catch_exception_unhandled, b);
 }
@@ -10809,8 +10813,11 @@ static struct breakpoint_ops catch_exception_unhandled_breakpoint_ops = {
   NULL, /* insert */
   NULL, /* remove */
   NULL, /* breakpoint_hit */
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_exception_unhandled,
   print_one_catch_exception_unhandled,
+  NULL, /* print_one_detail */
   print_mention_catch_exception_unhandled,
   print_recreate_catch_exception_unhandled
 };
@@ -10818,7 +10825,7 @@ static struct breakpoint_ops catch_exception_unhandled_breakpoint_ops = {
 /* Virtual table for "catch assert" breakpoints.  */
 
 static enum print_stop_action
-print_it_catch_assert (struct breakpoint *b)
+print_it_catch_assert (struct breakpoint *b, const struct value *old_val)
 {
   return print_it_exception (ex_catch_assert, b);
 }
@@ -10845,8 +10852,11 @@ static struct breakpoint_ops catch_assert_breakpoint_ops = {
   NULL, /* insert */
   NULL, /* remove */
   NULL, /* breakpoint_hit */
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_assert,
   print_one_catch_assert,
+  NULL, /* print_one_detail */
   print_mention_catch_assert,
   print_recreate_catch_assert
 };
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 55a08c7..90f38f5 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -219,6 +219,8 @@ static void disable_trace_command (char *, int);
 
 static void trace_pass_command (char *, int);
 
+static int is_masked_watchpoint (const struct breakpoint *b);
+
 /* Assuming we're creating a static tracepoint, does S look like a
    static tracepoint marker spec ("-m MARKER_ID")?  */
 #define is_marker_spec(s)						\
@@ -1391,27 +1393,52 @@ update_watchpoint (struct breakpoint *b, int reparse)
 	if ((b->type == bp_watchpoint || b->type == bp_hardware_watchpoint)
 	    && reparse)
 	  {
-	    int i, mem_cnt, other_type_used;
-
-	    /* We need to determine how many resources are already used
-	       for all other hardware watchpoints to see if we still have
-	       enough resources to also fit this watchpoint in as well.
-	       To avoid the hw_watchpoint_used_count call below from counting
-	       this watchpoint, make sure that it is marked as a software
-	       watchpoint.  */
-	    b->type = bp_watchpoint;
-	    i = hw_watchpoint_used_count (bp_hardware_watchpoint,
-					  &other_type_used);
+	    int mem_cnt;
+
 	    mem_cnt = can_use_hardware_watchpoint (val_chain);
 
 	    if (!mem_cnt)
-	      b->type = bp_watchpoint;
+	      {
+		if (b->type == bp_hardware_watchpoint
+		    && b->ops && b->ops->works_in_software_mode
+		    && !b->ops->works_in_software_mode (b))
+		  error (_("This watchpoint cannot be used in software mode."));
+		else
+		  b->type = bp_watchpoint;
+	      }
 	    else
 	      {
-		int target_resources_ok = target_can_use_hardware_watchpoint
-		  (bp_hardware_watchpoint, i + mem_cnt, other_type_used);
+		int i, other_type_used, target_resources_ok;
+		enum bptype orig_type;
+
+		if (b->ops && b->ops->extra_resources_needed)
+		  mem_cnt += b->ops->extra_resources_needed (b);
+
+		/* We need to determine how many resources are already used
+		   for all other hardware watchpoints to see if we still have
+		   enough resources to also fit this watchpoint in as well.
+		   To avoid the hw_watchpoint_used_count call below from
+		   counting this watchpoint, make sure that it is marked as a
+		   software watchpoint.  */
+		orig_type = b->type;
+		b->type = bp_watchpoint;
+		i = hw_watchpoint_used_count (bp_hardware_watchpoint,
+					      &other_type_used);
+
+		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;
+		  {
+		    if (orig_type == bp_hardware_watchpoint
+			&& b->ops && b->ops->works_in_software_mode
+			&& !b->ops->works_in_software_mode (b))
+		      {
+			b->type = bp_hardware_watchpoint;
+			error (_("This watchpoint cannot be used in software mode."));
+		      }
+		    else
+		      b->type = bp_watchpoint;
+		  }
 		else
 		  b->type = bp_hardware_watchpoint;
 	      }
@@ -3386,7 +3413,7 @@ print_bp_stop_message (bpstat bs)
 	   print_it_typical.  */
 	/* FIXME: how breakpoint can ever be NULL here?  */
 	if (b != NULL && b->ops != NULL && b->ops->print_it != NULL)
-	  return b->ops->print_it (b);
+	  return b->ops->print_it (b, bs->old_val);
 	else
 	  return print_it_typical (bs);
       }
@@ -3522,15 +3549,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 (is_masked_watchpoint (loc->owner))
+	      {
+		newaddr = addr & loc->owner->hw_wp_mask;
+		start = loc->address & loc->owner->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;
@@ -3644,6 +3686,11 @@ watchpoint_check (void *p)
 	  b->val_valid = 1;
 	  return WP_VALUE_CHANGED;
 	}
+      else if (is_masked_watchpoint (b))
+	/* 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.  */
@@ -4714,9 +4761,12 @@ print_one_breakpoint_location (struct breakpoint *b,
 	  ui_out_field_int (uiout, "task", b->task);
 	}
     }
-  
+
   ui_out_text (uiout, "\n");
-  
+
+  if (!part_of_multiple && b->ops && b->ops->print_one_detail)
+    b->ops->print_one_detail (b, uiout);
+
   if (!part_of_multiple && b->static_trace_marker_id)
     {
       gdb_assert (b->type == bp_static_tracepoint);
@@ -5890,7 +5940,7 @@ breakpoint_hit_catch_fork (struct breakpoint *b)
 /* Implement the "print_it" breakpoint_ops method for fork catchpoints.  */
 
 static enum print_stop_action
-print_it_catch_fork (struct breakpoint *b)
+print_it_catch_fork (struct breakpoint *b, const struct value *old_val)
 {
   annotate_catchpoint (b->number);
   printf_filtered (_("\nCatchpoint %d (forked process %d), "),
@@ -5948,8 +5998,11 @@ static struct breakpoint_ops catch_fork_breakpoint_ops =
   insert_catch_fork,
   remove_catch_fork,
   breakpoint_hit_catch_fork,
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_fork,
   print_one_catch_fork,
+  NULL, /* print_one_detail */
   print_mention_catch_fork,
   print_recreate_catch_fork
 };
@@ -5982,7 +6035,7 @@ breakpoint_hit_catch_vfork (struct breakpoint *b)
 /* Implement the "print_it" breakpoint_ops method for vfork catchpoints.  */
 
 static enum print_stop_action
-print_it_catch_vfork (struct breakpoint *b)
+print_it_catch_vfork (struct breakpoint *b, const struct value *old_val)
 {
   annotate_catchpoint (b->number);
   printf_filtered (_("\nCatchpoint %d (vforked process %d), "),
@@ -6039,8 +6092,11 @@ static struct breakpoint_ops catch_vfork_breakpoint_ops =
   insert_catch_vfork,
   remove_catch_vfork,
   breakpoint_hit_catch_vfork,
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_vfork,
   print_one_catch_vfork,
+  NULL, /* print_one_detail */
   print_mention_catch_vfork,
   print_recreate_catch_vfork
 };
@@ -6160,7 +6216,7 @@ breakpoint_hit_catch_syscall (struct breakpoint *b)
    catchpoints.  */
 
 static enum print_stop_action
-print_it_catch_syscall (struct breakpoint *b)
+print_it_catch_syscall (struct breakpoint *b, const struct value *old_val)
 {
   /* These are needed because we want to know in which state a
      syscall is.  It can be in the TARGET_WAITKIND_SYSCALL_ENTRY
@@ -6320,8 +6376,11 @@ static struct breakpoint_ops catch_syscall_breakpoint_ops =
   insert_catch_syscall,
   remove_catch_syscall,
   breakpoint_hit_catch_syscall,
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_syscall,
   print_one_catch_syscall,
+  NULL, /* print_one_detail */
   print_mention_catch_syscall,
   print_recreate_catch_syscall
 };
@@ -6423,7 +6482,7 @@ breakpoint_hit_catch_exec (struct breakpoint *b)
 }
 
 static enum print_stop_action
-print_it_catch_exec (struct breakpoint *b)
+print_it_catch_exec (struct breakpoint *b, const struct value *old_val)
 {
   annotate_catchpoint (b->number);
   printf_filtered (_("\nCatchpoint %d (exec'd %s), "), b->number,
@@ -6473,8 +6532,11 @@ static struct breakpoint_ops catch_exec_breakpoint_ops =
   insert_catch_exec,
   remove_catch_exec,
   breakpoint_hit_catch_exec,
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_exec,
   print_one_catch_exec,
+  NULL, /* print_one_detail */
   print_mention_catch_exec,
   print_recreate_catch_exec
 };
@@ -6522,7 +6584,14 @@ hw_watchpoint_used_count (enum bptype type, int *other_type_used)
     if (breakpoint_enabled (b))
       {
 	if (b->type == type)
-	  i++;
+	  {
+	    i++;
+
+	    /* Special types of hardware watchpoints can use more than
+	       one register.  */
+	    if (b->ops && b->ops->extra_resources_needed)
+	      i += b->ops->extra_resources_needed (b);
+	  }
 	else if (is_hardware_watchpoint (b))
 	  *other_type_used = 1;
       }
@@ -8080,12 +8149,353 @@ static struct breakpoint_ops watchpoint_breakpoint_ops =
   insert_watchpoint,
   remove_watchpoint,
   NULL, /* breakpoint_hit */
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
   NULL, /* print_it */
   NULL, /* print_one */
+  NULL, /* print_one_detail */
   NULL, /* print_mention */
   NULL  /* print_recreate */
 };
 
+/* Implement the "insert" breakpoint_ops method for
+   ranged hardware watchpoints.  */
+
+static int
+insert_ranged_watchpoint (struct bp_location *bpt)
+{
+  return target_insert_ranged_watchpoint (bpt->address,
+					  bpt->length,
+					  bpt->watchpoint_type);
+}
+
+/* Implement the "remove" breakpoint_ops method for
+   ranged hardware watchpoints.  */
+
+static int
+remove_ranged_watchpoint (struct bp_location *bpt)
+{
+  return target_remove_ranged_watchpoint (bpt->address, bpt->length,
+					  bpt->watchpoint_type);
+}
+
+/* Implement the "extra_resources_needed" breakpoint_ops method for
+   ranged hardware watchpoints.  */
+
+static int
+extra_resources_needed_ranged_watchpoint (const struct breakpoint *b)
+{
+  return target_hw_point_extra_slot_count (HW_POINT_RANGED_WATCH);
+}
+
+/* Implement the "print_one_detail" breakpoint_ops method for
+   ranged hardware watchpoints.  */
+
+static void
+print_one_detail_ranged_watchpoint (const struct breakpoint *b, struct ui_out *uiout)
+{
+  /* If there's a separate expression for reparsing, then exp_string is already
+     a nice text set by watch_range_command_1 and was printed earlier.  */
+  if (b->exp_string_reparse)
+    return;
+
+  gdb_assert (b->loc);
+
+  ui_out_text (uiout, "\tmemory range: ");
+  ui_out_field_range_core_addr (uiout, "addr", b->loc->gdbarch,
+				b->loc->address, b->loc->length);
+  ui_out_text (uiout, "\n");
+}
+
+/* Implement the "print_mention" breakpoint_ops method for
+   ranged hardware watchpoints.  */
+
+static void
+print_mention_ranged_watchpoint (struct breakpoint *b)
+{
+  struct cleanup *ui_out_chain;
+
+  switch (b->type)
+    {
+    case bp_watchpoint:
+      ui_out_text (uiout, "Ranged watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt");
+      break;
+    case bp_hardware_watchpoint:
+      ui_out_text (uiout, "Ranged hardware watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt");
+      break;
+    case bp_read_watchpoint:
+      ui_out_text (uiout, "Ranged hardware read watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-rwpt");
+      break;
+    case bp_access_watchpoint:
+      ui_out_text (uiout, "Ranged hardware access (read/write) watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-awpt");
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  ui_out_field_int (uiout, "number", b->number);
+  ui_out_text (uiout, ": ");
+  ui_out_field_string (uiout, "exp", b->exp_string);
+  do_cleanups (ui_out_chain);
+}
+
+static void
+print_recreate_ranged_watchpoint (struct breakpoint *b, struct ui_file *fp)
+{
+  switch (b->type)
+    {
+    case bp_watchpoint:
+    case bp_hardware_watchpoint:
+      if (b->exp_string_reparse)
+	fprintf_unfiltered (fp, "watch-range");
+      else
+	fprintf_unfiltered (fp, "watch");
+      break;
+    case bp_read_watchpoint:
+      if (b->exp_string_reparse)
+	fprintf_unfiltered (fp, "rwatch-range");
+      else
+	fprintf_unfiltered (fp, "rwatch");
+      break;
+    case bp_access_watchpoint:
+      if (b->exp_string_reparse)
+	fprintf_unfiltered (fp, "awatch-range");
+      else
+	fprintf_unfiltered (fp, "awatch");
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  if (b->exp_string_reparse)
+    {
+      char start_addr[40], length[40];
+
+      /* watch_range_command_1 creates the following expression to represent
+	 internally a ranged watchpoint.  */
+      sscanf (b->exp_string_reparse, "{char[ %39s ]} %39s", length, start_addr);
+
+      fprintf_unfiltered (fp, " %s, +%s", start_addr, length);
+    }
+  else
+    fprintf_unfiltered (fp, " %s", b->exp_string);
+}
+
+/* The breakpoint_ops structure to be used in ranged hardware watchpoints.  */
+
+static struct breakpoint_ops ranged_watchpoint_breakpoint_ops =
+{
+  insert_ranged_watchpoint,
+  remove_ranged_watchpoint,
+  NULL, /* breakpoint_hit */
+  extra_resources_needed_ranged_watchpoint,
+  NULL, /* works_in_software_mode */
+  NULL, /* print_it */
+  NULL, /* print_one */
+  print_one_detail_ranged_watchpoint,
+  print_mention_ranged_watchpoint,
+  print_recreate_ranged_watchpoint
+};
+
+/* Implement the "insert" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static int
+insert_masked_watchpoint (struct bp_location *bpt)
+{
+  return target_insert_mask_watchpoint (bpt->address, bpt->owner->hw_wp_mask,
+					bpt->watchpoint_type);
+}
+
+/* Implement the "remove" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static int
+remove_masked_watchpoint (struct bp_location *bpt)
+{
+  return target_remove_mask_watchpoint (bpt->address, bpt->owner->hw_wp_mask,
+				        bpt->watchpoint_type);
+}
+
+/* Implement the "extra_resources_needed" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static int
+extra_resources_needed_masked_watchpoint (const struct breakpoint *b)
+{
+  return target_hw_point_extra_slot_count (HW_POINT_MASKED_WATCH);
+}
+
+/* Implement the "works_in_software_mode_masked_watchpoint" breakpoint_ops
+   method for masked hardware watchpoints.  */
+
+static int
+works_in_software_mode_masked_watchpoint (const struct breakpoint *b)
+{
+  return 0;
+}
+
+/* Implement the "print_it" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static enum print_stop_action
+print_it_masked_watchpoint (struct breakpoint *b, const struct value *old_val)
+{
+  struct ui_stream *stb;
+  struct cleanup *old_chain;
+
+  stb = ui_out_stream_new (uiout);
+  old_chain = make_cleanup_ui_out_stream_delete (stb);
+
+  switch (b->type)
+    {
+    case bp_hardware_watchpoint:
+      annotate_watchpoint (b->number);
+      if (ui_out_is_mi_like_p (uiout))
+	ui_out_field_string
+	  (uiout, "reason",
+	   async_reason_lookup (EXEC_ASYNC_WATCHPOINT_TRIGGER));
+      break;
+
+    case bp_read_watchpoint:
+      if (ui_out_is_mi_like_p (uiout))
+	ui_out_field_string
+	  (uiout, "reason",
+	   async_reason_lookup (EXEC_ASYNC_READ_WATCHPOINT_TRIGGER));
+      break;
+
+    case bp_access_watchpoint:
+      if (old_val != NULL)
+	{
+	  annotate_watchpoint (b->number);
+	  if (ui_out_is_mi_like_p (uiout))
+	    ui_out_field_string
+	      (uiout, "reason",
+	       async_reason_lookup (EXEC_ASYNC_ACCESS_WATCHPOINT_TRIGGER));
+	}
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  mention (b);
+  ui_out_text (uiout, _("\nCheck the underlying instruction \
+at PC for address and value related to this watchpoint trigger.\n"));
+  ui_out_text (uiout, "\n");
+
+  do_cleanups (old_chain);
+
+  /* More than one watchpoint may have been triggered.  */
+  return PRINT_UNKNOWN;
+}
+
+/* Implement the "print_one_detail" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static void
+print_one_detail_masked_watchpoint (const struct breakpoint *b, struct ui_out *uiout)
+{
+  ui_out_text (uiout, "\tmask ");
+
+  /* I don't know whether it's possible to get here without a b->loc,
+     but we can handle the situation.  */
+  if (b->loc)
+    ui_out_field_core_addr (uiout, "mask", b->loc->gdbarch, b->hw_wp_mask);
+  else
+    ui_out_field_string (uiout, "mask", core_addr_to_string (b->hw_wp_mask));
+
+  ui_out_text (uiout, "\n");
+}
+
+/* Implement the "print_mention" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static void
+print_mention_masked_watchpoint (struct breakpoint *b)
+{
+  struct cleanup *ui_out_chain;
+
+  switch (b->type)
+    {
+    case bp_hardware_watchpoint:
+      ui_out_text (uiout, "Masked hardware watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt");
+      break;
+    case bp_read_watchpoint:
+      ui_out_text (uiout, "Masked hardware read watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-rwpt");
+      break;
+    case bp_access_watchpoint:
+      ui_out_text (uiout, "Masked hardware access (read/write) watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-awpt");
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  ui_out_field_int (uiout, "number", b->number);
+  ui_out_text (uiout, ": ");
+  ui_out_field_string (uiout, "exp", b->exp_string);
+  do_cleanups (ui_out_chain);
+}
+
+static void
+print_recreate_masked_watchpoint (struct breakpoint *b, struct ui_file *fp)
+{
+  char tmp[40];
+
+  switch (b->type)
+    {
+    case bp_hardware_watchpoint:
+      fprintf_unfiltered (fp, "watch");
+      break;
+    case bp_read_watchpoint:
+      fprintf_unfiltered (fp, "rwatch");
+      break;
+    case bp_access_watchpoint:
+      fprintf_unfiltered (fp, "awatch");
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  sprintf_vma (tmp, b->hw_wp_mask);
+  fprintf_unfiltered (fp, " %s mask 0x%s", b->exp_string, tmp);
+}
+
+/* The breakpoint_ops structure to be used in masked hardware watchpoints.  */
+
+static struct breakpoint_ops masked_watchpoint_breakpoint_ops =
+{
+  insert_masked_watchpoint,
+  remove_masked_watchpoint,
+  NULL, /* breakpoint_hit */
+  extra_resources_needed_masked_watchpoint,
+  works_in_software_mode_masked_watchpoint,
+  print_it_masked_watchpoint,
+  NULL, /* print_one */
+  print_one_detail_masked_watchpoint,
+  print_mention_masked_watchpoint,
+  print_recreate_masked_watchpoint
+};
+
+/* Tells whether the given watchpoint is a masked hardware watchpoint.  */
+
+static int
+is_masked_watchpoint (const struct breakpoint *b)
+{
+  return b->ops == &masked_watchpoint_breakpoint_ops;
+}
+
 /* accessflag:  hw_write:  watch write, 
                 hw_read:   watch read, 
 		hw_access: watch access (read or write) */
@@ -8100,8 +8510,8 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
   struct frame_info *frame;
   char *exp_start = NULL;
   char *exp_end = NULL;
-  char *tok, *id_tok_start, *end_tok;
-  int toklen;
+  char *tok, *end_tok;
+  int toklen = -1;
   char *cond_start = NULL;
   char *cond_end = NULL;
   int i, other_type_used, target_resources_ok = 0;
@@ -8109,66 +8519,98 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
   int mem_cnt = 0;
   int thread = -1;
   int pc = 0;
+  /* 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;
 
   /* Make sure that we actually have parameters to parse.  */
   if (arg != NULL && arg[0] != '\0')
     {
-      toklen = strlen (arg); /* Size of argument list.  */
+      char *value_start;
 
-      /* Points tok to the end of the argument list.  */
-      tok = arg + toklen - 1;
+      /* Look for "parameter value" pairs at the end
+	 of the arguments string.  */
+      for (tok = arg + strlen (arg) - 1; tok > arg; tok--)
+	{
+	  /* Skip whitespace at the end of the argument list.  */
+	  while (tok > arg && (*tok == ' ' || *tok == '\t'))
+	    tok--;
+
+	  /* Find the beginning of the last token.
+	     This is the value of the parameter.  */
+	  while (tok > arg && (*tok != ' ' && *tok != '\t'))
+	    tok--;
+	  value_start = tok + 1;
+
+	  /* Skip whitespace.  */
+	  while (tok > arg && (*tok == ' ' || *tok == '\t'))
+	    tok--;
+
+	  end_tok = tok;
+
+	  /* Find the beginning of the second to last token.
+	     This is the parameter itself.  */
+	  while (tok > arg && (*tok != ' ' && *tok != '\t'))
+	    tok--;
+	  tok++;
+	  toklen = end_tok - tok + 1;
+
+	  if (toklen == 6 && !strncmp (tok, "thread", 6))
+	    {
+	      /* 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;
 
-      /* 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--;
+	      if (thread != -1)
+		error(_("You can specify only one thread."));
 
-      /* Points end_tok to the beginning of the last token.  */
-      id_tok_start = tok + 1;
+	      /* Extract the thread ID from the next token.  */
+	      thread = strtol (value_start, &endp, 0);
 
-      /* 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--;
+	      /* 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."), value_start);
 
-      end_tok = tok;
+	      /* Check if the thread actually exists.  */
+	      if (!valid_thread_id (thread))
+		error (_("Unknown thread %d."), thread);
+	    }
+	  else if (toklen == 4 && !strncmp (tok, "mask", 4))
+	    {
+	      /* We've found a "mask" token, which means the user wants to
+		 create a hardware watchpoint that is going to have the mask
+		 facility.  */
+	      struct value *mask_value, *mark;
 
-      while (tok > arg && (*tok != ' ' && *tok != '\t'))
-        tok--;
+	      /* Does the target support masked watchpoints?  */
+	      if (!target_can_use_special_hw_point (HW_POINT_MASKED_WATCH))
+		error (_("\
+This target does not support the usage of masks with hardware watchpoints."));
 
-      /* Move the pointer forward to skip the whitespace and
-         calculate the length of the token.  */
-      tok++;
-      toklen = end_tok - tok;
+	      if (use_mask)
+		error(_("You can specify only one mask."));
 
-      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';
-        }
+	      use_mask = 1;
+
+	      mark = value_mark ();
+	      mask_value = parse_to_comma_and_eval (&value_start);
+	      hw_wp_mask = value_as_address (mask_value);
+	      value_free_to_mark (mark);
+	    }
+	  else
+	    /* We didn't recognize what we found.  We should stop here.  */
+	    break;
+
+	  /* Truncate the string and get rid of the "parameter value" pair before
+	     the arguments string is parsed by the parse_exp_1 function.  */
+	  *tok = '\0';
+	}
     }
 
   /* Parse the rest of the arguments.  */
@@ -8246,6 +8688,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 (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, 
@@ -8257,10 +8715,22 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
 	error (_("Target can only support one kind of HW watchpoint at a time."));
     }
 
-  /* 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 && !mem_cnt)
+	error (_("Cannot use masks with the given expression."));
+      else if (use_mask && target_resources_ok <= 0)
+	error (_("\
+Cannot use masks without enough available hardware watchpoints (need %d)."),
+	       mem_cnt);
+      else
+	{
+	  /* Change the type of breakpoint to an ordinary watchpoint if a
+	     hardware watchpoint could not be set.  */
+	  bp_type = bp_watchpoint;
+	  use_ranged = 0;
+	}
+    }
 
   frame = block_innermost_frame (exp_valid_block);
 
@@ -8328,7 +8798,16 @@ 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;
-  b->ops = &watchpoint_breakpoint_ops;
+
+  if (use_mask)
+    {
+      b->hw_wp_mask = hw_wp_mask;
+      b->ops = &masked_watchpoint_breakpoint_ops;
+    }
+  else if (use_ranged)
+    b->ops = &ranged_watchpoint_breakpoint_ops;
+  else
+    b->ops = &watchpoint_breakpoint_ops;
 
   if (cond_start)
     b->cond_string = savestring (cond_start, cond_end - cond_start);
@@ -8519,6 +8998,99 @@ awatch_command (char *arg, int from_tty)
 {
   watch_maybe_just_location (arg, hw_access, from_tty);
 }
+
+static void
+watch_range_command_1 (char *arg, enum bptype type, int from_tty)
+{
+  char *exp_string, *string_p;
+  struct gdbarch *gdbarch = get_current_arch ();
+  int wp_count, other_type_used, can_use_wp, mem_cnt, pc = 0;
+  CORE_ADDR start_addr;
+  ULONGEST length;
+  struct breakpoint *b;
+  struct expression *exp;
+  struct symtab_and_line sal;
+  struct value *val;
+  struct cleanup *cleanups;
+
+  /* Check if we need hardware watchpoints, and if we have enough
+     of them available.  */
+
+  if (!can_use_hw_watchpoints && type != bp_hardware_watchpoint)
+    error (_("\
+Need watchpoint hardware for read and access watchpoints, but cannot use it\n\
+(see set can-use-hw-watchpoints)."));
+
+  mem_cnt = target_hw_point_extra_slot_count (HW_POINT_RANGED_WATCH) + 1;
+  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 || !can_use_hw_watchpoints)
+    {
+      if (type == bp_hardware_watchpoint)
+	/* Change the type of breakpoint to an ordinary watchpoint if a
+	   hardware watchpoint could not be set.  */
+	type = bp_watchpoint;
+      else
+	error (_("Not enough available hardware watchpoints (need %d)."),
+	       mem_cnt);
+    }
+
+  parse_addr_range (&arg, &start_addr, &length);
+
+  /* We need spaces around the brackets in the expression below so that
+     print_it_recreate_ranged_watchpoint can use scanf on it.  */
+  exp_string = string_p = xstrprintf ("{char[ %s ]} %s", pulongest (length),
+				      paddress (gdbarch, start_addr));
+  exp = parse_exp_1 (&string_p, 0, 0);
+  fetch_subexp_value (exp, &pc, &val, NULL, NULL);
+  if (val != NULL)
+    release_value (val);
+  cleanups = make_cleanup (xfree, exp_string);
+
+  init_sal (&sal);		/* initialize to zeroes */
+  sal.pspace = current_program_space;
+
+  /* Now set up the breakpoint.  */
+  b = set_raw_breakpoint (gdbarch, sal, type);
+  set_breakpoint_count (breakpoint_count + 1);
+  b->number = breakpoint_count;
+  b->thread = -1;
+  b->disposition = disp_donttouch;
+  b->exp = exp;
+  b->exp_string_reparse = exp_string;
+  b->exp_string = xstrprintf (_("range [%s, %s]"),
+			      paddress (gdbarch, start_addr),
+			      paddress (gdbarch, start_addr + length - 1));
+  b->ops = &ranged_watchpoint_breakpoint_ops;
+  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);
+}
+
 \f
 
 /* Helper routines for the until_command routine in infcmd.c.  Here
@@ -8756,7 +9328,8 @@ catch_exec_command_1 (char *arg, int from_tty,
 }
 
 static enum print_stop_action
-print_exception_catchpoint (struct breakpoint *b)
+print_it_exception_catchpoint (struct breakpoint *b,
+			       const struct value *old_val)
 {
   int bp_temp, bp_throw;
 
@@ -8845,8 +9418,11 @@ static struct breakpoint_ops gnu_v3_exception_catchpoint_ops = {
   NULL, /* insert */
   NULL, /* remove */
   NULL, /* breakpoint_hit */
-  print_exception_catchpoint,
+  NULL, /* extra_resources_needed */
+  NULL, /* works_in_software_mode */
+  print_it_exception_catchpoint,
   print_one_exception_catchpoint,
+  NULL, /* print_one_detail */
   print_mention_exception_catchpoint,
   print_recreate_exception_catchpoint
 };
@@ -12256,7 +12832,44 @@ 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 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 the inferior whenever it\n\
+writes to any address within the [start-address, end-address] range\n\
+(including start-address and end-address)."));
+  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 the inferior whenever it\n\
+accesses (reads from or writes to) any address within the\n\
+[start-address, end-address] range (including start-address\n\
+and end-address)."));
+  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 the inferior whenever it\n\
+reads from any address within the [start-address, end-address] range\n\
+(including start-address and end-address)."));
+  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 84f8a39..6d9fa07 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -31,6 +31,7 @@
 
 struct value;
 struct block;
+struct ui_out;
 
 /* This is the maximum number of bytes a breakpoint instruction can take.
    Feel free to increase it.  It's just used in a few places to size
@@ -366,13 +367,37 @@ struct breakpoint_ops
      breakpoint was hit.  */
   int (*breakpoint_hit) (struct breakpoint *);
 
+  /* Tell how many additional hardware resources (debug registers) are needed
+     for this breakpoint.  We always count at least one resource.  If this
+     element is NULL, then no additional resources are needed.  */
+  int (*extra_resources_needed) (const struct breakpoint *);
+
+  /* Tell whether we can downgrade from a hardware watchpoint to a software
+     one.  If not, the user will not be able to enable the watchpoint when
+     there are not enough hardware resources available.  */
+  int (*works_in_software_mode) (const struct breakpoint *);
+
   /* The normal print routine for this breakpoint, called when we
      hit it.  */
-  enum print_stop_action (*print_it) (struct breakpoint *);
+  enum print_stop_action (*print_it) (struct breakpoint *,
+				      const struct value *old_val);
 
   /* Display information about this breakpoint, for "info breakpoints".  */
   void (*print_one) (struct breakpoint *, struct bp_location **);
 
+  /* Display extra information about this breakpoint, below the normal
+     breakpoint description in "info breakpoints".  In the example below,
+     the line with "memory range: [0x10094354, 0x100943a2]" was printed
+     by print_one_detail_ranged_watchpoint.
+
+     (gdb) info breakpoints
+     Num     Type           Disp Enb Address    What
+     2       hw watchpoint  keep y              b
+             memory range: [0x10094354, 0x100943a2]
+
+     */
+  void (*print_one_detail) (const struct breakpoint *, struct ui_out *);
+
   /* Display information about this breakpoint after setting it (roughly
      speaking; this is called from "mention").  */
   void (*print_mention) (struct breakpoint *);
@@ -405,6 +430,13 @@ DEF_VEC_P(bp_location_p);
    detail to the breakpoints module.  */
 struct counted_command_line;
 
+/* Special types of hardware breakpoints/watchpoints.  */
+enum hw_point_flag
+  {
+    HW_POINT_RANGED_WATCH,	/* Hardware ranged watchpoint.  */
+    HW_POINT_MASKED_WATCH	/* Hardware masked watchpoint.  */
+  };
+
 /* Note that the ->silent field is not currently used by any commands
    (though the code is in there if it was to be, and set_raw_breakpoint
    does set it to 0).  I implemented it because I thought it would be
@@ -571,7 +603,10 @@ struct breakpoint
        can sometimes be NULL for enabled GDBs as not all breakpoint
        types are tracked by the Python scripting API.  */
     PyObject *py_bp_object;
-};
+
+    /* The mask address for a masked hardware watchpoint.  */
+    CORE_ADDR hw_wp_mask;
+  };
 
 typedef struct breakpoint *breakpoint_p;
 DEF_VEC_P(breakpoint_p);
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index ddc711b..824f4c8 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -3714,7 +3714,7 @@ watchpoints, which do not slow down the running of your program.
 
 @table @code
 @kindex watch
-@item watch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]}
+@item watch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} @r{[}mask @var{maskvalue}@r{]}
 Set a watchpoint for an expression.  @value{GDBN} will break when the
 expression @var{expr} is written into by the program and its value
 changes.  The simplest (and the most popular) use of this command is
@@ -3725,12 +3725,17 @@ to watch the value of a single variable:
 @end smallexample
 
 If the command includes a @code{@r{[}thread @var{threadnum}@r{]}}
-clause, @value{GDBN} breaks only when the thread identified by
+argument, @value{GDBN} breaks only when the thread identified by
 @var{threadnum} changes the value of @var{expr}.  If any other threads
 change the value of @var{expr}, @value{GDBN} will not break.  Note
 that watchpoints restricted to a single thread in this way only work
 with Hardware Watchpoints.
 
+The @code{@r{[}mask @var{maskvalue}@r{]}} argument allows creation
+of masked watchpoints, if the current architecture supports this
+feature.  (Currently, this is only available on PowerPC Embedded
+architecture, see @ref{PowerPC Embedded}.)
+
 Ordinarily a watchpoint respects the scope of variables in @var{expr}
 (see below).  The @code{-location} argument tells @value{GDBN} to
 instead watch the memory referred to by @var{expr}.  In this case,
@@ -3741,12 +3746,12 @@ result does not have an address, then @value{GDBN} will print an
 error.
 
 @kindex rwatch
-@item rwatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]}
+@item rwatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} @r{[}mask @var{maskvalue}@r{]}
 Set a watchpoint that will break when the value of @var{expr} is read
 by the program.
 
 @kindex awatch
-@item awatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]}
+@item awatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} @r{[}mask @var{maskvalue}@r{]}
 Set a watchpoint that will break when @var{expr} is either read from
 or written into by the program.
 
@@ -18697,9 +18702,44 @@ The DVC register will be automatically used whenever @value{GDBN} detects
 such pattern in a condition expression.  This feature is available in native
 @value{GDBN} running on a Linux kernel version 2.6.34 or newer.
 
+PowerPC embedded processors support masked watchpoints and ranged watchpoints.
+
+A @dfn{masked watchpoint} specifies a mask in addition to an address
+to watch.  The mask specifies that some bits of an address (the bits
+which are reset in the mask) should be ignored when matching the
+address accessed by the inferior against the watchpoint address.
+Thus, a masked watchpoint watches many addresses
+simultaneously---those addresses whose unmasked bits are identical
+to the unmasked bits in the watchpoint address.
+
+To set a masked watchpoint in @value{GDBN}, use the @code{mask} argument in
+the @code{watch} command (@pxref{Set Watchpoints}), as in:
+
+@smallexample
+(@value{GDBP}) watch *0xdeadbeef mask 0xffffff00
+@end smallexample
+
+A @dfn{ranged watchpoint} watches a contiguous range of addresses.
+To set a ranged watchpoint in @value{GDBN}, use the @code{watch-range} command.
+In addition, @value{GDBN} automatically creates a ranged watchpoint when asked
+to watch an array or struct of known size and there are enough hardware
+registers available.
+
 @value{GDBN} provides the following PowerPC-specific commands:
 
 @table @code
+@kindex watch-range
+@item watch-range @var{start-address}, +@var{length}
+@itemx watch-range @var{start-address}, @var{end-address}
+@item rwatch-range @var{start-address}, +@var{length}
+@itemx rwatch-range @var{start-address}, @var{end-address}
+@item awatch-range @var{start-address}, +@var{length}
+@itemx awatch-range @var{start-address}, @var{end-address}
+Set a hardware watchpoint for an address range.
+The watchpoint will stop execution of your program whenever the inferior
+writes, reads, or accesses (respectively for watch-range, awatch-range
+and rwatch-range) any address within the specified range.
+
 @kindex set powerpc
 @item set powerpc soft-float
 @itemx show powerpc soft-float
diff --git a/gdb/findcmd.c b/gdb/findcmd.c
index ac63a9e..34b0dfe 100644
--- a/gdb/findcmd.c
+++ b/gdb/findcmd.c
@@ -45,6 +45,79 @@ 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.  Returns 1 on success, or 0 if an empty address range was given.  */
+
+int
+parse_addr_range (char **args, CORE_ADDR *start_addrp,
+		  ULONGEST *address_range_lenp)
+{
+  char *s = *args;
+  CORE_ADDR start_addr;
+  ULONGEST address_range_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)
+	{
+	  printf_filtered (_("Empty address range.\n"));
+	  return 0;
+	}
+      if (len < 0)
+	error (_("Invalid (negative) length of the address range."));
+      /* Watch for overflows.  */
+      if (len > CORE_ADDR_MAX
+	  || (start_addr + len - 1) < start_addr)
+	error (_("Address range too large."));
+      address_range_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 address range, end preceeds start."));
+      address_range_len = end_addr - start_addr + 1;
+      /* We don't support searching all of memory
+	 (i.e. start=0, end = 0xff..ff).
+	 Bail out to avoid overflows later on.  */
+      if (address_range_len == 0)
+	error (_("Overflow in address range computation, choose smaller range."));
+    }
+
+  if (*s == ',')
+    ++s;
+
+  *args = s;
+  *start_addrp = start_addr;
+  *address_range_lenp = address_range_len;
+
+  return 1;
+}
+
 /* Subroutine of find_command to simplify it.
    Parse the arguments of the "find" command.  */
 
@@ -114,53 +187,8 @@ 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;
+  if (!parse_addr_range (&s, &start_addr, &search_space_len))
+    return;
 
   /* Fetch the search string.  */
 
diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c
index 18ddee7..de7cafa 100644
--- a/gdb/ppc-linux-nat.c
+++ b/gdb/ppc-linux-nat.c
@@ -1478,6 +1478,29 @@ ppc_linux_can_use_hw_breakpoint (int type, int cnt, int ot)
 }
 
 static int
+ppc_linux_can_use_special_hw_point (struct target_ops *ops,
+				    enum hw_point_flag flag)
+{
+  uint64_t features;
+
+  if (!have_ptrace_booke_interface ())
+    return 0;
+
+  features = booke_debug_info.features;
+
+  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;
+      default:
+	internal_error (__FILE__, __LINE__,
+			_("Unknown hardware breakpoint/watchpoint type."));
+    }
+}
+
+static int
 ppc_linux_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
 {
   /* Handle sub-8-byte quantities.  */
@@ -1489,9 +1512,16 @@ ppc_linux_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
      to determine the hardcoded watchable region for watchpoints.  */
   if (have_ptrace_booke_interface ())
     {
-      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 (ppc_linux_can_use_special_hw_point (&current_target,
+					      HW_POINT_RANGED_WATCH))
+	return 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
@@ -1685,6 +1715,114 @@ get_trigger_type (int rw)
   return t;
 }
 
+static int
+ppc_linux_insert_mask_watchpoint (struct target_ops *ops, CORE_ADDR addr,
+				  CORE_ADDR mask, int rw)
+{
+  ptid_t ptid;
+  struct lwp_info *lp;
+  struct ppc_hw_breakpoint p;
+
+  gdb_assert (have_ptrace_booke_interface ());
+
+  if ((mask & 0xC0000000) != 0xC0000000)
+    error (_("\
+The given mask covers kernel address space and cannot be used.\n\
+You have to delete the masked watchpoint to continue the debugging session."));
+
+  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            = addr;
+  p.addr2           = mask;
+  p.condition_value = 0;
+
+  ALL_LWPS (lp, ptid)
+    booke_insert_point (&p, TIDGET (ptid));
+
+  return 0;
+}
+
+static int
+ppc_linux_remove_mask_watchpoint (struct target_ops *ops, CORE_ADDR addr,
+				  CORE_ADDR mask, int rw)
+{
+  ptid_t ptid;
+  struct lwp_info *lp;
+  struct ppc_hw_breakpoint p;
+
+  gdb_assert (have_ptrace_booke_interface ());
+
+  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            = addr;
+  p.addr2           = mask;
+  p.condition_value = 0;
+
+  ALL_LWPS (lp, ptid)
+    booke_remove_point (&p, TIDGET (ptid));
+
+  return 0;
+}
+
+static int
+ppc_linux_insert_ranged_watchpoint (struct target_ops *ops, CORE_ADDR addr,
+				    int len, int rw)
+{
+  ptid_t ptid;
+  struct lwp_info *lp;
+  struct ppc_hw_breakpoint p;
+
+  gdb_assert (have_ptrace_booke_interface ());
+
+  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.condition_value = 0;
+
+  /* The watchpoint will trigger if the address of the memory access is
+     within the defined range, as follows: p.addr <= address < p.addr2.
+
+     Note that the above sentence just documents how ptrace interprets
+     its arguments; the watchpoint is set to watch the range defined by
+     the user _inclusively_, as specified by the user interface.  */
+  p.addr            = (uint64_t) addr;
+  p.addr2           = (uint64_t) addr + len;
+
+  ALL_LWPS (lp, ptid)
+    booke_insert_point (&p, TIDGET (ptid));
+
+  return 0;
+}
+
+static int
+ppc_linux_remove_ranged_watchpoint (struct target_ops *ops, CORE_ADDR addr,
+				    int len, int rw)
+{
+  ptid_t ptid;
+  struct lwp_info *lp;
+  struct ppc_hw_breakpoint p;
+
+  gdb_assert (have_ptrace_booke_interface ());
+
+  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;
+}
+
 /* Check whether we have at least one free DVC register.  */
 static int
 can_use_watchpoint_cond_accel (void)
@@ -2136,6 +2274,15 @@ ppc_linux_watchpoint_addr_within_range (struct target_ops *target,
   return start <= addr + mask && start + length - 1 >= addr;
 }
 
+static int
+ppc_linux_hw_point_extra_slot_count (struct target_ops *target,
+				     enum hw_point_flag flag)
+{
+  gdb_assert (flag == HW_POINT_MASKED_WATCH || flag == HW_POINT_RANGED_WATCH);
+
+  return 1;
+}
+
 static void
 ppc_linux_store_inferior_registers (struct target_ops *ops,
 				    struct regcache *regcache, int regno)
@@ -2347,12 +2494,18 @@ _initialize_ppc_linux_nat (void)
   t->to_insert_hw_breakpoint = ppc_linux_insert_hw_breakpoint;
   t->to_remove_hw_breakpoint = ppc_linux_remove_hw_breakpoint;
   t->to_region_ok_for_hw_watchpoint = ppc_linux_region_ok_for_hw_watchpoint;
+  t->to_can_use_special_hw_point = ppc_linux_can_use_special_hw_point;
   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_stopped_by_watchpoint = ppc_linux_stopped_by_watchpoint;
   t->to_stopped_data_address = ppc_linux_stopped_data_address;
   t->to_watchpoint_addr_within_range = ppc_linux_watchpoint_addr_within_range;
   t->to_can_accel_watchpoint_condition = ppc_linux_can_accel_watchpoint_condition;
+  t->to_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/target.c b/gdb/target.c
index dd976c9..47a0210 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -601,11 +601,16 @@ update_current_target (void)
       INHERIT (to_files_info, t);
       INHERIT (to_insert_breakpoint, t);
       INHERIT (to_remove_breakpoint, t);
+      /* Do not inherit to_can_use_special_hw_point.  */
       INHERIT (to_can_use_hw_breakpoint, t);
       INHERIT (to_insert_hw_breakpoint, t);
       INHERIT (to_remove_hw_breakpoint, t);
       INHERIT (to_insert_watchpoint, t);
       INHERIT (to_remove_watchpoint, t);
+      /* Do not inherit to_insert_ranged_watchpoint.  */
+      /* Do not inherit to_remove_ranged_watchpoint.  */
+      /* Do not inherit to_insert_mask_watchpoint.  */
+      /* Do not inherit to_remove_mask_watchpoint.  */
       INHERIT (to_stopped_data_address, t);
       INHERIT (to_have_steppable_watchpoint, t);
       INHERIT (to_have_continuable_watchpoint, t);
@@ -613,6 +618,7 @@ update_current_target (void)
       INHERIT (to_watchpoint_addr_within_range, t);
       INHERIT (to_region_ok_for_hw_watchpoint, t);
       INHERIT (to_can_accel_watchpoint_condition, t);
+      /* Do not inherit to_hw_point_extra_slot_count.  */
       INHERIT (to_terminal_init, t);
       INHERIT (to_terminal_inferior, t);
       INHERIT (to_terminal_ours_for_output, t);
@@ -3334,6 +3340,122 @@ target_verify_memory (const gdb_byte *data, CORE_ADDR memaddr, ULONGEST size)
   tcomplain ();
 }
 
+int
+target_can_use_special_hw_point (enum hw_point_flag flag)
+{
+  struct target_ops *t;
+
+  for (t = current_target.beneath; t != NULL; t = t->beneath)
+    if (t->to_can_use_special_hw_point != NULL)
+      return t->to_can_use_special_hw_point (t, flag);
+
+  return return_zero ();
+}
+
+int
+target_insert_ranged_watchpoint (CORE_ADDR addr, int len, int rw)
+{
+  struct target_ops *t;
+
+  for (t = current_target.beneath; t != NULL; t = t->beneath)
+    if (t->to_insert_ranged_watchpoint != NULL)
+      {
+	int ret;
+
+	ret = t->to_insert_ranged_watchpoint (t, addr, len, rw);
+
+	if (targetdebug)
+	  fprintf_unfiltered (gdb_stdlog, "\
+target_insert_ranged_watchpoint (%s, %d, %d) = %d\n",
+			      core_addr_to_string (addr), len, rw, ret);
+
+	return ret;
+      }
+
+  return return_minus_one ();
+}
+
+int
+target_remove_ranged_watchpoint (CORE_ADDR addr, int len, int rw)
+{
+  struct target_ops *t;
+
+  for (t = current_target.beneath; t != NULL; t = t->beneath)
+    if (t->to_remove_ranged_watchpoint != NULL)
+      {
+	int ret;
+
+	ret = t->to_remove_ranged_watchpoint (t, addr, len, rw);
+
+	if (targetdebug)
+	  fprintf_unfiltered (gdb_stdlog, "\
+target_remove_ranged_watchpoint (%s, %d, %d) = %d\n",
+			      core_addr_to_string (addr), len, rw, ret);
+
+	return ret;
+      }
+
+  return return_minus_one ();
+}
+
+int
+target_insert_mask_watchpoint (CORE_ADDR addr, CORE_ADDR mask, int rw)
+{
+  struct target_ops *t;
+
+  for (t = current_target.beneath; t != NULL; t = t->beneath)
+    if (t->to_insert_mask_watchpoint != NULL)
+      {
+	int ret;
+
+	ret = t->to_insert_mask_watchpoint (t, addr, mask, rw);
+
+	if (targetdebug)
+	  fprintf_unfiltered (gdb_stdlog, "\
+target_insert_mask_watchpoint (%s, %s, %d) = %d\n", core_addr_to_string (addr),
+			      core_addr_to_string (mask), rw, ret);
+
+	return ret;
+      }
+
+  return return_minus_one ();
+}
+
+int
+target_remove_mask_watchpoint (CORE_ADDR addr, CORE_ADDR mask, int rw)
+{
+  struct target_ops *t;
+
+  for (t = current_target.beneath; t != NULL; t = t->beneath)
+    if (t->to_remove_mask_watchpoint != NULL)
+      {
+	int ret;
+
+	ret = t->to_remove_mask_watchpoint (t, addr, mask, rw);
+
+	if (targetdebug)
+	  fprintf_unfiltered (gdb_stdlog, "\
+target_remove_mask_watchpoint (%s, %s, %d) = %d\n", core_addr_to_string (addr),
+			      core_addr_to_string (mask), rw, ret);
+
+	return ret;
+      }
+
+  return return_minus_one ();
+}
+
+int
+target_hw_point_extra_slot_count (enum hw_point_flag flag)
+{
+  struct target_ops *t;
+
+  for (t = current_target.beneath; t != NULL; t = t->beneath)
+    if (t->to_hw_point_extra_slot_count != NULL)
+      return t->to_hw_point_extra_slot_count (t, flag);
+
+  return return_zero ();
+}
+
 static void
 debug_to_prepare_to_store (struct regcache *regcache)
 {
diff --git a/gdb/target.h b/gdb/target.h
index bc70107..dd822a9 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -39,6 +39,8 @@ struct static_tracepoint_marker;
 
 struct expression;
 
+enum hw_point_flag;
+
 /* This include file defines the interface between the main part
    of the debugger, and the part which is target-specific, or
    specific to the communications interface between us and the
@@ -438,6 +440,8 @@ struct target_ops
     int (*to_insert_breakpoint) (struct gdbarch *, struct bp_target_info *);
     int (*to_remove_breakpoint) (struct gdbarch *, struct bp_target_info *);
     int (*to_can_use_hw_breakpoint) (int, int, int);
+    int (*to_can_use_special_hw_point) (struct target_ops *,
+					enum hw_point_flag);
     int (*to_insert_hw_breakpoint) (struct gdbarch *, struct bp_target_info *);
     int (*to_remove_hw_breakpoint) (struct gdbarch *, struct bp_target_info *);
 
@@ -446,6 +450,14 @@ struct target_ops
     int (*to_remove_watchpoint) (CORE_ADDR, int, int, struct expression *);
     int (*to_insert_watchpoint) (CORE_ADDR, int, int, struct expression *);
 
+    int (*to_insert_ranged_watchpoint) (struct target_ops *,
+					CORE_ADDR, int, int);
+    int (*to_remove_ranged_watchpoint) (struct target_ops *,
+					CORE_ADDR, int, int);
+    int (*to_insert_mask_watchpoint) (struct target_ops *,
+				      CORE_ADDR, CORE_ADDR, int);
+    int (*to_remove_mask_watchpoint) (struct target_ops *,
+				      CORE_ADDR, CORE_ADDR, int);
     int (*to_stopped_by_watchpoint) (void);
     int to_have_steppable_watchpoint;
     int to_have_continuable_watchpoint;
@@ -455,6 +467,8 @@ struct target_ops
     int (*to_region_ok_for_hw_watchpoint) (CORE_ADDR, int);
     int (*to_can_accel_watchpoint_condition) (CORE_ADDR, int, int,
 					      struct expression *);
+    int (*to_hw_point_extra_slot_count) (struct target_ops *,
+					 enum hw_point_flag);
     void (*to_terminal_init) (void);
     void (*to_terminal_inferior) (void);
     void (*to_terminal_ours_for_output) (void);
@@ -1316,6 +1330,10 @@ extern char *normal_pid_to_str (ptid_t ptid);
 #define target_region_ok_for_hw_watchpoint(addr, len) \
     (*current_target.to_region_ok_for_hw_watchpoint) (addr, len)
 
+/* Returns non-zero if the target supports the special type of hardware
+   breakpoint/watchpoint represented by FLAG.  */
+
+extern int target_can_use_special_hw_point (enum hw_point_flag);
 
 /* Set/clear a hardware watchpoint starting at ADDR, for LEN bytes.
    TYPE is 0 for write, 1 for read, and 2 for read/write accesses.
@@ -1329,6 +1347,16 @@ extern char *normal_pid_to_str (ptid_t ptid);
 #define	target_remove_watchpoint(addr, len, type, cond) \
      (*current_target.to_remove_watchpoint) (addr, len, type, cond)
 
+/* Hardware ranged watchpoints.  */
+
+extern int target_insert_ranged_watchpoint (CORE_ADDR, int, int);
+extern int target_remove_ranged_watchpoint (CORE_ADDR, int, int);
+
+/* Hardware watchpoints with an associated address mask.  */
+
+extern int target_insert_mask_watchpoint (CORE_ADDR, CORE_ADDR, int);
+extern int target_remove_mask_watchpoint (CORE_ADDR, CORE_ADDR, int);
+
 #define target_insert_hw_breakpoint(gdbarch, bp_tgt) \
      (*current_target.to_insert_hw_breakpoint) (gdbarch, bp_tgt)
 
@@ -1357,6 +1385,8 @@ extern char *normal_pid_to_str (ptid_t ptid);
 #define target_can_accel_watchpoint_condition(addr, len, type, cond) \
   (*current_target.to_can_accel_watchpoint_condition) (addr, len, type, cond)
 
+extern int target_hw_point_extra_slot_count (enum hw_point_flag);
+
 /* Target can execute in reverse?  */
 #define target_can_execute_reverse \
      (current_target.to_can_execute_reverse ? \
diff --git a/gdb/ui-out.c b/gdb/ui-out.c
index 4d3bf0c..cf4b929 100644
--- a/gdb/ui-out.c
+++ b/gdb/ui-out.c
@@ -487,6 +487,46 @@ ui_out_field_fmt_int (struct ui_out *uiout,
 }
 
 void
+ui_out_field_range_core_addr (struct ui_out *uiout,
+			      const char *fldname,
+			      struct gdbarch *gdbarch,
+			      CORE_ADDR address_start,
+			      CORE_ADDR length)
+{
+  char addstr[80];
+  int addr_bit = gdbarch_addr_bit (gdbarch);
+  CORE_ADDR address_end = address_start + length - 1;
+
+  if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT))
+    {
+      address_start &= ((CORE_ADDR) 1 << addr_bit) - 1;
+      address_end &= ((CORE_ADDR) 1 << addr_bit) - 1;
+    }
+
+  /* FIXME: cagney/2002-05-03: Need local_address_string() function
+     that returns the language localized string formatted to a width
+     based on gdbarch_addr_bit.  */
+  if (addr_bit <= 32)
+    {
+      strcpy (addstr, "[");
+      strcat (addstr, hex_string_custom (address_start, 8));
+      strcat (addstr, ", ");
+      strcat (addstr, hex_string_custom (address_end, 8));
+      strcat (addstr, "]");
+    }
+  else
+    {
+      strcpy (addstr, "[");
+      strcat (addstr, hex_string_custom (address_start, 16));
+      strcat (addstr, ", ");
+      strcat (addstr, hex_string_custom (address_end, 16));
+      strcat (addstr, "]");
+    }
+
+  ui_out_field_string (uiout, fldname, addstr);
+}
+
+void
 ui_out_field_core_addr (struct ui_out *uiout,
 			const char *fldname,
 			struct gdbarch *gdbarch,
diff --git a/gdb/ui-out.h b/gdb/ui-out.h
index f65f42b..49e21b6 100644
--- a/gdb/ui-out.h
+++ b/gdb/ui-out.h
@@ -113,6 +113,12 @@ extern void ui_out_field_fmt_int (struct ui_out *uiout, int width,
 				  enum ui_align align, const char *fldname, 
 		 		  int value);
 
+extern void ui_out_field_range_core_addr (struct ui_out *uiout,
+					  const char *fldname,
+					  struct gdbarch *gdbarch,
+					  CORE_ADDR address_start,
+					  CORE_ADDR length);
+
 extern void ui_out_field_core_addr (struct ui_out *uiout, const char *fldname,
 				    struct gdbarch *gdbarch, CORE_ADDR address);
 
diff --git a/gdb/value.h b/gdb/value.h
index ef2cb4f..cc3bf90 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -560,6 +560,9 @@ extern CORE_ADDR parse_and_eval_address_1 (char **expptr);
 
 extern LONGEST parse_and_eval_long (char *exp);
 
+int 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);


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

* Re: [patch 2/2] Implement support for PowerPC BookE masked and ranged watchpoints
  2010-11-19 19:55                 ` Thiago Jung Bauermann
@ 2010-11-19 23:45                   ` Joel Brobecker
  2010-11-22 17:04                     ` Thiago Jung Bauermann
  2010-11-20  5:00                   ` Joel Brobecker
  1 sibling, 1 reply; 19+ messages in thread
From: Joel Brobecker @ 2010-11-19 23:45 UTC (permalink / raw)
  To: Thiago Jung Bauermann; +Cc: Jan Kratochvil, Eli Zaretskii, gdb-patches

> So to be honest I'm the only one actually in favor of introducing
> watch-range. :-)  So should I drop watch-range then?

One thing that I was going to propose when I thought I was going to be
the only reviewer was to split the patch a little. The are several
different features being implemented by this patch.  If you want,
we can discuss this separately from the other features...

-- 
Joel

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

* Re: [patch 2/2] Implement support for PowerPC BookE masked and ranged watchpoints
  2010-11-19 19:55                 ` Thiago Jung Bauermann
  2010-11-19 23:45                   ` Joel Brobecker
@ 2010-11-20  5:00                   ` Joel Brobecker
  2010-11-23 22:05                     ` Thiago Jung Bauermann
  1 sibling, 1 reply; 19+ messages in thread
From: Joel Brobecker @ 2010-11-20  5:00 UTC (permalink / raw)
  To: Thiago Jung Bauermann; +Cc: Jan Kratochvil, Eli Zaretskii, gdb-patches

> Changed to:
> 
> +The watchpoint will stop execution of the inferior whenever it\n\
> +writes to any address within the [start-address, end-address] range\n\
> +(including start-address and end-address)."));

Can you move the "writes" to the line before? This is to prevent
breaking line between the subject and the verb, making it easier
for the user to read...

> Previous patches in this series also used this style and were accepted,
> so there's currently code like that in ppc-linux-nat.c in CVS HEAD
> (e.g., ppc_linux_{insert,remove}_hw_breakpoint,
> ppc_linux_{insert,remove}_watchpoint). Should I keep this patch like
> this for consistency, or change this patch and the existing instances?

You'll have to excuse us, because not all of us are aware of the entire
coding standard used in GDB.  It makes me want to revive the idea of
a Wiki page, because I need some kind of table/list to remind me of
all of them.  If it's against the CS, then I'd just fix the instances
there, and let anyone changing the code on the other instances worry
about that (or you can do that already as an (obvious) separate patch).

-- 
Joel

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

* Re: [patch 2/2] Implement support for PowerPC BookE masked and ranged watchpoints
  2010-11-19 23:45                   ` Joel Brobecker
@ 2010-11-22 17:04                     ` Thiago Jung Bauermann
  2010-11-22 17:38                       ` Joel Brobecker
  0 siblings, 1 reply; 19+ messages in thread
From: Thiago Jung Bauermann @ 2010-11-22 17:04 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: Jan Kratochvil, Eli Zaretskii, gdb-patches

On Fri, 2010-11-19 at 15:45 -0800, Joel Brobecker wrote:
> > So to be honest I'm the only one actually in favor of introducing
> > watch-range. :-)  So should I drop watch-range then?
> 
> One thing that I was going to propose when I thought I was going to be
> the only reviewer was to split the patch a little. The are several
> different features being implemented by this patch.  If you want,
> we can discuss this separately from the other features...

I will divide the patch in 3, one for ranged watchpoints, another for
masked watchpoints and one for the watch-range command. Was this
division you were thinking of?
-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center

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

* Re: [patch 2/2] Implement support for PowerPC BookE masked and ranged watchpoints
  2010-11-22 17:04                     ` Thiago Jung Bauermann
@ 2010-11-22 17:38                       ` Joel Brobecker
  2010-11-22 17:46                         ` Jan Kratochvil
  0 siblings, 1 reply; 19+ messages in thread
From: Joel Brobecker @ 2010-11-22 17:38 UTC (permalink / raw)
  To: Thiago Jung Bauermann; +Cc: Jan Kratochvil, Eli Zaretskii, gdb-patches

> I will divide the patch in 3, one for ranged watchpoints, another for
> masked watchpoints and one for the watch-range command. Was this
> division you were thinking of?

Yes - but I'd recommend doing it only if that helps either Jan or
yourself in the review process. Now that the whole patch got reviewed,
then perhaps it's no longer useful to do so?

-- 
Joel

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

* Re: [patch 2/2] Implement support for PowerPC BookE masked and ranged watchpoints
  2010-11-22 17:38                       ` Joel Brobecker
@ 2010-11-22 17:46                         ` Jan Kratochvil
  2010-11-22 18:37                           ` Joel Brobecker
  0 siblings, 1 reply; 19+ messages in thread
From: Jan Kratochvil @ 2010-11-22 17:46 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: Thiago Jung Bauermann, Eli Zaretskii, gdb-patches

On Mon, 22 Nov 2010 18:38:30 +0100, Joel Brobecker wrote:
> > I will divide the patch in 3, one for ranged watchpoints, another for
> > masked watchpoints and one for the watch-range command. Was this
> > division you were thinking of?
> 
> Yes - but I'd recommend doing it only if that helps either Jan or
> yourself in the review process. Now that the whole patch got reviewed,
> then perhaps it's no longer useful to do so?

There are already many GDB commands, I do not want to block the patch due to
some additional IMO redundant ones, if other maintainers are fine with it.


Regards,
Jan

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

* Re: [patch 2/2] Implement support for PowerPC BookE masked and ranged watchpoints
  2010-11-22 17:46                         ` Jan Kratochvil
@ 2010-11-22 18:37                           ` Joel Brobecker
  0 siblings, 0 replies; 19+ messages in thread
From: Joel Brobecker @ 2010-11-22 18:37 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: Thiago Jung Bauermann, Eli Zaretskii, gdb-patches

> There are already many GDB commands, I do not want to block the patch due to
> some additional IMO redundant ones, if other maintainers are fine with it.

I personally don't have a strong opinion. It sounds from the previous
discussion that it was sort of OK with the new command, even if there
were other ways to achieve the same result?

-- 
Joel

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

* Re: [patch 2/2] Implement support for PowerPC BookE masked and ranged watchpoints
  2010-11-20  5:00                   ` Joel Brobecker
@ 2010-11-23 22:05                     ` Thiago Jung Bauermann
  0 siblings, 0 replies; 19+ messages in thread
From: Thiago Jung Bauermann @ 2010-11-23 22:05 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: Jan Kratochvil, Eli Zaretskii, gdb-patches

On Fri, 2010-11-19 at 20:59 -0800, Joel Brobecker wrote:
> > Changed to:
> > 
> > +The watchpoint will stop execution of the inferior whenever it\n\
> > +writes to any address within the [start-address, end-address] range\n\
> > +(including start-address and end-address)."));
> 
> Can you move the "writes" to the line before? This is to prevent
> breaking line between the subject and the verb, making it easier
> for the user to read...

Ok. Fixed in the patch I just posted.

> > Previous patches in this series also used this style and were accepted,
> > so there's currently code like that in ppc-linux-nat.c in CVS HEAD
> > (e.g., ppc_linux_{insert,remove}_hw_breakpoint,
> > ppc_linux_{insert,remove}_watchpoint). Should I keep this patch like
> > this for consistency, or change this patch and the existing instances?
> 
> You'll have to excuse us, because not all of us are aware of the entire
> coding standard used in GDB.  It makes me want to revive the idea of
> a Wiki page, because I need some kind of table/list to remind me of
> all of them.  If it's against the CS, then I'd just fix the instances
> there, and let anyone changing the code on the other instances worry
> about that (or you can do that already as an (obvious) separate patch).

No problem. I fixed the whitespace in my patch. I'll commit a separate
obvious patch later then.
-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center

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

end of thread, other threads:[~2010-11-23 22:05 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-08-17 19:42 [patch 2/2] Implement support for PowerPC BookE masked and ranged watchpoints Thiago Jung Bauermann
2010-10-07 14:48 ` Thiago Jung Bauermann
2010-10-23  4:23 ` Thiago Jung Bauermann
2010-10-23  9:07   ` Eli Zaretskii
2010-10-30  1:59     ` Thiago Jung Bauermann
2010-10-30  7:13       ` Eli Zaretskii
2010-11-01 21:47         ` Thiago Jung Bauermann
2010-11-02  3:53           ` Eli Zaretskii
2010-11-04 21:12             ` Thiago Jung Bauermann
2010-11-16  4:01               ` Jan Kratochvil
2010-11-18 17:26                 ` Joel Brobecker
2010-11-19 19:55                 ` Thiago Jung Bauermann
2010-11-19 23:45                   ` Joel Brobecker
2010-11-22 17:04                     ` Thiago Jung Bauermann
2010-11-22 17:38                       ` Joel Brobecker
2010-11-22 17:46                         ` Jan Kratochvil
2010-11-22 18:37                           ` Joel Brobecker
2010-11-20  5:00                   ` Joel Brobecker
2010-11-23 22:05                     ` Thiago Jung Bauermann

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