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


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

Re: [patch 2/2] Implement support for PowerPC BookE masked and ranged watchpoints


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);
+}
+
 
 
 /* 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);



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